ui: migrate to OnBackPressedDispatcher
This is compatible with Android 13's prediction-based back gesture animation. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
b7295cd56f
commit
cf943b7119
@ -35,6 +35,7 @@
|
|||||||
android:name=".Application"
|
android:name=".Application"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:banner="@mipmap/banner"
|
android:banner="@mipmap/banner"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
@ -9,6 +9,8 @@ import android.os.Bundle
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.addCallback
|
||||||
import androidx.appcompat.app.ActionBar
|
import androidx.appcompat.app.ActionBar
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
@ -26,27 +28,29 @@ import com.wireguard.android.model.ObservableTunnel
|
|||||||
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
|
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
|
||||||
private var actionBar: ActionBar? = null
|
private var actionBar: ActionBar? = null
|
||||||
private var isTwoPaneLayout = false
|
private var isTwoPaneLayout = false
|
||||||
|
private var backPressedCallback: OnBackPressedCallback? = null
|
||||||
|
|
||||||
override fun onBackPressed() {
|
private fun handleBackPressed() {
|
||||||
val backStackEntries = supportFragmentManager.backStackEntryCount
|
val backStackEntries = supportFragmentManager.backStackEntryCount
|
||||||
// If the two-pane layout does not have an editor open, going back should exit the app.
|
// If the two-pane layout does not have an editor open, going back should exit the app.
|
||||||
if (isTwoPaneLayout && backStackEntries <= 1) {
|
if (isTwoPaneLayout && backStackEntries <= 1) {
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
|
|
||||||
if (!isTwoPaneLayout && backStackEntries == 1) {
|
if (backStackEntries >= 1)
|
||||||
supportFragmentManager.popBackStack()
|
supportFragmentManager.popBackStack()
|
||||||
|
|
||||||
|
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
|
||||||
|
if (backStackEntries == 1)
|
||||||
selectedTunnel = null
|
selectedTunnel = null
|
||||||
return
|
|
||||||
}
|
|
||||||
super.onBackPressed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackStackChanged() {
|
override fun onBackStackChanged() {
|
||||||
|
val backStackEntries = supportFragmentManager.backStackEntryCount
|
||||||
|
backPressedCallback?.isEnabled = backStackEntries >= 1
|
||||||
if (actionBar == null) return
|
if (actionBar == null) return
|
||||||
// Do not show the home menu when the two-pane layout is at the detail view (see above).
|
// Do not show the home menu when the two-pane layout is at the detail view (see above).
|
||||||
val backStackEntries = supportFragmentManager.backStackEntryCount
|
|
||||||
val minBackStackEntries = if (isTwoPaneLayout) 2 else 1
|
val minBackStackEntries = if (isTwoPaneLayout) 2 else 1
|
||||||
actionBar!!.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries)
|
actionBar!!.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries)
|
||||||
}
|
}
|
||||||
@ -57,6 +61,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
|||||||
actionBar = supportActionBar
|
actionBar = supportActionBar
|
||||||
isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null
|
isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null
|
||||||
supportFragmentManager.addOnBackStackChangedListener(this)
|
supportFragmentManager.addOnBackStackChangedListener(this)
|
||||||
|
backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() }
|
||||||
onBackStackChanged()
|
onBackStackChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +74,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
|||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
// The back arrow in the action bar should act the same as the back button.
|
// The back arrow in the action bar should act the same as the back button.
|
||||||
onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.menu_action_edit -> {
|
R.id.menu_action_edit -> {
|
||||||
|
@ -16,12 +16,14 @@ import android.os.storage.StorageVolume
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.addCallback
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.databinding.Observable
|
||||||
import androidx.databinding.ObservableBoolean
|
import androidx.databinding.ObservableBoolean
|
||||||
import androidx.databinding.ObservableField
|
import androidx.databinding.ObservableField
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@ -185,6 +187,17 @@ class TvMainActivity : AppCompatActivity() {
|
|||||||
binding.tunnelList.requestFocus()
|
binding.tunnelList.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() }
|
||||||
|
val updateBackPressedCallback = object : Observable.OnPropertyChangedCallback() {
|
||||||
|
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
|
||||||
|
backPressedCallback.isEnabled = isDeleting.get() || filesRoot.get()?.isNotEmpty() == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isDeleting.addOnPropertyChangedCallback(updateBackPressedCallback)
|
||||||
|
filesRoot.addOnPropertyChangedCallback(updateBackPressedCallback)
|
||||||
|
backPressedCallback.isEnabled = false
|
||||||
|
|
||||||
binding.executePendingBindings()
|
binding.executePendingBindings()
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
@ -298,7 +311,7 @@ class TvMainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
private fun handleBackPressed() {
|
||||||
when {
|
when {
|
||||||
isDeleting.get() -> {
|
isDeleting.get() -> {
|
||||||
isDeleting.set(false)
|
isDeleting.set(false)
|
||||||
@ -313,7 +326,6 @@ class TvMainActivity : AppCompatActivity() {
|
|||||||
binding.tunnelList.requestFocus()
|
binding.tunnelList.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> super.onBackPressed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user