From bfe24e5dfdd152b17361de5eafacb31cede20b29 Mon Sep 17 00:00:00 2001 From: tzugen Date: Mon, 5 Jun 2023 17:23:48 +0200 Subject: [PATCH] Modernize backhandling to support predictive back handling --- ultrasonic/src/main/AndroidManifest.xml | 1 + .../ultrasonic/activity/NavigationActivity.kt | 48 ++++++++++++------- .../ultrasonic/fragment/EditServerFragment.kt | 30 +++++++++--- .../fragment/OnBackPressedHandler.kt | 15 ------ 4 files changed, 56 insertions(+), 38 deletions(-) delete mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt diff --git a/ultrasonic/src/main/AndroidManifest.xml b/ultrasonic/src/main/AndroidManifest.xml index 266ccd79..332bb4a2 100644 --- a/ultrasonic/src/main/AndroidManifest.xml +++ b/ultrasonic/src/main/AndroidManifest.xml @@ -33,6 +33,7 @@ android:supportsRtl="false" android:preserveLegacyExternalStorage="true" tools:ignore="UnusedAttribute"> + diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index 8ed8c8bc..416d5e12 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -21,6 +21,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ImageView +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat @@ -51,7 +52,6 @@ import org.moire.ultrasonic.R import org.moire.ultrasonic.app.UApp import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ServerSettingDao -import org.moire.ultrasonic.fragment.OnBackPressedHandler import org.moire.ultrasonic.model.ServerSettingsModel import org.moire.ultrasonic.provider.SearchSuggestionProvider import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport @@ -126,6 +126,8 @@ class NavigationActivity : AppCompatActivity() { navigationView = findViewById(R.id.nav_view) drawerLayout = findViewById(R.id.drawer_layout) + setupDrawerLayout(drawerLayout!!) + val toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) @@ -212,6 +214,27 @@ class NavigationActivity : AppCompatActivity() { } } + private fun setupDrawerLayout(drawerLayout: DrawerLayout) { + onBackPressedDispatcher.addCallback(this, closeNavigationDrawerOnBack) + drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { + // Nothing + } + + override fun onDrawerOpened(drawerView: View) { + closeNavigationDrawerOnBack.isEnabled = true + } + + override fun onDrawerClosed(drawerView: View) { + closeNavigationDrawerOnBack.isEnabled = false + } + + override fun onDrawerStateChanged(newState: Int) { + // Nothing + } + }) + } + override fun onResume() { Timber.d("onResume called") super.onResume() @@ -328,15 +351,11 @@ class NavigationActivity : AppCompatActivity() { setupActionBarWithNavController(navController, appBarConfig) } - override fun onBackPressed() { - if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true) { - this.drawerLayout?.closeDrawer(GravityCompat.START) - } else { - val currentFragment = host!!.childFragmentManager.fragments.last() - if (currentFragment is OnBackPressedHandler) currentFragment.onBackPressed() - else super.onBackPressed() + private val closeNavigationDrawerOnBack = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + drawerLayout?.closeDrawer(GravityCompat.START) + } } - } override fun onCreateOptionsMenu(menu: Menu): Boolean { val retValue = super.onCreateOptionsMenu(menu) @@ -352,17 +371,12 @@ class NavigationActivity : AppCompatActivity() { super.onOptionsItemSelected(item) } + // TODO: Why is this needed? Shouldn't it just work by default? override fun onSupportNavigateUp(): Boolean { - val currentFragment = host!!.childFragmentManager.fragments.last() - return if (currentFragment is OnBackPressedHandler) { - currentFragment.onBackPressed() - true - } else { - findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration) - } + return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration) } - // TODO Test if this works with external Intents + // TODO: Test if this works with external Intents // android.intent.action.SEARCH and android.media.action.MEDIA_PLAY_FROM_SEARCH calls here override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index 73d3a0ba..b50cfb67 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -7,12 +7,14 @@ package org.moire.ultrasonic.fragment +import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.ImageView +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment @@ -52,7 +54,7 @@ private const val DIALOG_PADDING = 12 /** * Displays a form where server settings can be created / edited */ -class EditServerFragment : Fragment(), OnBackPressedHandler { +class EditServerFragment : Fragment() { private val serverSettingsModel: ServerSettingsModel by viewModel() private val activeServerProvider: ActiveServerProvider by inject() @@ -82,6 +84,13 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { super.onCreate(savedInstanceState) } + override fun onAttach(context: Context) { + requireActivity().onBackPressedDispatcher.addCallback( + this, confirmCloseCallback + ) + super.onAttach(context) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -189,11 +198,25 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { } } + private val confirmCloseCallback = object : OnBackPressedCallback( + true // default to enabled + ) { + override fun handleOnBackPressed() { + finishActivity() + } + } + override fun onStop() { Util.hideKeyboard(activity) + confirmCloseCallback.isEnabled = false super.onStop() } + override fun onResume() { + confirmCloseCallback.isEnabled = true + super.onResume() + } + private fun correctServerAddress() { serverAddressEditText?.editText?.setText( serverAddressEditText?.editText?.text?.trim(' ', '/') @@ -206,11 +229,6 @@ class EditServerFragment : Fragment(), OnBackPressedHandler { image?.setTint(currentColor) serverColorImageView?.background = image } - - override fun onBackPressed() { - finishActivity() - } - override fun onSaveInstanceState(savedInstanceState: Bundle) { savedInstanceState.putString( ::serverNameEditText.name, serverNameEditText!!.editText?.text.toString() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt deleted file mode 100644 index c34ca2dd..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * OnBackPressedHandler.kt - * Copyright (C) 2009-2022 Ultrasonic developers - * - * Distributed under terms of the GNU GPLv3 license. - */ - -package org.moire.ultrasonic.fragment - -/** - * Interface for fragments handling their own Back button - */ -interface OnBackPressedHandler { - fun onBackPressed() -}