From b3c7b2177c4e31a9e880ab0da5f822f07f38d236 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 2 Apr 2026 18:20:35 +0200 Subject: [PATCH 1/4] Preview: Text selectable For #110 --- .../src/main/res/layout/preview_format_text_fragment.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/opencloudApp/src/main/res/layout/preview_format_text_fragment.xml b/opencloudApp/src/main/res/layout/preview_format_text_fragment.xml index ebb7254f1..842573813 100644 --- a/opencloudApp/src/main/res/layout/preview_format_text_fragment.xml +++ b/opencloudApp/src/main/res/layout/preview_format_text_fragment.xml @@ -26,6 +26,7 @@ android:id="@+id/text_preview" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textIsSelectable="true" android:paddingTop="@dimen/standard_half_margin" android:paddingBottom="@dimen/standard_half_margin" android:layout_marginStart="@dimen/standard_margin" From e04db448bc6169f47a49291eb3e7d1affbd6a4b7 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 6 Apr 2026 09:44:28 +0200 Subject: [PATCH 2/4] Fix detekt issue --- .../eu/opencloud/android/ui/activity/ActivityEdgeToEdgeUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/ActivityEdgeToEdgeUtils.kt b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/ActivityEdgeToEdgeUtils.kt index aba27e209..f71dc6454 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/ActivityEdgeToEdgeUtils.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/ui/activity/ActivityEdgeToEdgeUtils.kt @@ -52,4 +52,4 @@ fun View.updatePaddingTop(@Px paddingTop: Int) { fun View.updatePaddingBottom(@Px paddingBottom: Int) { updatePadding(bottom = paddingBottom) -} \ No newline at end of file +} From d39d25e9716cd37b4e4bc60783a62b1b73047f10 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 6 Apr 2026 11:37:08 +0200 Subject: [PATCH 3/4] Login: Work around Chrome not clearing cookies --- .../android/presentation/authentication/LoginActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 9b1d4cb9d..ea440310d 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 @@ -720,7 +720,8 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted clientId = clientId, responseType = ResponseType.CODE.string, scope = scope, - prompt = if (oidcSupported) mdmProvider.getBrandingString(CONFIGURATION_OAUTH2_OPEN_ID_PROMPT, R.string.oauth2_openid_prompt) else "", + prompt = if (!oidcSupported) "" else if (loginAction == ACTION_CREATE) "login" + else mdmProvider.getBrandingString(CONFIGURATION_OAUTH2_OPEN_ID_PROMPT, R.string.oauth2_openid_prompt), codeChallenge = authenticationViewModel.codeChallenge, state = authenticationViewModel.oidcState, username = username, @@ -1117,6 +1118,7 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted private fun saveAuthState() { val prefs = getSharedPreferences("auth_state", android.content.Context.MODE_PRIVATE) prefs.edit().apply { + clear() // Remove stale state from any previous auth flow putString(KEY_CODE_VERIFIER, authenticationViewModel.codeVerifier) putString(KEY_CODE_CHALLENGE, authenticationViewModel.codeChallenge) putString(KEY_OIDC_STATE, authenticationViewModel.oidcState) From 30055076005f0a0dbe7535a36a40a7c5289ff925 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 6 Apr 2026 11:37:39 +0200 Subject: [PATCH 4/4] Fix top crashes from Play Store --- .../thumbnails/ThumbnailsRequester.kt | 32 +++++++++++++------ .../ui/activity/FileDisplayActivity.kt | 4 +++ ...tSpaceWithSpecialsByIdForAccountUseCase.kt | 6 +++- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/opencloudApp/src/main/java/eu/opencloud/android/presentation/thumbnails/ThumbnailsRequester.kt b/opencloudApp/src/main/java/eu/opencloud/android/presentation/thumbnails/ThumbnailsRequester.kt index ea3dde5f6..af4ecc503 100644 --- a/opencloudApp/src/main/java/eu/opencloud/android/presentation/thumbnails/ThumbnailsRequester.kt +++ b/opencloudApp/src/main/java/eu/opencloud/android/presentation/thumbnails/ThumbnailsRequester.kt @@ -148,13 +148,16 @@ object ThumbnailsRequester : KoinComponent { } private fun buildThumbnailImageLoader(account: Account): ImageLoader { - val openCloudClient = clientManager.getClientForCoilThumbnails(account.name) val interceptor = CoilRequestHeaderInterceptor(clientManager, account.name) return ImageLoader(appContext).newBuilder() - .okHttpClient( - openCloudClient.okHttpClient.newBuilder() + .okHttpClient { + // Lazy: deferred to first image request (off main thread). + // getClientForCoilThumbnails calls blockingGetAuthToken which + // must not run on the main thread. + clientManager.getClientForCoilThumbnails(account.name) + .okHttpClient.newBuilder() .addInterceptor(interceptor).build() - ) + } .apply { if (preferencesProvider.getBoolean("enable_logging", false)) logger(DebugLogger()) } .memoryCache { sharedMemoryCache } .diskCache { sharedDiskCache } @@ -163,15 +166,15 @@ object ThumbnailsRequester : KoinComponent { } private fun buildAvatarImageLoader(account: Account): ImageLoader { - val openCloudClient = clientManager.getClientForCoilThumbnails(account.name) val interceptor = CoilRequestHeaderInterceptor(clientManager, account.name) return ImageLoader(appContext).newBuilder() - .okHttpClient( - openCloudClient.okHttpClient.newBuilder() + .okHttpClient { + clientManager.getClientForCoilThumbnails(account.name) + .okHttpClient.newBuilder() .addInterceptor(interceptor) .cache(avatarHttpCache) .build() - ) + } .apply { if (preferencesProvider.getBoolean("enable_logging", false)) logger(DebugLogger()) } .memoryCache { sharedMemoryCache } // No Coil disk cache — OkHttp's HTTP cache handles persistence @@ -187,7 +190,18 @@ object ThumbnailsRequester : KoinComponent { ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { - val openCloudClient = clientManager.getClientForCoilThumbnails(accountName) + val openCloudClient = try { + clientManager.getClientForCoilThumbnails(accountName) + } catch (e: Exception) { + Timber.d(e, "Account $accountName not found, skipping thumbnail request") + return Response.Builder() + .request(chain.request()) + .protocol(okhttp3.Protocol.HTTP_1_1) + .code(401) + .message("Account not found") + .body(okhttp3.ResponseBody.create(null, "")) + .build() + } val credentials = openCloudClient.credentials ?: return Response.Builder() .request(chain.request()) 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 d65e14e34..9013ac538 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 @@ -1775,6 +1775,10 @@ class FileDisplayActivity : FileActivity(), } private fun navigateTo(newFileListOption: FileListOption, initialState: Boolean = false) { + // account can be null if it was removed while the activity was still visible. + // swapToDefaultAccount (called from onRestart/onNewIntent) launches the login + // wizard asynchronously, but we can't navigate without an account. + if (account == null) return val previousFileListOption = fileListOption when (newFileListOption) { FileListOption.ALL_FILES -> { diff --git a/opencloudDomain/src/main/java/eu/opencloud/android/domain/spaces/usecases/GetSpaceWithSpecialsByIdForAccountUseCase.kt b/opencloudDomain/src/main/java/eu/opencloud/android/domain/spaces/usecases/GetSpaceWithSpecialsByIdForAccountUseCase.kt index 587bcdf7d..00ef61302 100644 --- a/opencloudDomain/src/main/java/eu/opencloud/android/domain/spaces/usecases/GetSpaceWithSpecialsByIdForAccountUseCase.kt +++ b/opencloudDomain/src/main/java/eu/opencloud/android/domain/spaces/usecases/GetSpaceWithSpecialsByIdForAccountUseCase.kt @@ -30,7 +30,11 @@ class GetSpaceWithSpecialsByIdForAccountUseCase( override fun run(params: Params): OCSpace? { if (params.spaceId == null) return null - return spacesRepository.getSpaceWithSpecialsByIdForAccount(params.spaceId, params.accountName) + return try { + spacesRepository.getSpaceWithSpecialsByIdForAccount(params.spaceId, params.accountName) + } catch (_: Exception) { + null + } } data class Params(