Paulakram
Paulakram

Reputation: 1

In kotlin, returning from a single item update fragment, I am unable to reapply my searchquery to my recyclerview

I am trying to teach myself coding using kotlin. I am using a navigation graph to navigate through various fragments using a mainactivity. THe home fragment displays in a recyclerview a list of towns, from a firebase realtime database, with a searchquery on the town name. The user can select a single item on the recyclerview and go to the update fragment where one or more fields can be updated. There is a button in the update fragment that allows the user to update the item. After validation the user is returned to the home fragment. Because of the eventlistener on firebase the updated item is correctly displayed in the recyclerview. If the user returns without updating the data remains the same.If another user updates an item that is displayed in this users list it is immediately updated. There are 4 options. No search criteria, return from update without updating item. Works ok. No search criteria, return from update fragment after updating item. Works ok. With search criteria, return from update fragment without updating. Works ok. (list shown is meets the search criteria) With search criteria, return from update fragment after updating item. Not working - the previous search criteria is not being reapplied and the full list is being displayed. I am not using diffutil, but when I did I had the same problem. town data class

data class Towns(
    val townCountryCode: String? = null,
    val townCode: String? = null,
    val townName: String? = null,
    val townLat: String? = null,
    val townLng: String? = null,
    val townEmail: String? = null,
    val townFranId: String? = null
) 
                                 
class HometownFragment : Fragment() {
    private var bindingH: FragmentHometownBinding? = null
    private val binding get() = bindingH!!
    private lateinit var townsList: ArrayList<Towns>
    private lateinit var firebaseRef: DatabaseReference
    private lateinit var rvTownsAdapter: RvTownsAdapter
    private var valueEventListener: ValueEventListener? = null
    private var currentSearchQuery: String? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        bindingH = FragmentHometownBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Restore search query from savedInstanceState (Bundle)
        currentSearchQuery = savedInstanceState?.getString("SEARCH_QUERY")

        Log.d("hometown", "currentSearchQuery restore $currentSearchQuery ")
        // Handle back press to sign out
        requireActivity().onBackPressedDispatcher.addCallback(
            viewLifecycleOwner,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    SignOutUtils.signOutHandler(this@HometownFragment)
                }
            })

        binding.btnAddT.setOnClickListener {
            findNavController().navigate(R.id.action_hometownFragment_to_addtownFragment)
        }

        // Shared preferences to get country and set up Firebase reference
        val sharePreference = activity?.getSharedPreferences("MY_PRE", Context.MODE_PRIVATE)
        val userCountry = sharePreference?.getString("USERCOUNTRY", "").toString()
        firebaseRef = FirebaseDatabase.getInstance().getReference("towns").child(userCountry)

        townsList = arrayListOf()
        rvTownsAdapter = RvTownsAdapter(townsList)

        // Set up RecyclerView
        binding.rvTowns.apply {
            setHasFixedSize(true)
            layoutManager = LinearLayoutManager(this.context)
            adapter = rvTownsAdapter
        }

        // Fetch data from Firebase and update the list
        fetchData()

        // Handle search query changes
        binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {

            override fun onQueryTextSubmit(query: String?): Boolean {
                binding.searchView.clearFocus()
                Log.d("hometown", "in onQueryTextSubmit ")
                return false
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                Log.d("hometown", "currentSearchQuery text change before newText $currentSearchQuery ")
                currentSearchQuery = newText
                Log.d("hometown", "currentSearchQuery text change after newText $currentSearchQuery ")
                applySearchQuery() // Reapply filter immediately when query changes
                return true
            }
        })

        // If there was a saved search query, apply it
        currentSearchQuery?.let {
            binding.searchView.setQuery(it, false)
            applySearchQuery() // Apply the filter
        }
    }

    override fun onPause() {
        super.onPause()
        // Save the current search query
        currentSearchQuery = binding.searchView.query.toString()
        Log.d("hometown", "currentSearchQuery on pause $currentSearchQuery ")
    }

    override fun onResume() {
        super.onResume()
        // Restore the search query when coming back to the fragment
        currentSearchQuery?.let {
            binding.searchView.setQuery(it, false)
        }
        Log.d("hometown", "currentSearchQuery on resume $currentSearchQuery ")
    }


    private fun fetchData() {
        valueEventListener?.let {
            firebaseRef.removeEventListener(it)
        }

        valueEventListener = firebaseRef.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                townsList.clear()
                if (snapshot.exists()) {
                    for (contactSnap in snapshot.children) {
                        val towns = contactSnap.getValue(Towns::class.java)
                        townsList.add(towns!!)
                    }
                }

                // After data is fetched, apply the search query if there is one
                applySearchQuery()

                // Ensure that the search query listener is still set
                binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                    override fun onQueryTextSubmit(query: String?): Boolean {
                        binding.searchView.clearFocus()
                        return false
                    }

                    override fun onQueryTextChange(newText: String?): Boolean {
                        Log.d("hometown", "currentSearchQuery text change before 2nd newText $currentSearchQuery ")
                        currentSearchQuery = newText
                        Log.d("hometown", "currentSearchQuery text change after 2nd newText $currentSearchQuery ")
                        applySearchQuery() // Reapply filter immediately when query changes
                        return true
                    }
                })

            }

            override fun onCancelled(error: DatabaseError) {
                Toast.makeText(context, "Error fetching data: $error", Toast.LENGTH_SHORT).show()
            }
        })
    }

    private fun applySearchQuery() {
        // Always apply search query when the data is updated
        val filteredList = if (currentSearchQuery.isNullOrEmpty()) {
            townsList // Show all towns if there's no search query
        } else {
            townsList.filter {
                it.townName!!.lowercase().contains(currentSearchQuery!!.lowercase())
            }
        }

        rvTownsAdapter.updateList(ArrayList(filteredList))
        if (filteredList.isEmpty() && townsList.isNotEmpty()) {
            ToastUtils.showToast(requireContext(), R.string.no_data_available)
        }
    }
}                                                                                      

 
class RvTownsAdapter(private var townsList: ArrayList<Towns>) :
    RecyclerView.Adapter<RvTownsAdapter.ViewHolder>() {

        class ViewHolder(val binding: RvTownsItemBinding) : RecyclerView.ViewHolder(binding.root)
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            return ViewHolder(RvTownsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
        }

        override fun getItemCount(): Int {
            return townsList.size
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val currentItem = townsList[position]
            val context = holder.itemView.context

            holder.binding.apply {
                tvTownCodeItem.text = currentItem.townCode
                tvTownNameItem.text = currentItem.townName
                tvTownLatItem.text = currentItem.townLat
                tvTownLngItem.text = currentItem.townLng
                tvTownEmailItem.text = currentItem.townEmail
                tvTownFranIdItem.text = currentItem.townFranId

                 rvTownContainer.setOnClickListener {
                    navigateToUpdateTownFragment(currentItem, holder)
                }

                rvTownContainer.setOnLongClickListener {
                    handleLongClick(context, currentItem, holder)
                    true
                }

                btnAddS.setOnClickListener {
                    Log.d("Navigate", "townCode: $currentItem.townCode, townName: $currentItem.townName")
                    navigateToStreetFragment(currentItem, holder)
                }
            }
        }

       fun updateList(newList: ArrayList<Towns>) {
            townsList = newList
            notifyDataSetChanged()
       }

        private fun navigateToUpdateTownFragment(currentItem: Towns, holder: ViewHolder) {
            val actionUpdate = HometownFragmentDirections.actionHometownFragmentToUpdatetownFragment(
                currentItem.townCountryCode?: "",
                currentItem.townCode?: "",
                currentItem.townName?: "",
                currentItem.townLat?: "",
                currentItem.townLng?: "",
                currentItem.townEmail?: "",
                currentItem.townFranId?: ""
            )
            findNavController(holder.itemView).navigate(actionUpdate)
        }


 
        private fun navigateToStreetFragment(currentItem: Towns, holder: RvTownsAdapter.ViewHolder) {
            val action = HometownFragmentDirections.actionHometownFragmentToHomestreetFragment(
                currentItem.townCode?: "",
                currentItem.townName?: ""
            )
            Log.d("NavigateToStreet", "townCode: $currentItem.townCode, townName: $currentItem.townName")


            findNavController(holder.itemView).navigate(action)
        }

        private fun showMessageShort(context: Context, message: String) {
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
        }
    }

I tried storing the currentSearchQuery in SEARCH_QUERY and reapplying it on returning from the update fragment but that is not working. After many different attempts I added log.d to monitor what happens. With my current code, which I recognize is not efficient, When using the search criteria est

Upvotes: 0

Views: 20

Answers (0)

Related Questions