fix: replace modal restart dialog with inline banner#711
Conversation
The ServiceRestartDialog was duplicated in SettingsScreen and IdentityScreen as a blocking modal with a cancel button that only appeared after 15s — the same duration as the init timeout, making it useless. DiscoveredInterfacesScreen already had a better inline banner pattern. - Extract shared ServiceRestartBanner composable from the inline pattern in DiscoveredInterfacesScreen - Replace modal dialogs in SettingsScreen and IdentityScreen with the inline banner - Add onServiceReady callback to applyInterfaceChanges() so ViewModels clear isRestarting after Reticulum init (Step 9) rather than waiting for post-init bookkeeping (Steps 10-12) - All 3 screens now use consistent non-blocking restart UX Closes #694 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR replaces the blocking Key changes:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant VM as ViewModel
participant ICM as InterfaceConfigManager
participant UI as Screen (Banner)
VM->>UI: isRestarting = true → banner appears
VM->>ICM: applyInterfaceChanges(onServiceReady)
ICM-->>ICM: Steps 1–8 (shutdown, restart, bind…)
ICM-->>ICM: Step 9: Reticulum init ✓
ICM-->>VM: onServiceReady() callback
VM->>UI: isRestarting = false → banner disappears
ICM-->>ICM: Steps 10–12 (identity restore, manager restart)
ICM-->>VM: Result.success(Unit)
note over VM,ICM: On early failure (Steps 1–9 fail)
ICM-->>VM: Result.failure (no throw) [SettingsVM/.getOrThrow() re-throws → catch resets flag ✓]
note over VM: DebugViewModel: result discarded,<br/>catch never fires → isRestarting stuck true ✗
Prompt To Fix All With AIThis is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/viewmodel/DebugViewModel.kt
Line: 581-587
Comment:
**`isRestarting` stuck `true` on early-failure path**
`applyInterfaceChanges` wraps all failures in `runCatching` and returns `Result.failure` — it never throws. This means the outer `catch` block on line 585 only fires for exceptions raised by other code in the `try` block (practically nothing), not for a failed restart.
- **Happy path**: Step 9 succeeds → `onServiceReady` fires → `_isRestarting.value = false` ✓
- **Late failure** (Step 10–12 fail): `onServiceReady` already fired → `_isRestarting` already `false` ✓
- **Early failure** (Steps 1–9 fail, e.g. timeout, service shutdown error): `onServiceReady` is **never invoked**, `applyInterfaceChanges` returns `Result.failure` silently, `catch` block never runs → `_isRestarting` stays `true` forever ✗
In contrast, `SettingsViewModel.restartService()` avoids this by calling `.getOrThrow()` which re-throws the failure, allowing its `catch` block to reset the flag.
Fix: either ignore-and-reset, or mirror the `SettingsViewModel` pattern:
```suggestion
interfaceConfigManager.applyInterfaceChanges(
onServiceReady = { _isRestarting.value = false },
).also { result ->
if (result.isFailure) _isRestarting.value = false
}
Log.i(TAG, "Service restart completed successfully")
} catch (e: Exception) {
Log.e(TAG, "Error restarting service", e)
_isRestarting.value = false
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (3): Last reviewed commit: "fix: update test to match unicode ellips..." | Re-trigger Greptile |
app/src/main/java/com/lxmf/messenger/ui/screens/IdentityScreen.kt
Outdated
Show resolved
Hide resolved
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
No UI callers remain after replacing the modal dialog with the inline banner. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matches the pattern used by OfflineModeBanner. Uses \u2026 ellipsis consistent with offline_banner_reconnecting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The string resource uses \u2026 (…) instead of three dots (...). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
ServiceRestartBannercomposable from the inline pattern already used inDiscoveredInterfacesScreenServiceRestartDialoginSettingsScreenandIdentityScreenwith the non-modal inline banneronServiceReadycallback toInterfaceConfigManager.applyInterfaceChanges()so ViewModels clearisRestartingafter Reticulum init (Step 9) rather than waiting for post-init bookkeeping (Steps 10-12: identity restore, manager restart)The old modal dialog had a cancel button that was hidden for 15 seconds via
delay(15_000)— the same duration as the init timeout — so it only appeared when the operation had already succeeded or failed. The inline banner lets users continue interacting with the screen while the service restarts.Test plan
InterfaceConfigManagerTesttests pass (17/17)SettingsViewModelTest,DebugViewModelEventDrivenTest,DiscoveredInterfacesViewModelTestpassCloses #694
🤖 Generated with Claude Code