Fix navigation and backstack problems

Check if the search view is iconified or current destination is bottom nav, then avoid navigation to search fragment.

Move the `searchFragment` navigation to `onMenuItemActionExpand` so every time search expand, try to get the search fragment.

Clear the focus of `searchView` when a query is submitted. Helps in decreasing the number of back presses to minimize player and navigate back.

No need to remove focus using `SearchResultFragment#onStop`, `BackPressedDispatche` can handle it.
This commit is contained in:
Krunal Patel 2022-11-20 23:29:12 +05:30
parent b45e6f8166
commit d03169b11a
2 changed files with 49 additions and 22 deletions

View File

@ -17,6 +17,7 @@ import android.view.WindowManager
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.children
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.findNavController import androidx.navigation.findNavController
@ -117,13 +118,17 @@ class MainActivity : BaseActivity() {
binding.bottomNav.removeBadge(R.id.subscriptionsFragment) binding.bottomNav.removeBadge(R.id.subscriptionsFragment)
} }
removeSearchFocus()
// navigate to the selected fragment, if the fragment already // navigate to the selected fragment, if the fragment already
// exists in backstack then pop up to that entry // exists in backstack then pop up to that entry
if (!navController.popBackStack(it.itemId, false)) { if (!navController.popBackStack(it.itemId, false)) {
navController.navigate(it.itemId) navController.navigate(it.itemId)
} }
// Remove focus from search view when navigating to bottom view.
// Call only after navigate to destination, so it can be used in
// onMenuItemActionCollapse for backstack management
removeSearchFocus()
false false
} }
@ -154,6 +159,8 @@ class MainActivity : BaseActivity() {
if (navController.currentDestination?.id == startFragmentId) { if (navController.currentDestination?.id == startFragmentId) {
moveTaskToBack(true) moveTaskToBack(true)
} else { } else {
navController.popBackStack(R.id.searchResultFragment, false) ||
navController.popBackStack(R.id.searchFragment, true) ||
navController.popBackStack() navController.popBackStack()
} }
} }
@ -226,23 +233,26 @@ class MainActivity : BaseActivity() {
val searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java] val searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]
searchView.setOnSearchClickListener {
if (navController.currentDestination?.id != R.id.searchResultFragment) {
searchViewModel.setQuery(null)
navController.navigate(R.id.searchFragment)
}
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean { override fun onQueryTextSubmit(query: String?): Boolean {
val bundle = Bundle() val bundle = Bundle()
bundle.putString("query", query) bundle.putString("query", query)
navController.navigate(R.id.searchResultFragment, bundle) navController.navigate(R.id.searchResultFragment, bundle)
searchViewModel.setQuery("") searchViewModel.setQuery("")
searchView.clearFocus()
return true return true
} }
override fun onQueryTextChange(newText: String?): Boolean { override fun onQueryTextChange(newText: String?): Boolean {
// Prevent navigation when search view is collapsed
if (searchView.isIconified ||
binding.bottomNav.menu.children.any {
it.itemId == navController.currentDestination?.id
}
) {
return true
}
// prevent malicious navigation when the search view is getting collapsed // prevent malicious navigation when the search view is getting collapsed
if (navController.currentDestination?.id in listOf( if (navController.currentDestination?.id in listOf(
R.id.searchResultFragment, R.id.searchResultFragment,
@ -265,6 +275,35 @@ class MainActivity : BaseActivity() {
return true return true
} }
}) })
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
if (navController.currentDestination?.id != R.id.searchResultFragment) {
searchViewModel.setQuery(null)
navController.navigate(R.id.searchFragment)
}
return true
}
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
if (binding.mainMotionLayout.progress == 0F) {
try {
minimizePlayer()
} catch (e: Exception) {
// current fragment isn't the player fragment
}
}
// Handover back press to `BackPressedDispatcher`
else if (binding.bottomNav.menu.children.none {
it.itemId == navController.currentDestination?.id
}
) {
this@MainActivity.onBackPressedDispatcher.onBackPressed()
}
return true
}
})
return super.onCreateOptionsMenu(menu) return super.onCreateOptionsMenu(menu)
} }

View File

@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.RetrofitInstance
@ -16,7 +15,6 @@ import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.obj.SearchHistoryItem import com.github.libretube.db.obj.SearchHistoryItem
import com.github.libretube.extensions.TAG import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.hideKeyboard import com.github.libretube.extensions.hideKeyboard
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.adapters.SearchAdapter import com.github.libretube.ui.adapters.SearchAdapter
import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.PreferenceHelper
@ -143,14 +141,4 @@ class SearchResultFragment : BaseFragment() {
) )
} }
} }
override fun onStop() {
if (findNavController().currentDestination?.id != R.id.searchFragment) {
// remove the search focus
(activity as MainActivity)
.binding.toolbar.menu
.findItem(R.id.action_search).collapseActionView()
}
super.onStop()
}
} }