From 3188fc472af5c93e1eaf331472757156edfca59a Mon Sep 17 00:00:00 2001 From: Wally Hackenslacker Date: Wed, 18 Mar 2026 09:30:45 -0400 Subject: [PATCH] fix: refresh drawer after failed load and use rtl-safe drawer close --- .../kanbn4droid/app/BoardsActivity.kt | 3 +-- .../kanbn4droid/app/boards/BoardsViewModel.kt | 12 +++++++++- .../app/boards/BoardsViewModelTest.kt | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/space/hackenslacker/kanbn4droid/app/BoardsActivity.kt b/app/src/main/java/space/hackenslacker/kanbn4droid/app/BoardsActivity.kt index 3e9eed7..8f1d0db 100644 --- a/app/src/main/java/space/hackenslacker/kanbn4droid/app/BoardsActivity.kt +++ b/app/src/main/java/space/hackenslacker/kanbn4droid/app/BoardsActivity.kt @@ -2,7 +2,6 @@ package space.hackenslacker.kanbn4droid.app import android.content.Intent import android.os.Bundle -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.widget.ArrayAdapter @@ -249,7 +248,7 @@ class BoardsActivity : AppCompatActivity() { selectedWorkspace == state.drawer.activeWorkspaceId && state.drawer.errorCode == DrawerDataErrorCode.NONE ) { - drawerLayout.closeDrawer(Gravity.START) + drawerLayout.closeDrawer(GravityCompat.START) } pendingWorkspaceSelectionId = null } diff --git a/app/src/main/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModel.kt b/app/src/main/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModel.kt index 8e6d9c4..d8a82ae 100644 --- a/app/src/main/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModel.kt +++ b/app/src/main/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModel.kt @@ -39,6 +39,7 @@ class BoardsViewModel( val events: SharedFlow = _events.asSharedFlow() private var lastDrawerLoadAtMillis: Long? = null + private var hadDrawerLoadFailureSinceLastSuccess: Boolean = false fun loadBoards() { fetchBoards(initial = true) @@ -49,6 +50,10 @@ class BoardsViewModel( } fun loadDrawerDataIfStale() { + if (hadDrawerLoadFailureSinceLastSuccess) { + fetchDrawerData() + return + } val now = nowProvider() val isStale = lastDrawerLoadAtMillis?.let { now - it >= DRAWER_STALE_MS } ?: true if (!isStale) { @@ -258,7 +263,12 @@ class BoardsViewModel( ) } - lastDrawerLoadAtMillis = nowProvider() + if (result.errorCode == DrawerDataErrorCode.NONE) { + lastDrawerLoadAtMillis = nowProvider() + hadDrawerLoadFailureSinceLastSuccess = false + } else { + hadDrawerLoadFailureSinceLastSuccess = true + } if (result.errorCode == DrawerDataErrorCode.UNAUTHORIZED) { _events.emit(BoardsUiEvent.ForceSignOut) diff --git a/app/src/test/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModelTest.kt b/app/src/test/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModelTest.kt index 429a05a..fbdd9f6 100644 --- a/app/src/test/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModelTest.kt +++ b/app/src/test/java/space/hackenslacker/kanbn4droid/app/boards/BoardsViewModelTest.kt @@ -302,6 +302,30 @@ class BoardsViewModelTest { assertEquals(2, api.getCurrentUserCalls) } + @Test + fun loadDrawerDataIfStaleRefetchesImmediatelyAfterFailedLoad() = runTest { + val api = FakeBoardsApiClient().apply { + usersMeResults.addLast(BoardsApiResult.Failure("Cannot reach server. Check your connection and URL.")) + usersMeResults.addLast(BoardsApiResult.Success(DrawerProfile(displayName = "Alice", email = null))) + workspacesResults.addLast(BoardsApiResult.Failure("Cannot reach server. Check your connection and URL.")) + workspacesResults.addLast(BoardsApiResult.Success(listOf(WorkspaceSummary("ws-1", "Main")))) + } + val viewModel = newViewModel(apiClient = api, nowProvider = { 1_000L }) + + viewModel.loadDrawerData() + advanceUntilIdle() + assertEquals(DrawerDataErrorCode.NETWORK, viewModel.uiState.value.drawer.errorCode) + assertEquals(1, api.listWorkspacesCalls) + assertEquals(1, api.getCurrentUserCalls) + + viewModel.loadDrawerDataIfStale() + advanceUntilIdle() + + assertEquals(DrawerDataErrorCode.NONE, viewModel.uiState.value.drawer.errorCode) + assertEquals(2, api.listWorkspacesCalls) + assertEquals(2, api.getCurrentUserCalls) + } + @Test fun loadDrawerDataFallbackWorkspacePersistsFirstAndTriggersBoardsRefresh() = runTest { val api = FakeBoardsApiClient().apply {