* fix(#688): route expired auth sessions to sign-in
Adopt global 401 latch, WS disconnect, and Back/profile guards.
* chore: clean up formatting noise
* fix(ktlint): reorder imports to place java and kotlinx at end
* fix(ktlint): place java.io.IOException at end of imports
* test: fix NavBackStack type parameter in AuthenticationRoutingTest
* test: add AuthSessionState tests to AuthLoginViewModelTest
* fix(ktlint): fix import order in AuthLoginViewModelTest
* perf(model): optimize model tab load speed with two-phase fetch and loadQuick
* perf: optimize data loading across Config, System, Profiles, and Billing tabs
* chore: remove leftover bottom nav references and unused updatePrimaryScreens
* style: fix ktlint violations in Config/Profiles/Billing ViewModels
- property/argument-list wrapping for async(...) calls
- multiline-expression wrapping for async blocks
- remove unused import in ConfigViewModel
- break long error-message string literals to stay under 120 cols
---------
Co-authored-by: M57 <Hy4ri@users.noreply.github.com>
Replaces the fragile DRAWER_GESTURE_SCREENS global set + defensive
LaunchedEffect(snapTo(Closed)) + closeDrawer callback workaround with a
single source of truth: each screen declares its drawer-gesture preference
via HermesScaffold's new drawerGesturesEnabled parameter (default true).
Architecture:
- DrawerGestureController holds the active gesture state. HermesScaffold
reconciles each screen's preference into it via SideEffect; when a screen
opts out while the drawer is open, the controller closes the drawer itself.
- LocalDrawerGestureController CompositionLocal flows the controller from
MainNavigation down to ModalNavigationDrawer, which reads .enabled and
passes it to Material's gesturesEnabled parameter.
- DisableDrawerGestures() helper for entry screens that don't use
HermesScaffold (Landing, AuthLogin, PairingCodeEntry).
- All 6 Settings drill-down sub-pages pass drawerGesturesEnabled = false.
- NavigationController.closeDrawer removed; navigateTo no longer needs a
synchronous drawer-dismiss hook.
Removes: DRAWER_GESTURE_SCREENS set, both LaunchedEffect(gesturesEnabled)
and LaunchedEffect(drawerGesturesEnabled) blocks, drawerGesturesEnabled
local state, closeDrawer callback on NavigationController.
Fixes the recurring drawer-scrim stuck-open bug class (PRs #445, #454, #455).
Verified: ktlintCheck, assembleDebug, testDebugUnitTest all green locally.
Co-authored-by: Hy4ri <hy4ri@users.noreply.github.com>
* refactor(settings): drill-down navigation replacing tabbed layout
Replaces the 4-tab settings layout with a native Android-style drill-down:
a single category list (SettingsScreen) where each row pushes a dedicated
sub-page onto the Navigation3 back stack (SettingsConnection / Appearance /
Chat / NavBar / Behavior / About). Each sub-page is its own NavKey destination
registered in Navigation.kt and reuses the existing section composables.
- SettingsScreen becomes the category list with icon + label + summary
(Appearance row shows live theme + language, e.g. "Dark · 한국어").
- New SettingsSubPages.kt hosts the 6 full-screen sub-pages.
- AboutSection promoted out of SettingsScreen into its own sub-page.
- SettingsViewModel remains the single source of truth; no persistence changes.
- Adds settings_summary_* strings for list subtitles.
Consumes the in-app language switcher from the prior commit (AppearancePage
passes appLanguage through to AppearanceSection).
* [bug] fix settings sub-page back button opening drawer on first tap
The ModalNavigationDrawer wraps the whole app and stays gesture-enabled on
the Settings root (a DRAWER_GESTURE_SCREEN). Drilling into a sub-page
(SettingsConnection/Appearance/Chat/NavBar/Behavior/About) disables gestures,
but the existing LaunchedEffect only snapped the drawer closed when it was
already isOpen. The drawer's scrim surface lingered during the transition and
intercepted the first back-button tap, sliding the sidebar open instead of
navigating back.
Now snapTo(Closed) unconditionally whenever gestures are disabled — a safe
no-op when already closed — so the sub-page back button works on the first tap.
* [bug] fix settings sub-page back button opening drawer (gesture-surface race)
The first "back" tap on a settings sub-page opened the sidebar instead of
navigating back. Root cause: Settings root is a gesture-enabled drawer screen,
and the sub-pages are the first destinations ever drilled down from it. When
navigating in, ModalNavigationDrawer's gesture interceptor surface lingered
for a frame (gesture -> non-gesture transition), so the top-left tap was
consumed by the drawer instead of the Back IconButton. The previous snapTo
fix only reset drawer *state*, not the gesture layer, so it didn't help.
Fix: NavigationController now holds a closeDrawer hook (set by MainNavigation)
and invokes it synchronously inside navigateTo() when pushing a non-primary
sub-page. The drawer is dismissed in the same tap handler that triggers the
navigation, before any recomposition, so the sub-page is never tappable while
the gesture surface is still mounted. The LaunchedEffect(gesturesEnabled)
snapTo remains as a backstop for non-navigateTo entries.
* fix(#603): delay drawer gesture activation to prevent residual swipe
* fix(#603): fix settings back navigation and drawer auto-open
---------
Co-authored-by: hy4ri <hy4ri@users.noreply.github.com>
* feat: move session history to a dedicated history screen
Closes#159.
* fix(ci): fix ktlint style issues and unresolved NavigationController reference
goBack() now uses ChatScreen as a fallback when the stack has
only one item, preventing the Settings back-button crash.
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
## What
Adds a new Navigation Bar section to Settings where users can customize which items appear in the bottom navigation bar.
## Features
- Pick from any of the 19 drawer screens (max 5 items)
- Remove items with a close/delete button
- Items persist via SharedPreferences (CSV format)
- Invalid names are silently dropped
- Existing screens and auth-aware filtering respected
Closes#23
Complete UI/UX rewrite of hermes-mobile with Material You design system.
Phase 1: Color/Theme/Type/Shapes/Spacing/Motion tokens
Phase 2: HermesScaffold, StateViews (skeleton/empty/error), SearchBar, StatusBadge, ToggleRow
Phase 3: Bottom nav + drawer navigation with NavigationController
Phase 4: All 17 screens rewritten with HermesScaffold and Material You patterns
Closes PR #3.