From 0e08b97e791d7f9a4e285ddfd80a4b47d4544312 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 11 Aug 2026 17:00:50 +0200 Subject: [PATCH] Snackbar: Longer duration for errors For https://github.com/opencloud-eu/android/issues/100 and more --- .../opencloud/android/extensions/ActivityExt.kt | 7 ++++++- .../opencloud/android/extensions/FragmentExt.kt | 2 +- .../presentation/authentication/LoginActivity.kt | 8 ++++++-- .../files/details/FileDetailsFragment.kt | 5 +++-- .../files/filelist/MainFileListFragment.kt | 3 ++- .../privacypolicy/PrivacyPolicyActivity.kt | 6 +++++- .../android/ui/activity/FileDisplayActivity.kt | 16 +++++++++++----- 7 files changed, 34 insertions(+), 13 deletions(-) diff --git a/opencloudApp/src/main/java/eu/opencloud/android/extensions/ActivityExt.kt b/opencloudApp/src/main/java/eu/opencloud/android/extensions/ActivityExt.kt index baac7a3f2f..2c9a6171bf 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/extensions/ActivityExt.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/extensions/ActivityExt.kt @@ -75,10 +75,15 @@ import org.koin.android.ext.android.inject import timber.log.Timber import java.io.File +// Error snackbars need longer than the default LENGTH_LONG (2.75s) so the user can read a failure +// and react (retry, reconnect). Passed as a raw millisecond value, which Snackbar.make accepts. +const val SNACKBAR_DURATION_ERROR_MS = 7000 + fun Activity.showErrorInSnackbar(genericErrorMessageId: Int, throwable: Throwable?) = throwable?.let { showMessageInSnackbar( - message = it.parseError(getString(genericErrorMessageId), resources) + message = it.parseError(getString(genericErrorMessageId), resources), + duration = SNACKBAR_DURATION_ERROR_MS ) } diff --git a/opencloudApp/src/main/java/eu/opencloud/android/extensions/FragmentExt.kt b/opencloudApp/src/main/java/eu/opencloud/android/extensions/FragmentExt.kt index 1fc32b4828..17d9ebf969 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/extensions/FragmentExt.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/extensions/FragmentExt.kt @@ -40,7 +40,7 @@ import kotlinx.coroutines.launch fun Fragment.showErrorInSnackbar(genericErrorMessageId: Int, throwable: Throwable?) = throwable?.let { - showMessageInSnackbar(it.parseError(getString(genericErrorMessageId), resources)) + showMessageInSnackbar(it.parseError(getString(genericErrorMessageId), resources), SNACKBAR_DURATION_ERROR_MS) } fun Fragment.showMessageInSnackbar( diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/LoginActivity.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/LoginActivity.kt index 1569a098e1..0d28c2b19d 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/LoginActivity.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/LoginActivity.kt @@ -72,6 +72,7 @@ import eu.opencloud.android.extensions.goToUrl import eu.opencloud.android.extensions.manageOptionLockSelected import eu.opencloud.android.extensions.parseError import eu.opencloud.android.extensions.showErrorInToast +import eu.opencloud.android.extensions.SNACKBAR_DURATION_ERROR_MS import eu.opencloud.android.extensions.showMessageInSnackbar import eu.opencloud.android.lib.common.accounts.AccountTypeUtils import eu.opencloud.android.lib.common.accounts.AccountUtils @@ -331,7 +332,10 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted if (getAccounts(baseContext).isNotEmpty()) { launchFileDisplayActivity() } else { - showMessageInSnackbar(message = baseContext.getString(R.string.uploader_wrn_no_account_title)) + showMessageInSnackbar( + message = baseContext.getString(R.string.uploader_wrn_no_account_title), + duration = SNACKBAR_DURATION_ERROR_MS + ) } } } @@ -806,7 +810,7 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted if (state != authenticationViewModel.oidcState) { Timber.e("OAuth: state mismatch (expected=${authenticationViewModel.oidcState}, got=$state). Finishing.") - showMessageInSnackbar(message = getString(R.string.auth_oauth_error)) + showMessageInSnackbar(message = getString(R.string.auth_oauth_error), duration = SNACKBAR_DURATION_ERROR_MS) finish() } else { if (authorizationCode != null) { diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/details/FileDetailsFragment.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/details/FileDetailsFragment.kt index 85c7fd91f9..8e17069faf 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/details/FileDetailsFragment.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/details/FileDetailsFragment.kt @@ -56,6 +56,7 @@ import eu.opencloud.android.extensions.filterMenuOptions import eu.opencloud.android.extensions.isDownload import eu.opencloud.android.extensions.openOCFile import eu.opencloud.android.extensions.sendDownloadedFilesByShareSheet +import eu.opencloud.android.extensions.SNACKBAR_DURATION_ERROR_MS import eu.opencloud.android.extensions.showErrorInSnackbar import eu.opencloud.android.extensions.showMessageInSnackbar import eu.opencloud.android.presentation.authentication.ACTION_UPDATE_EXPIRED_TOKEN @@ -203,7 +204,7 @@ class FileDetailsFragment : FileFragment() { } SynchronizeFileUseCase.SyncType.FileNotFound -> { - showMessageInSnackbar(getString(R.string.sync_file_not_found_msg)) + showMessageInSnackbar(getString(R.string.sync_file_not_found_msg), SNACKBAR_DURATION_ERROR_MS) } is SynchronizeFileUseCase.SyncType.UploadEnqueued -> { @@ -211,7 +212,7 @@ class FileDetailsFragment : FileFragment() { } null -> { - showMessageInSnackbar(getString(R.string.common_error_unknown)) + showMessageInSnackbar(getString(R.string.common_error_unknown), SNACKBAR_DURATION_ERROR_MS) } } } diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt index a7ed1e9bd7..41d7a25d7d 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/MainFileListFragment.kt @@ -85,6 +85,7 @@ import eu.opencloud.android.extensions.collectLatestLifecycleFlow import eu.opencloud.android.extensions.filterMenuOptions import eu.opencloud.android.extensions.parseError import eu.opencloud.android.extensions.sendDownloadedFilesByShareSheet +import eu.opencloud.android.extensions.SNACKBAR_DURATION_ERROR_MS import eu.opencloud.android.extensions.showErrorInSnackbar import eu.opencloud.android.extensions.showMessageInSnackbar import eu.opencloud.android.extensions.toDrawableRes @@ -865,7 +866,7 @@ class MainFileListFragment : Fragment(), is UIResult.Error -> { fileActivity.dismissLoadingDialog() - showMessageInSnackbar(resources.getString(R.string.common_error_unknown)) + showMessageInSnackbar(resources.getString(R.string.common_error_unknown), SNACKBAR_DURATION_ERROR_MS) } } } diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/settings/privacypolicy/PrivacyPolicyActivity.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/settings/privacypolicy/PrivacyPolicyActivity.kt index eaabc45a31..e35d21546c 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/settings/privacypolicy/PrivacyPolicyActivity.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/settings/privacypolicy/PrivacyPolicyActivity.kt @@ -37,6 +37,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import androidx.core.view.updatePadding import eu.opencloud.android.R +import eu.opencloud.android.extensions.SNACKBAR_DURATION_ERROR_MS import eu.opencloud.android.extensions.showMessageInSnackbar import eu.opencloud.android.ui.activity.enableEdgeToEdgePostSetContentView import eu.opencloud.android.ui.activity.enableEdgeToEdgePreSetContentView @@ -97,7 +98,10 @@ class PrivacyPolicyActivity : AppCompatActivity() { webViewClient = object : WebViewClient() { override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) { - showMessageInSnackbar(message = getString(R.string.privacy_policy_error) + description) + showMessageInSnackbar( + message = getString(R.string.privacy_policy_error) + description, + duration = SNACKBAR_DURATION_ERROR_MS + ) } override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { diff --git a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt index 9013ac5382..a4c9c95f16 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/FileDisplayActivity.kt @@ -85,6 +85,7 @@ import eu.opencloud.android.extensions.observeWorkerTillItFinishes import eu.opencloud.android.extensions.openOCFile import eu.opencloud.android.extensions.parseError import eu.opencloud.android.extensions.sendDownloadedFilesByShareSheet +import eu.opencloud.android.extensions.SNACKBAR_DURATION_ERROR_MS import eu.opencloud.android.extensions.showErrorInSnackbar import eu.opencloud.android.extensions.showMessageInSnackbar import eu.opencloud.android.lib.common.accounts.AccountUtils @@ -930,7 +931,7 @@ class FileDisplayActivity : FileActivity(), if (synchResult.httpPhrase == "Error: Call to a member function getUID() on null") { showRequestAccountChangeNotice(getString(R.string.auth_failure_snackbar), false) } else { - showMessageInSnackbar(R.id.list_layout, synchResult.httpPhrase) + showMessageInSnackbar(R.id.list_layout, synchResult.httpPhrase, SNACKBAR_DURATION_ERROR_MS) } } else { showRequestAccountChangeNotice(getString(R.string.auth_failure_snackbar), false) @@ -1430,7 +1431,7 @@ class FileDisplayActivity : FileActivity(), } else -> { - showMessageInSnackbar(R.id.list_layout, getString(R.string.sync_fail_ticker)) + showMessageInSnackbar(R.id.list_layout, getString(R.string.sync_fail_ticker), SNACKBAR_DURATION_ERROR_MS) } } } @@ -1538,7 +1539,7 @@ class FileDisplayActivity : FileActivity(), } else -> { - showMessageInSnackbar(R.id.list_layout, getString(R.string.sync_fail_ticker)) + showMessageInSnackbar(R.id.list_layout, getString(R.string.sync_fail_ticker), SNACKBAR_DURATION_ERROR_MS) } } } @@ -1982,7 +1983,11 @@ class FileDisplayActivity : FileActivity(), is UIResult.Error -> { dismissLoadingDialog() if (uiResult.error is FileNotFoundException) { - showMessageInSnackbar(R.id.list_layout, message = getString(R.string.deep_link_user_no_access)) + showMessageInSnackbar( + R.id.list_layout, + message = getString(R.string.deep_link_user_no_access), + duration = SNACKBAR_DURATION_ERROR_MS + ) changeUser() } else { showMessageInSnackbar( @@ -1993,7 +1998,8 @@ class FileDisplayActivity : FileActivity(), } else { R.string.default_error_msg } - ) + ), + duration = SNACKBAR_DURATION_ERROR_MS ) } }