Toolbar menu not inflating - android

I am making a contexual action bar by modifying the toolbar on long click of recyclerView which contains edit and delete. It works okay if I select / deselect the views, however if I click on edit, the menu doesn't appear until I focus on one of the edit texts. When I edit any entry, it works again. the toolbar textView is being updated but menu is not inflating
//Activity Expense_list
class Expenses_list : AppCompatActivity(), View.OnLongClickListener{
lateinit var expenses_recycler : RecyclerView
var expense_list_items :MutableList<expense_input> = ArrayList()
var selection_list_items :MutableList<expense_input> = ArrayList()
var db = DataBaseHandler(this)
var categ:String = ""
var is_in_action_mode = false
var edit_mode = false
private var counter = 0
lateinit var toolbar: android.support.v7.widget.Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_expenses_list)
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
categ= intent.getStringExtra("cat")
textView.text = categ.capitalize()
loadData()
expenses_recycler = findViewById(R.id.expense_list_item)
expenses_recycler.layoutManager = LinearLayoutManager(this)
expenses_recycler.adapter =
Expense_Adapter(expense_list_items,this,this#Expenses_list)
}
fun addObject(i:Int) {
selection_list_items.add(expense_list_items[i])
counter=counter+1
changeMenu()
updateCounter(counter)
}
private fun updateCounter(counter:Int) {
if(counter==0)
{
textToolbar.text = "0 item selected"
}
else
{
textToolbar.text = "" + counter + "item selected"
}
}
private fun removeObject(adapterPosition: Int) {
selection_list_items.remove(expense_list_items[adapterPosition])
counter=counter-1
changeMenu()
updateCounter(counter)
}
fun loadData() {
expense_list_items.clear()
var data = db.readDataExpense(categ)
for (i in 0..(data.size - 1))
{
expense_list_items.add(data[i])
}
}
override fun onLongClick(p0: View?): Boolean {
toolbar.menu.clear()
textToolbar.visibility = View.VISIBLE
is_in_action_mode = true
expenses_recycler.adapter.notifyDataSetChanged()
return true
}
fun changeMenu() {
when (counter) {
0 -> {
Toast.makeText(this,"counter=0",Toast.LENGTH_SHORT).show()
toolbar.menu.clear()
}
1 -> {
Toast.makeText(this,"counter=1",Toast.LENGTH_SHORT).show()
toolbar.menu.clear()
toolbar.inflateMenu(R.menu.menu_toolbar_edit)
}
else -> {
toolbar.menu.clear()
toolbar.inflateMenu(R.menu.menu_toolbar)
}
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item?.itemId)
{
R.id.edit->{
edit_mode=true
expenses_recycler.adapter.notifyDataSetChanged()
}
R.id.delete->{
db.deleteExpense(selection_list_items)
loadData()
clearActionMode()
}
}
return super.onOptionsItemSelected(item)
}
private fun clearActionMode() {
is_in_action_mode=false
edit_mode=false
selection_list_items.clear()
toolbar.menu.clear()
textToolbar.visibility = View.GONE
textToolbar.text = "0 item selected"
expenses_recycler.adapter.notifyDataSetChanged()
}
override fun onBackPressed() {
if(is_in_action_mode==true)
{
clearActionMode()
}
else
super.onBackPressed()
}
}
//Adapter
class Expense_Adapter(items
:List<expense_input>,ctx:Context,el:Expenses_list) :
RecyclerView.Adapter<Expense_Adapter.ViewHolder>() {
var expl = el
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(context,expl,LayoutInflater.from(context).inflate(R.layout.expense_list,parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindTo(list[position])
}
var list = items
var context = ctx
override fun getItemCount(): Int {
return list.size
}
class ViewHolder(v:View) :RecyclerView.ViewHolder(v)
{
var mex :Expenses_list? = null
var context : Context?= null
var exp :expense_input ?= null
constructor(ctx: Context,ex: Expenses_list,v: View):this(v){
mex = ex
context = ctx
bl.setOnLongClickListener(mex)
cb?.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
mex!!.addObject(adapterPosition)
}
else {
mex!!.removeObject(adapterPosition)
}
}
}
fun bindTo(l: expense_input)
{
exp = l
name?.setText(l.item)
//name?.text = l.item
am.setText(l.amount.toString())
//am.text = l.amount.toString()
d.text = l.date
if(mex?.is_in_action_mode==false) {
cb.visibility = View.GONE
}
else {
cb.visibility = View.VISIBLE
cb.isChecked = false
}
if(mex?.edit_mode==false)
{
if(vs.displayedChild == 1)
{
Log.d("action","here")
im.setImageResource(R.drawable.ic_expnote)
vs.showPrevious()
}
}
if(mex!!.edit_mode)
{
Log.d("action","Edit")
vs.showNext()
cb.visibility = View.GONE
ename.setText(exp?.item)
eam.setText(exp?.amount.toString())
im.setImageResource(R.drawable.ic_list)
}
im.setOnClickListener {
val db = DataBaseHandler(context!!)
if(vs.displayedChild==1)
{
if(eam.text.toString().isNotEmpty() && ename.text.toString().isNotEmpty())
{
var ex = l
ex.amount = eam.text.toString().toFloat()
ex.item = ename.text.toString()
db.UpdateDataExpense(ex)
mex?.clearActionMode()
}
else
{
Toast.makeText(context,"Item is invalid",Toast.LENGTH_SHORT).show()
}
}
else
{
val detailIntent = Intent(context, Exp_note::class.java)
detailIntent.putExtra("Note",l.id)
context!!.startActivity(detailIntent)
}
}
}
val name = v.textItem
val am = v.textAmount
val d = v.textDate
val im = v.openNote
val cb = v.cb
val bl = v.biglinear
val vs = v.viewSwitcher
val ename = v.editItem
val eam = v.EditAmount
}
}

Instead of trying to inflate different menus in one Activity did you try to create one menu that contains all items and set them to invisible by default? You could then override onPrepareOptionsMenu, for example like below, to change what items are to be displayed based on your defined conditions:
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
invalidateOptionsMenu()
when {
// more than one item selected
mSelectedItems.isNotEmpty() && mSelectedItems.size > 1 -> {
menu.findItem(R.id.action_edit).isVisible = false
menu.findItem(R.id.action_delete).isVisible = true
}
// one item selected
mSelectedItems.isNotEmpty() -> {
menu.findItem(R.id.action_edit).isVisible = true
menu.findItem(R.id.action_delete).isVisible = true
}
// none selected
else -> {
menu.findItem(R.id.action_edit).isVisible = false
menu.findItem(R.id.action_delete).isVisible = false
}
}
return super.onPrepareOptionsMenu(menu)
}
obove code produces following result

Related

How to implement serch in recycler view for firestore data?

I want to implement search in my recyclerview. The data I am retrieving is from firebase (firestore). When I click on the search icon and type any text, my application crashes and I am not able to figure out what could be the reason. Can anyone tell me what is wrong with my code?
class ActivityStudentList : AppCompatActivity() {
private lateinit var studentRecyclerView: RecyclerView
private lateinit var recyclerViewAdapter: RecyclerViewAdapter
private val db = FirebaseFirestore.getInstance()
private lateinit var studentArrayList: ArrayList<StudentRecyclerViewDataClass>
private lateinit var editStudentFab: ExtendedFloatingActionButton
private lateinit var addStudentFab: ExtendedFloatingActionButton
private lateinit var removeStudentFab: ExtendedFloatingActionButton
private lateinit var tempArrayList: ArrayList<StudentRecyclerViewDataClass>
private lateinit var newArrayList: ArrayList<StudentRecyclerViewDataClass>
private var clicked = false
private lateinit var obstructor: RelativeLayout
private val fromBottom: Animation by lazy { AnimationUtils.loadAnimation(this,R.anim.from_bottom_anim) }
private val toBottom: Animation by lazy { AnimationUtils.loadAnimation(this,R.anim.to_bottom_anim) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_student_list)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
actionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayShowTitleEnabled(false)
editStudentFab = findViewById(R.id.editStudentFab)
addStudentFab = findViewById(R.id.addStudentFab)
removeStudentFab = findViewById(R.id.removeStudentFab)
obstructor = findViewById(R.id.obstructor)
studentRecyclerView = findViewById(R.id.studentRecyclerView)
studentRecyclerView.layoutManager = LinearLayoutManager(this)
studentRecyclerView.setHasFixedSize(true)
studentArrayList = arrayListOf<StudentRecyclerViewDataClass>()
recyclerViewAdapter = RecyclerViewAdapter(studentArrayList)
studentRecyclerView.adapter = recyclerViewAdapter
studentRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(studentRecyclerView: RecyclerView, dx: Int, dy: Int) {
if (dy > 0) editStudentFab.hide() else if (dy < 0) editStudentFab.show()
}
})
getStudentData()
editStudentFab.setOnClickListener {
onEditButtonClicked()
}
addStudentFab.setOnClickListener {
startActivity(Intent(this,ActivityAddStudent::class.java))
}
removeStudentFab.setOnClickListener {
startActivity(Intent(this,ActivityAddStudent::class.java))
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.student_recycler_view_search, menu)
val search = menu?.findItem(R.id.student_recycler_view_search)
val searchView = search?.actionView as? SearchView
searchView?.isSubmitButtonEnabled = true
searchView?.setOnQueryTextListener(object: SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
TODO("Not yet implemented")
}
#SuppressLint("NotifyDataSetChanged")
override fun onQueryTextChange(newText: String?): Boolean {
tempArrayList.clear()
val searchText = newText!!.toLowerCase(Locale.getDefault())
if(searchText.isNotEmpty()){
newArrayList.forEach{
if(it.Name!!.toLowerCase(Locale.getDefault()).contains(searchText)){
tempArrayList.add(it)
}
}
studentRecyclerView.adapter!!.notifyDataSetChanged()
}else{
tempArrayList.clear()
tempArrayList.addAll(newArrayList)
studentRecyclerView.adapter!!.notifyDataSetChanged()
}
return false
}
})
return super.onCreateOptionsMenu(menu)
}
private fun onEditButtonClicked() {
setVisibility(clicked)
setAnimation(clicked)
clicked = !clicked
}
#SuppressLint("SetTextI18n")
private fun setAnimation(clicked: Boolean) {
obstructor = findViewById(R.id.obstructor)
addStudentFab = findViewById(R.id.addStudentFab)
removeStudentFab = findViewById(R.id.removeStudentFab)
editStudentFab = findViewById(R.id.editStudentFab)
if(!clicked){
obstructor.visibility = View.VISIBLE
editStudentFab.text = "Close"
editStudentFab.setIconResource(R.drawable.ic_outline_close_24)
addStudentFab.startAnimation(fromBottom)
removeStudentFab.startAnimation(fromBottom)
}else{
obstructor.visibility = View.INVISIBLE
editStudentFab.text = "Edit List"
editStudentFab.setIconResource(R.drawable.ic_outline_edit_24)
addStudentFab.startAnimation(toBottom)
removeStudentFab.startAnimation(toBottom)
}
}
private fun setVisibility(clicked: Boolean) {
addStudentFab = findViewById(R.id.addStudentFab)
removeStudentFab = findViewById(R.id.removeStudentFab)
if(!clicked){
addStudentFab.visibility = View.VISIBLE
removeStudentFab.visibility = View.VISIBLE
}else{
addStudentFab.visibility = View.INVISIBLE
removeStudentFab.visibility = View.INVISIBLE
}
}
private fun getStudentData() {
db.collection("StudentInfo").addSnapshotListener(object: EventListener<QuerySnapshot>{
#SuppressLint("NotifyDataSetChanged")
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
if(error != null){
Log.e("Firestore Error",error.message.toString())
return
}
for(dc : DocumentChange in value?.documentChanges!!){
if(dc.type == DocumentChange.Type.ADDED){
studentArrayList.add(dc.document.toObject(StudentRecyclerViewDataClass::class.java))
}
}
recyclerViewAdapter.notifyDataSetChanged()
}
})
}
}
RecyclerView Adapter code:
class RecyclerViewAdapter(private var studentList : ArrayList<StudentRecyclerViewDataClass>) : RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_student_list_item,parent,false)
return RecyclerViewHolder(itemView)
}
override fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) {
val currentItem = studentList[position]
holder.name.text = currentItem.Name
holder.SRN.text = currentItem.SRN
holder.phone.text = currentItem.Phone
holder.age.text = currentItem.Age
}
override fun getItemCount(): Int {
return studentList.size
}
class RecyclerViewHolder(itemView : View ) : RecyclerView.ViewHolder(itemView){
val name : TextView = itemView.findViewById(R.id.tv_name)
val SRN : TextView = itemView.findViewById(R.id.tv_srn)
val phone : TextView = itemView.findViewById(R.id.tv_phone)
val age : TextView = itemView.findViewById(R.id.tv_age)
}
}

RecyclerView adds Fragment to the wrong position in the list

I have a RecyclerView that has many ViewHolder types. One of those ViewHolder (GoalCardViewHolder) holds a View that is just a container for displaying a Fragment. In my chat app this ViewHolder is used by two different ViewTypes, this is for UserInput and ChatItem view types.
The UserInput type represents when the user needs to act.
User Input
The ChatItemType represent any of the other elements in the Chat, when the user inputs a new goal, a ChatItemType.GoalCard is created: ChatItem.GoalCard
Note that both types use the same ViewHolder.
The problem
When the user is trying to create a new Goal , I expect a new UserInput to be created at the bottom of the chat. However, the previous GoalCardViewHolder is being re-used(this happens a few times, until the list grows long enough that the ViewHolder gets recycled, when that happens the new view is added at the bottom as expected).
The source code
Apologies for the lengthy pasting but the Adapter and MainChatFragment are very complex (please do let me know if you need anything else):
MainChatFragment.kt
class MainChatFragment(
private val viewModel: MainChatViewModel,
private val chatAdapter: ChatAdapter,
private val chatToolbar: ChatToolbar,
private val chatDaySelector: ChatDaySelector,
private val dayOfStudyProvider: DayOfStudyProvider,
private val subjectMenuFragment: SubjectMenuFragment,
private val chatSpeedHelper: ChatSpeedHelper,
) : Fragment() {
private lateinit var dayOfStudySelectorView: DayOfStudySelectorView
private lateinit var binding: FragmentChatBinding
private var scrollDistance: Int = 0
private val cancelOnPauseScope = CancelOnPauseCoroutineScope(this)
private val bufferedChatItems = mutableListOf<IChatItem>()
private val arguments: MainChatFragmentArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentChatBinding.inflate(inflater)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dayOfStudySelectorView = binding.dashboardView
dayOfStudySelectorView.init(dayOfStudyProvider, chatDaySelector)
setupChatItemList()
subjectMenuFragment.closeMenuCallback = { shouldDiscardItems ->
if (!shouldDiscardItems) {
bufferedChatItems.forEach {
addChatItem(it)
}
}
bufferedChatItems.clear()
}
chatAdapter.removeLastUserInput = this::removeLastUserInput
chatAdapter.subjectMenuButtonOnClick = this::openSubjectMenuFragment
chatToolbar.setMenuButtonOnClickListener {
openSubjectMenuFragment()
}
}
private fun removeLastUserInput() {
viewModel.removeLastUserInputAndLogMessage()
}
private fun openSubjectMenuFragment() {
if (!subjectMenuFragment.isAdded) {
subjectMenuFragment.show(requireActivity().supportFragmentManager, "subjectMenu")
}
}
override fun onResume() {
super.onResume()
observeChatItemActions() // Should be last entry in here
}
#Suppress("IMPLICIT_CAST_TO_ANY")
private fun observeChatItemActions() {
cancelOnPauseScope.launch {
viewModel.chatItemActionFlow()
.onStart { viewModel.onUserEnteredChat(arguments.hasJustActivated) }
.transform {
if (it is ChatItemAction.AddChatItemAction) {
val delayMs = chatSpeedHelper.itemDelay(it.chatItem)
if (delayMs > 0) {
delay(delayMs)
}
if (subjectMenuFragment.isVisible) {
bufferedChatItems.add(it.chatItem)
return#transform
}
}
emit(it)
}
.collect {
if (!isVisible) {
return#collect
}
when (it) {
is ChatItemAction.AddChatItemAction -> {
addChatItem(it.chatItem)
}
is ChatItemAction.SetChatItemsAction -> {
chatAdapter.showWaitingBubble = false
binding.emptyChatText.isVisible =
it.chatItems.isEmpty() && !it.chatEnabled
chatAdapter.items = it.chatItems.map { item -> ChatViewItem(item) }
}
is ChatItemAction.RemoveAllItemsAction -> {
chatAdapter.removeAllItems()
}
is ChatItemAction.RemoveLastItemAction -> {
chatAdapter.conditionallyRemoveLastChatItem(it.predicate)
}
}.let { } // Make when exhaustive
}
}
}
private fun addChatItem(chatItem: IChatItem) {
if (chatItem is ChatItem) {
chatItem.chatBackgroundAction?.let { chatBackgroundAction ->
viewModel.launchChatBackgroundAction(chatBackgroundAction)
}
}
val chatViewItem = ChatViewItem(chatItem)
chatAdapter.showWaitingBubble = chatViewItem.shouldShowPendingBubble()
chatAdapter.addChatItem(chatViewItem)
binding.emptyChatText.isVisible = false
}
private fun setupChatItemList() {
val linearLayoutManager = LinearLayoutManager(requireView().context)
linearLayoutManager.stackFromEnd = true
with(binding.chatList) {
layoutManager = linearLayoutManager
adapter = chatAdapter
addItemDecoration(
DividerItemDecoration(
requireView().context,
linearLayoutManager.orientation
).apply {
setDrawable(
ContextCompat.getDrawable(
requireView().context,
R.drawable.divider_chat
)!!
)
})
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
scrollDistance += dy
if (dy < 0 &&
(scrollDistance.absoluteValue >= measuredHeight || !binding.chatList.canScrollVertically(
-1
))
) {
dayOfStudySelectorView.revealDaySelector()
} else if (dy > 0) {
dayOfStudySelectorView.hideDaySelector()
}
}
})
}
}
}
ChatAdapter.kt
class ChatAdapter(
private val widgetHandler: WidgetHandler,
private val coroutineScope: CoroutineScope,
) : RecyclerView.Adapter<BaseChatItemViewHolder>() {
private lateinit var context: Context
private lateinit var layoutInflater: LayoutInflater
private var recyclerView: RecyclerView? = null
private val lastDivider = ChatViewItem(ChatItemType.LastDivider)
private val pendingMessage = ChatViewItem(ChatItemType.PendingMessage)
private val staticPendingView = false
var showWaitingBubble: Boolean = true
set(value) {
if (value != showWaitingBubble) {
setShowingWaitingBubble(value)
}
field = value
}
var removeLastUserInput: () -> Unit = {}
var subjectMenuButtonOnClick: () -> Unit = {}
lateinit var onGoalSettingStarted: (GoalCardProgressListener) -> Unit
private fun setShowingWaitingBubble(value: Boolean): Int {
var updatedIndex = -1
if (_items.isNotEmpty()) {
if (!value) {
_items.lastIndexOf(pendingMessage)
.takeIf { it >= 0 }
?.let {
_items.removeAt(it)
updatedIndex = it
}
} else {
if (!hasPendingBubble() && shouldShowPendingBubble(getLastRealChatItem().second)) {
val divider = hasLastDivider()
updatedIndex = Math.max(0, _items.size - divider.toBitInteger())
_items.add(updatedIndex, pendingMessage)
}
}
}
if (updatedIndex != -1) {
scrollToBottom()
}
return updatedIndex
}
private var _items = ArrayList<ChatViewItem>()
var items: List<ChatViewItem>
get() = _items
set(value) {
_items.clear()
_items.addAll(value)
if (value.isNotEmpty()) {
setShowingWaitingBubble(showWaitingBubble)
}
_items.add(lastDivider)
notifyDataSetChanged()
scrollToBottom()
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
this.recyclerView = recyclerView
context = recyclerView.context
layoutInflater = LayoutInflater.from(recyclerView.context)
recyclerView.setItemViewCacheSize(20)
}
override fun getItemCount(): Int = items.size
override fun getItemViewType(position: Int): Int {
val chatViewItem = items[position]
return when (chatViewItem.type) {
ChatItemType.UserInput, ChatItemType.DisabledUserInput -> {
val inputType = chatViewItem.inputType ?: npe("chatViewItem.inputType")
when (inputType) {
is InputType.GoalSettingCard -> R.layout.goal_card
else -> -1 // deleted other viewTypes for stackOverflow
}
}
ChatItemType.GoalCard -> R.layout.goal_card
else -> -1 // deleted other viewTypes for stackOverflow
}
}
#SuppressLint("SetJavaScriptEnabled")
override fun onBindViewHolder(holder: BaseChatItemViewHolder, position: Int) {
val chatViewItem = items[position]
when (chatViewItem.type) {
ChatItemType.UserInput, ChatItemType.DisabledUserInput -> {
val inputType = chatViewItem.inputType ?: npe("chatViewItem.inputType")
when (inputType) {
is InputType.GoalSettingCard -> {
val goalCardFragment = GoalCardFragment()
goalCardFragment.initialProgress =
GoalBuilder() // Fixme use goal builder from topic interactor
onGoalSettingStarted.invoke(goalCardFragment)
goalCardFragment.arguments =
bundleOf(GoalCardFragment.FLOW_TYPE_EXTRA to inputType.flowType)
goalCardFragment.onCanceledCallback =
(holder as GoalCardViewHolder).canceledListener
goalCardFragment.onCompletedCallback = holder.completedListener
if (inputType.flowType == FlowType.COMPLETE_GOAL) {
context.activity().supportFragmentManager
.beginTransaction()
.replace(
holder.binding.goalCardContainer.id,
goalCardFragment,
GOAL_CARD_FRAGMENT_AS_USER_INPUT
)
.commit()
} else {
TODO("Need implementation")
}
}
}
}
ChatItemType.GoalCard -> {
gson.fromJson(chatViewItem.text, GoalCardParameters::class.java)
GoalCardFragment().let {
if (chatViewItem.data is GoalSettingData) {
it.initialProgress = (chatViewItem.data as GoalSettingData).goalBuilder
}
context.activity().supportFragmentManager.beginTransaction()
.replace(
(holder as GoalCardViewHolder).binding.goalCardContainer.id,
it as GoalCardFragment,
GOAL_CARD_FRAGMENT_AS_CHAT_ITEM
)
.commit()
}
}
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
#LayoutRes viewType: Int
): BaseChatItemViewHolder {
val itemView = layoutInflater.inflate(viewType, parent, false)
return when (viewType) {
R.layout.goal_card -> {
GoalCardViewHolder(itemView).apply {
setOnCanceledListener {
coroutineScope.launch {
removeLastUserInput()
removeFragmentByTag(GOAL_CARD_FRAGMENT_AS_USER_INPUT)
widgetHandler.onWidgetDone(
userResponse = UserResponse(
WIDGET_DISMISSED_WITH_VALUE + "cancelled"
)
)
}
}
setOnCompletedListener {
coroutineScope.launch {
val goalData = UserResponseData.GoalData(it)
removeLastUserInput()
removeFragmentByTag(GOAL_CARD_FRAGMENT_AS_USER_INPUT)
widgetHandler.onWidgetDone(
userResponse = UserResponse(
WIDGET_DISMISSED_WITH_VALUE + "completed", data = goalData
)
)
// TODO api
}
}
}
}
else -> throw IllegalStateException("View type not mapped to a view holder")
}
}
private fun removeFragmentByTag(tag: String) {
context.activity().supportFragmentManager.apply {
findFragmentByTag(tag)?.let {
beginTransaction()
.remove(it)
.commit()
}
}
}
fun addChatItem(chatItemView: ChatViewItem) {
val shouldShowPendingBubble = shouldShowPendingBubble(chatItemView)
setShowingWaitingBubble(shouldShowPendingBubble)
val hasPendingBubble = hasPendingBubble()
val insertIndex = Math.max(
0,
itemCount - hasLastDivider().toBitInteger() - hasPendingBubble.toBitInteger()
)
_items.add(insertIndex, chatItemView)
// sending notifyItemRangeChanged instead of notifyItemInserted is for a feeling of
// scrolling also the pendingBubble, otherwise it looks like it's static view and it's not part of scrolling content
if (staticPendingView && shouldShowPendingBubble) {
notifyItemInserted(insertIndex)
} else {
notifyItemRangeChanged(insertIndex, 1 + hasPendingBubble.toBitInteger())
}
when (chatItemView.inputType) {
is InputType.FreeText,
is InputType.FreeTextWithLimit ->
// for some reason RecyclerView scrolls up little bit when EditText is shown
// basically aligns to bottom of line, not bottom of EditText =>
// let RV do this nonsense and scroll down little bit later
// however we have to do it sooner, we try to show the keyboard then
recyclerView?.postDelayed(UiConst.keyboardHandlingDelay / 2) {
scrollToBottom()
}
else -> scrollToBottom()
}
}
override fun onViewAttachedToWindow(holder: BaseChatItemViewHolder) {
super.onViewAttachedToWindow(holder)
holder.onAttached()
}
override fun onViewDetachedFromWindow(holder: BaseChatItemViewHolder) {
super.onViewDetachedFromWindow(holder)
holder.onDetached()
}
fun removeAllItems() {
_items.clear()
notifyDataSetChanged()
}
fun notifyItemChanged(chatViewItem: ChatViewItem) {
notifyItemChanged(items.indexOf(chatViewItem))
}
fun conditionallyRemoveLastChatItem(predicate: (ChatViewItem) -> Boolean) {
val (index, item) = getLastRealChatItem()
if (item != null && predicate(item)) {
_items.removeAt(index)
notifyItemRemoved(index)
}
}
private fun hasLastDivider(): Boolean = _items.lastOrNull()?.type == ChatItemType.LastDivider
private fun hasPendingBubble(): Boolean {
return (items.lastOrNull(1)?.type == ChatItemType.PendingMessage) ||
(items.lastOrNull(0)?.type == ChatItemType.PendingMessage)
}
private fun getLastRealChatItem(): Pair<Int, ChatViewItem?> {
if (!items.isEmpty()) {
(items.size - 1 downTo 0).forEach { i ->
val item = items[i]
when (item.type) {
ChatItemType.LastDivider,
ChatItemType.PendingMessage -> {
/*ignore*/
}
else -> return Pair(i, item)
}
}
}
return Pair(-1, null)
}
private val skipPendingBubbleFor = listOf(
ChatItemType.UserInput,
ChatItemType.LastBotMessage
)
private fun shouldShowPendingBubble(chatItemView: ChatViewItem?): Boolean {
return showWaitingBubble && !skipPendingBubbleFor.contains(chatItemView?.type)
}
private fun scrollToBottom() {
(recyclerView?.layoutManager as? LinearLayoutManager)?.scrollToPosition(itemCount - 1)
}
companion object {
const val GOAL_CARD_FRAGMENT_AS_USER_INPUT = "goal-card-fragment-user-input"
const val GOAL_CARD_FRAGMENT_AS_CHAT_ITEM = "goal-card-fragment-chat-item"
}
}
abstract class BaseChatItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
open fun onAttached() {}
open fun onDetached() {}
open fun bind(chatViewItem: ChatViewItem) {}
abstract val binding: ViewBinding?
}
abstract class BaseTextChatItemViewHolder(itemView: View) : BaseChatItemViewHolder(itemView) {
abstract val chatText: TextView
}
class GoalCardViewHolder(itemView: View) : BaseChatItemViewHolder(itemView) {
lateinit var canceledListener: (() -> Unit)
lateinit var completedListener: ((GoalBuilder) -> Unit)
fun setOnCanceledListener(canceledListener: () -> Unit) {
this.canceledListener = canceledListener
}
fun setOnCompletedListener(completedListener: (GoalBuilder) -> Unit) {
this.completedListener = completedListener
}
override val binding: GoalCardBinding = GoalCardBinding.bind(itemView)
}
goal_card.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/goal_card_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The issue and lesson learned was 'never use a Fragment in a RecyclerView.ViewHolders
I converted my fragment to a custom view and the problem is no longer happening.
I think it must have been an issue with the Fragment's lifecycle.

How to insert items at a certain position in a recyclerView?

I have set up a fragment with a recyclerView in it and I fetch data from firestore successfully. What I want to know is that if it is possible to add items at a certain position in recyclerView. Suppose, I want to add an item (from a different collection in Firestore) after every 5 items in a recyclervView. Is it possible to do it in Android using Kotlin?
Thank you.
Edit:
DashboardFragment.kt
class DashboardFragment : BaseFragment() {
var srchProductsList: ArrayList<Product> = ArrayList()
var adList: ArrayList<Ads> = ArrayList()
var srchTempProductsList: ArrayList<Product> = ArrayList()
var newView: String = "ListView"
private lateinit var binding: FragmentDashboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.fbDashboard.setImageResource(R.drawable.ic_grid_view)
binding.fbDashboard.setOnClickListener {
if (newView=="ListView"){
newView="GridView"
fb_dashboard.setImageResource(R.drawable.ic_list_view)
}else{
newView="ListView"
fb_dashboard.setImageResource(R.drawable.ic_grid_view)
}
onResume()
}
return binding.root
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
R.id.action_settings -> {
startActivity(Intent(activity, SettingsActivity::class.java))
return true
}
R.id.action_cart -> {
startActivity(Intent(activity, CartListActivity::class.java))
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
srchProductsList.clear()
srchTempProductsList.clear()
getDashboardItemsList()
}
private fun getDashboardItemsList() {
showProgressDialog(resources.getString(R.string.please_wait))
getDashboardItemsList2()
}
fun successDashboardItemsList(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
fun successDashboardItemsListListView(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
LinearLayoutManager(context)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.dashboard_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
val item = menu.findItem(R.id.my_search_bar)
val searchView = item?.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
srchTempProductsList.clear()
val searchKey = query
if (searchKey != null) {
if (searchKey.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault())
.contains(searchKey)
) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
}
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
srchTempProductsList.clear()
val searchText = newText!!.toLowerCase(Locale.getDefault())
if (searchText.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault()).contains(searchText)) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
return false
}
})
}
private fun getDashboardItemsList2() {
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection(Constants.PRODUCTS)
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val product = i.toObject(Product::class.java)!!
product.product_id = i.id
srchProductsList.add(product)
}
srchTempProductsList.addAll(srchProductsList)
if (newView == "ListView") {
successDashboardItemsListListView(srchTempProductsList)
} else {
successDashboardItemsList(srchTempProductsList)
}
}
.addOnFailureListener {
}
}
private fun getListOfAds() : ArrayList<Ads>{
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("ads")
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val ad = i.toObject(Ads::class.java)!!
ad.ad_id = i.id
adList.add(ad)
}
}
.addOnFailureListener {
}
return adList
}
}
DashboardItemListAdapterTest.kt
open class DashboardItemsListAdapterTest(
private val context: Context,
private var prodlist: ArrayList<Product>,
private var adslist: ArrayList<Ads>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val produc= 1
const val ads= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == produc) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_list_view_layout, parent, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_ad_view_layout, parent, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val promodel = prodlist[position]
val adsmodel = adslist[position]
if(getItemViewType(position) == produc) {
holder.itemView.tv_item_name.text = promodel.title
}else{
holder.itemView.tv_item_name.text = adsmodel.title
}
}
override fun getItemCount(): Int {
return prodlist.size + adslist.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) ads else produc
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}
Model class
Ads.kt
data class Ads(
val title: String = "",
var ad_id: String = ""
)
You can use two viewholder for two different collections of data.
Change your adapter class like this.
class YourAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val COLLCTION1= 1
const val COLLCTION2= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == COLLCTION1) {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection1, viewGroup, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection2, viewGroup, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(getItemViewType(position) == COLLCTION1) {
holder.name.text = collection1.text
}else{
holder.name.text = collection2.text
}
}
override fun getItemCount(): Int {
return collection1.size + collection2.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) COLLCTION2 else COLLCTION1
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}

ListAdapter does not fill the adapter on 2nd fragment of application

I have an application with 2 fragments, both have lists that are being filled from the same adapter.
The first one works correctly, but the second one -
class CountryBordersFragment : Fragment(R.layout.fragment_country_borders) {
private lateinit var selectedCountry: String
private lateinit var countriesViewModel: CountriesListViewModel
private lateinit var countriesAdapter: CountriesListAdapter
private var countriesList = mutableListOf<CountryEntity>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
countriesViewModel = ViewModelProvider(this).get(CountriesListViewModel::class.java)
initData()
initClickListener()
}
private fun initClickListener() {
backButton.setOnClickListener {
requireActivity().onBackPressed()
}
}
private fun initData() {
countriesAdapter = CountriesListAdapter(null)
countriesAdapter.submitList(countriesList)
countriesRecyclerView.setHasFixedSize(true)
countriesRecyclerView.layoutManager = LinearLayoutManager(context)
countriesRecyclerView.adapter = countriesAdapter
arguments?.let {
selectedCountry = it.getString(getString(R.string.countries_list_fragment_selected_country))!!
}
countryName.text = selectedCountry
countriesViewModel.getCountryBorders(selectedCountry).observeOnce(requireActivity(), Observer { countryBorder ->
if (countryBorder.neighborCountries.isEmpty()) {
bordersWith.text = getString(R.string.country_border_fragment_country_does_not_have_borders)
return#Observer
}
countriesViewModel.getCountryByCioc(countryBorder.neighborCountries).observe(requireActivity(), Observer { countryEntityList ->
countriesAdapter.submitList(countryEntityList)
})
})
}
}
Does not fill the adapter at all. It just does not display any list whatsoever.
For sure something is missing because I am able to fill my adapter correctly at the first fragment but coming to this one the list does not pop up.
Here is my ListAdapter implementation -
class CountriesListAdapter(private val callback: CountryViewHolder.OnCountryClickListener?)
: ListAdapter<CountryEntity, CountryViewHolder>(CountriesDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CountryViewHolder {
val view = LayoutInflater.from(App.context!!).inflate(R.layout.country_viewholder, parent, false)
return CountryViewHolder(view)
}
override fun onBindViewHolder(holder: CountryViewHolder, position: Int) {
holder.bind(getItem(position), callback)
}
class CountriesDiffCallback : DiffUtil.ItemCallback<CountryEntity>() {
override fun areItemsTheSame(oldItem: CountryEntity, newItem: CountryEntity): Boolean {
return oldItem.countryName == newItem.countryName
}
override fun areContentsTheSame(oldItem: CountryEntity, newItem: CountryEntity): Boolean {
return oldItem == newItem
}
}
}
and my ViewHolder and model -
class CountryViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val rootLayout: LinearLayout = view.country_viewholder_root_layout
private val nativeName: TextView = view.country_viewholder_native_name
private val countryName: TextView = view.country_viewholder_country_name
private val area: TextView = view.country_viewholder_area
private val countryImage: ImageView = view.country_viewholder_country_image
fun bind(model: CountryEntity, callback: OnCountryClickListener?) {
nativeName.text = App.context!!.getString(R.string.country_view_holder_native_name).plus(" ${model.countryName}")
countryName.text = App.context!!.getString(R.string.country_view_holder_country_name).plus(" ${model.nativeName}")
area.text = App.context!!.getString(R.string.country_view_holder_country_area).plus(" ${model.area}")
// Glide.with(App.context!!).load("https://www.talkwalker.com/images/2020/blog-headers/image-analysis.png").into(countryImage)
Picasso.get().load(model.imageUri).into(countryImage)
rootLayout.setOnClickListener {
callback?.onCountryClicked(model.countryName)
}
}
interface OnCountryClickListener {
fun onCountryClicked(countryName: String)
}
}
#Entity(tableName = countriesTable, primaryKeys = ["countryName"])
class CountryEntity(
val countryName: String,
val nativeName: String,
val area: Double,
val cioc: String? = null,
val imageUri : String? = null
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CountryEntity
if (countryName != other.countryName) return false
if (nativeName != other.nativeName) return false
if (area != other.area) return false
if (cioc != other.cioc) return false
if (imageUri != other.imageUri) return false
return true
}
override fun hashCode(): Int {
var result = countryName.hashCode()
result = 31 * result + nativeName.hashCode()
result = 31 * result + area.hashCode()
result = 31 * result + (cioc?.hashCode() ?: 0)
result = 31 * result + (imageUri?.hashCode() ?: 0)
return result
}
}
class CountryViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val rootLayout: LinearLayout = view.country_viewholder_root_layout
private val nativeName: TextView = view.country_viewholder_native_name
private val countryName: TextView = view.country_viewholder_country_name
private val area: TextView = view.country_viewholder_area
private val countryImage: ImageView = view.country_viewholder_country_image
fun bind(model: CountryEntity, callback: OnCountryClickListener?) {
nativeName.text = App.context!!.getString(R.string.country_view_holder_native_name).plus(" ${model.countryName}")
countryName.text = App.context!!.getString(R.string.country_view_holder_country_name).plus(" ${model.nativeName}")
area.text = App.context!!.getString(R.string.country_view_holder_country_area).plus(" ${model.area}")
// Glide.with(App.context!!).load("https://www.talkwalker.com/images/2020/blog-headers/image-analysis.png").into(countryImage)
Picasso.get().load(model.imageUri).into(countryImage)
rootLayout.setOnClickListener {
callback?.onCountryClicked(model.countryName)
}
}
interface OnCountryClickListener {
fun onCountryClicked(countryName: String)
}
}
What is it that I am missing? Just started working with ListAdapter from normal RecyclerView.Adapter.
Looks like you are missing - notifyDataSetChanged()
Just After -
countriesAdapter.submitList(countryEntityList)
Add -
countriesAdapter.notifyDataSetChanged()

How to get selected Popup Menu item position value and pass it

I've got a Popup menu that should launch a Maps intent whenever a Popup menu item is clicked. In popupMenu.setOnMenuItemClickListener, does anyone know how I can pass the String of the clicked Popup menu item (from the arrayAMap array) and use it for an intent? I've already got the Arrays but I can't seem to figure out that correct way to implement this function.
class MyAdapter(
private val mCtx: Context,
var myList: MutableList<ItemRV>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), PopupMenu.OnMenuItemClickListener {
private var mClickListener: ItemClickListener? = null
lateinit var mAdView : AdView
private val itemRV = 1
private val itemAD = 2
override fun getItemViewType(position: Int): Int {
return if (position % 4 == 0) {
itemAD
} else {
itemRV
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == itemAD) {
val v = LayoutInflater.from(mCtx).inflate(R.layout.item_ad, parent, false)
AdViewHolder(v)
} else {
val v = LayoutInflater.from(mCtx).inflate(R.layout.item_rv, parent, false)
AreaViewHolder(v)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder) {
is AdViewHolder -> {
MobileAds.initialize(mCtx) {}
mAdView = holder.itemView.findViewById(R.id.adView)
val adRequest = AdRequest.Builder().build()
mAdView.loadAd(adRequest)
}
is AreaViewHolder -> {
val positionToBind = position - position / 4 - 1
val product = myList[positionToBind]
holder.tvTitle.text = product.itemTitle
}
}
}
override fun getItemCount(): Int {
return myList.size
}
inner class AdViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
.ViewHolder(itemView), View.OnClickListener {
override fun onClick(v: View?) {
}
}
inner class AreaViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
.ViewHolder(itemView), View.OnClickListener {
var tvTitle: TextView = itemView.tvtitle
// Use package name which we want to check
private val isAppInstalled = appInstalledOrNot("com.google.android.apps.maps")
private val isLiteAppInstalled = appInstalledOrNot("com.google.android.apps.mapslite")
fun launchMapIntent(nameLocation: String) {
val mapPkg = when {
isAppInstalled -> "com.google.android.apps.maps"
isLiteAppInstalled -> "com.google.android.apps.mapslite"
else -> null
}
val mapIntent = if(mapPkg != null) {
val gmmIntentUri = Uri.parse("geo:0,0?q=$nameLocation")
Intent(Intent.ACTION_VIEW, gmmIntentUri).setPackage(mapPkg)
} else {
val encLoc = Uri.encode(nameLocation)
val str = "https://www.google.com/maps/place/$encLoc/"
Intent(Intent.ACTION_VIEW, Uri.parse(str))
}
mCtx.startActivity(mapIntent)
}
val arrayA = arrayOf(view.resources.getString(R.string.stockholm),
view.resources.getString(R.string.copenhagen))
val arrayAMap = arrayOf("Stockholm, Sweden", "Copenhagen, Denmark")
fun launchPopupMenu(namePopupItemLocation: Array<String>, nameLocation: Array<String>){
val popupMenu = PopupMenu(ibMap.context, ibMap)
for (item in namePopupItemLocation) {
popupMenu.menu.add(item)
}
popupMenu.setOnMenuItemClickListener {
launchMapIntent(nameLocation.get())
true
}
popupMenu.show()
}
ibMap.setOnClickListener {
when(tvTitle.text.toString()) {
"A" -> launchMapIntent("Paris, France")
"B" -> launchPopupMenu(arrayA, arrayAMap)
else -> return#setOnClickListener
}
}
}
private fun appInstalledOrNot(uri: String): Boolean {
val pm = mCtx.packageManager
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES)
return true
} catch (e: PackageManager.NameNotFoundException) {
}
return false
}
}
// Parent activity will implement this method to respond to click events
interface ItemClickListener {
fun onItemClick(view: View, position: Int)
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
}
}
You can get clicked menu item in setOnMenuItemClickListener and from that menu item you can get title of that menu
popupMenu.setOnMenuItemClickListener { item ->
nameLocation.forEach {
if (it.toLowerCase().startsWith(item.title.toLowerCase())) {
launchMapIntent(it)
}
}
true
}
Hope this will help!!

Categories

Resources