Skip to content

Commit

Permalink
increase speed of back navigation between screens
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Jul 14, 2024
1 parent a22e200 commit ef99354
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,46 @@ import kotlinx.coroutines.Job
abstract class BaseFragment<T : ViewBinding> : Fragment(), Throttler {

abstract val inflater: (LayoutInflater, ViewGroup?, Boolean) -> T
protected val binding: T get() = _binding!!
override var throttleJob: Job? = null
protected open val binding: T get() = _binding!!
private var _binding: T? = null
private var preDrawListeners: MutableList<OnPreDrawListener> = mutableListOf()
override var throttleJob: Job? = null
private var initialized: Boolean = false

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
_binding = inflater(inflater, container, false)
return binding.root
// Use previously saved view to avoid whole screen reinflating on back navigation,
// because of android nav component using fragment.replace internally.
// This also somehow fixes memory leaks occurring on navigation
// from main to some edit screen and back.
// If this ever changes - need to also fix these memory leaks.
return _binding?.root?.also {
initialized = true
} ?: run {
initialized = false
_binding = inflater(inflater, container, false)
binding.root
}
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
initUi()
initUx()
if (!initialized) {
initUi()
initUx()
}
// Need to observe ViewModel again because LiveData.observe() uses fragment lifecycle,
// meaning that the subscriptions are removed on view destroy event.
initViewModel()
}

override fun onDestroy() {
super.onDestroy()
preDrawListeners.forEach { view?.viewTreeObserver?.removeOnPreDrawListener(it) }
preDrawListeners.clear()
_binding = null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ inline fun Fragment.setSharedTransitions(
ViewCompat.setTransitionName(sharedView, transitionName)
}

fun Fragment.addOnBackPressedListener(isEnabled: Boolean = true, action: () -> Unit) {
activity?.onBackPressedDispatcher?.addCallback(
this,
object : OnBackPressedCallback(isEnabled) {
override fun handleOnBackPressed() = action()
},
)
fun Fragment.addOnBackPressedListener(
isEnabled: Boolean = true,
action: () -> Unit,
): OnBackPressedCallback {
val callback = object : OnBackPressedCallback(isEnabled) {
override fun handleOnBackPressed() = action()
}
// Using fragment lifecycle to avoid listener removed on view destroy event.
activity?.onBackPressedDispatcher?.addCallback(this, callback)
return callback
}

fun Fragment.getDrawable(@DrawableRes resId: Int): Drawable? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ChangeActivityFilterFragment :
}
}

override fun initUx() = with(binding) {
override fun initUx(): Unit = with(binding) {
etChangeActivityFilterName.doAfterTextChanged { viewModel.onNameChange(it.toString()) }
fieldChangeActivityFilterColor.setOnClick(viewModel::onColorChooserClick)
fieldChangeActivityFilterType.setOnClick(viewModel::onTypeChooserClick)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class ChangeCategoryFragment :
)
}

override fun initUx() = with(binding) {
override fun initUx(): Unit = with(binding) {
etChangeCategoryName.doAfterTextChanged { viewModel.onNameChange(it.toString()) }
fieldChangeCategoryColor.setOnClick(viewModel::onColorChooserClick)
fieldChangeCategoryType.setOnClick(viewModel::onTypeChooserClick)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class ChangeRecordTagFragment :
}
}

override fun initUx() = with(binding) {
override fun initUx(): Unit = with(binding) {
etChangeRecordTagName.doAfterTextChanged { viewModel.onNameChange(it.toString()) }
fieldChangeRecordTagColor.setOnClick(viewModel::onColorChooserClick)
fieldChangeRecordTagIcon.setOnClick(viewModel::onIconChooserClick)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class ChangeRecordTypeFragment :
}
}

override fun initUx() = with(binding) {
override fun initUx(): Unit = with(binding) {
etChangeRecordTypeName.doAfterTextChanged { viewModel.onNameChange(it.toString()) }
fieldChangeRecordTypeColor.setOnClick(viewModel::onColorChooserClick)
fieldChangeRecordTypeIcon.setOnClick(viewModel::onIconChooserClick)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.fragment.app.viewModels
import androidx.viewpager2.widget.ViewPager2
import com.example.util.simpletimetracker.core.base.BaseFragment
import com.example.util.simpletimetracker.core.di.BaseViewModelFactory
import com.example.util.simpletimetracker.core.extension.addOnBackPressedListener
import com.example.util.simpletimetracker.core.extension.addOnPageChangeCallback
import com.example.util.simpletimetracker.core.sharedViewModel.MainTabsViewModel
import com.example.util.simpletimetracker.core.utils.SHORTCUT_NAVIGATION_KEY
Expand Down Expand Up @@ -48,7 +49,7 @@ class MainFragment : BaseFragment<Binding>() {

private val selectedColorFilter by lazy { getColorFilter(R.attr.appTabSelectedColor) }
private val unselectedColorFilter by lazy { getColorFilter(R.attr.appTabUnselectedColor) }
private val backPressedCallback: OnBackPressedCallback = getOnBackPressedCallback()
private var backPressedCallback: OnBackPressedCallback? = null
private var shortcutNavigationHandled = false
private val mainPagePosition by lazy {
mainTabsProvider.mainTab.let(mainTabsProvider::mapTabToPosition)
Expand All @@ -57,7 +58,10 @@ class MainFragment : BaseFragment<Binding>() {
override fun initUi() {
setupPager()
checkForShortcutNavigation()
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, backPressedCallback)
}

override fun initUx() {
backPressedCallback = addOnBackPressedListener(false, ::onBackPressed)
}

override fun initViewModel() {
Expand Down Expand Up @@ -102,7 +106,7 @@ class MainFragment : BaseFragment<Binding>() {

override fun onTabSelected(tab: TabLayout.Tab?) {
tab?.icon?.colorFilter = selectedColorFilter
backPressedCallback.isEnabled = tab?.position.orZero() != mainPagePosition
backPressedCallback?.isEnabled = tab?.position.orZero() != mainPagePosition
}
},
)
Expand Down Expand Up @@ -132,12 +136,8 @@ class MainFragment : BaseFragment<Binding>() {
}.let(mainTabs::setSelectedTabIndicatorGravity)
}

private fun getOnBackPressedCallback(): OnBackPressedCallback {
return object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
binding.mainPager.setCurrentItem(mainPagePosition, true)
}
}
private fun onBackPressed() {
binding.mainPager.setCurrentItem(mainPagePosition, true)
}

private fun checkForShortcutNavigation() = with(binding) {
Expand Down

0 comments on commit ef99354

Please sign in to comment.