From f78d43fa2a1ac5a337a54a0e10020f21c06aefd3 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 16 Sep 2026 15:21:21 +0200 Subject: [PATCH] Fix cloud nodes folders up This fixes #651 and was introduces with targetSdk 36 and the predictive back handling --- .../presentation/ui/activity/BaseActivity.kt | 13 ++++++ .../ui/activity/BrowseFilesActivity.kt | 44 +++++++++++-------- .../ui/activity/TextEditorActivity.kt | 20 ++++++--- .../ui/activity/WelcomeActivity.kt | 12 ++++- 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BaseActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BaseActivity.kt index 0b45840e57..2a580c3327 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BaseActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BaseActivity.kt @@ -11,6 +11,7 @@ import android.view.Menu import android.view.MenuItem import android.view.WindowManager import android.widget.Toast +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.fragment.app.DialogFragment @@ -225,6 +226,18 @@ abstract class BaseActivity(val bindingFactory: (LayoutInflate transaction.commit() } + /** + * Hands the back event over to the system (which finishes this activity) while the given [callback] is disabled, + * so that the callback does not handle its own dispatch. + * + * @param callback The activity's back callback that decided not to handle the event itself. + */ + internal fun performDefaultBackPressed(callback: OnBackPressedCallback) { + callback.isEnabled = false + onBackPressedDispatcher.onBackPressed() + callback.isEnabled = true + } + override fun getComponent(): ActivityComponent? = activityComponent override fun activity(): android.app.Activity = this diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BrowseFilesActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BrowseFilesActivity.kt index 010f888785..045069123c 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BrowseFilesActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/BrowseFilesActivity.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.content.IntentFilter import android.view.Menu import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -86,6 +87,7 @@ class BrowseFilesActivity : BaseActivity(ActivityLayoutBi override fun setupView() { setupToolbar() setupNavigationMode() + setupBackPressedCallback() } private fun setupNavigationMode() { @@ -130,26 +132,32 @@ class BrowseFilesActivity : BaseActivity(ActivityLayoutBi }.also { LocalBroadcastManager.getInstance(this).registerReceiver(it, IntentFilter(CryptorsService.SCREEN_AND_VAULT_LOCKED)) } } - override fun onBackPressed() { - browseFilesPresenter.onBackPressed() - when { - isNavigationMode(SELECT_ITEMS) -> { - browseFilesPresenter.disableSelectionMode() - } - supportFragmentManager.backStackEntryCount > 0 -> { - supportFragmentManager.popBackStack() - } - hasCloudNodeSettings() && isNavigationMode(MOVE_CLOUD_NODE) && browseFilesFragment().folder.hasParent() -> { - browseFilesFragment().folder.parent?.let { - createBackStackFor(it) - } ?: throw ParentFolderIsNullException(browseFilesFragment().folder.name) - } - else -> { - super.onBackPressed() + private val backPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + browseFilesPresenter.onBackPressed() + when { + isNavigationMode(SELECT_ITEMS) -> { + browseFilesPresenter.disableSelectionMode() + } + supportFragmentManager.backStackEntryCount > 0 -> { + supportFragmentManager.popBackStack() + } + hasCloudNodeSettings() && isNavigationMode(MOVE_CLOUD_NODE) && browseFilesFragment().folder.hasParent() -> { + browseFilesFragment().folder.parent?.let { + createBackStackFor(it) + } ?: throw ParentFolderIsNullException(browseFilesFragment().folder.name) + } + else -> { + performDefaultBackPressed(this) + } } } } + private fun setupBackPressedCallback() { + onBackPressedDispatcher.addCallback(this, backPressedCallback) + } + private fun isNavigationMode(navigationMode: ChooseCloudNodeSettings.NavigationMode): Boolean = this.navigationMode == navigationMode private fun hasCloudNodeSettings(): Boolean = @@ -630,10 +638,10 @@ class BrowseFilesActivity : BaseActivity(ActivityLayoutBi } override fun navigateFolderBackBecauseSymlink() { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } override fun navigateFolderBackBecauseNoDirFile() { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/TextEditorActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/TextEditorActivity.kt index 10166e5104..be686a8ae4 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/TextEditorActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/TextEditorActivity.kt @@ -2,6 +2,7 @@ package org.cryptomator.presentation.ui.activity import android.view.Menu import android.view.MenuItem +import androidx.activity.OnBackPressedCallback import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import org.cryptomator.generator.Activity @@ -41,16 +42,23 @@ class TextEditorActivity : BaseActivity(ActivityLayoutBin override fun setupView() { textEditorPresenter.setTextFile(textEditorIntent.textFile()) setupToolbar() + setupBackPressedCallback() } override fun createFragment(): Fragment = TextEditorFragment() - override fun onBackPressed() { - if (!hasWriteAccess()) { - super.onBackPressed() - return + private val backPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (!hasWriteAccess()) { + performBackPressed() + return + } + textEditorPresenter.onBackPressed() } - textEditorPresenter.onBackPressed() + } + + private fun setupBackPressedCallback() { + onBackPressedDispatcher.addCallback(this, backPressedCallback) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -120,7 +128,7 @@ class TextEditorActivity : BaseActivity(ActivityLayoutBin } override fun performBackPressed() { - super.onBackPressed() + performDefaultBackPressed(backPressedCallback) } override fun showUnsavedChangesDialog() { diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/WelcomeActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/WelcomeActivity.kt index 22ac7e9e09..80165b77ca 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/WelcomeActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/WelcomeActivity.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat @@ -100,6 +101,7 @@ class WelcomeActivity : BaseActivity(ActivityWelcomeBind setupPages() setupPager() + setupBackPressedCallback() validate(intent) updateNotificationPermissionState() @@ -123,8 +125,14 @@ class WelcomeActivity : BaseActivity(ActivityWelcomeBind orchestrator.onPause() } - override fun onBackPressed() { - goBackOrExit() + private val backPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + goBackOrExit() + } + } + + private fun setupBackPressedCallback() { + onBackPressedDispatcher.addCallback(this, backPressedCallback) } private fun setupPages() {