Commit Graph
42 Commits
Author SHA1 Message Date
M57andM57 2c6e437a5b Fix: Prevent AuthManager state pollution on connection verification (#348)
* Fix: Prevent AuthManager state pollution on connection verification

Modified `ConnectViewModel.connect()` to construct a temporary OkHttpClient and Retrofit builder, isolated from the global `ApiClient` state. The connection verification is executed using this temporary service. Only upon a successful HTTP response does the system persist the configured `host`, `port`, and `token` to the global `AuthManager` and triggers an `ApiClient.rebuild()`. This resolves the issue where a failed connection attempt would overwrite active and verified profiles. Extracted `createTempService` factory to `ApiClient` for robustness and clean tests.

Fixes #260

* Fix: Prevent AuthManager state pollution on connection verification

Modified `ConnectViewModel.connect()` to construct a temporary OkHttpClient and Retrofit builder, isolated from the global `ApiClient` state. The connection verification is executed using this temporary service. Only upon a successful HTTP response does the system persist the configured `host`, `port`, and `token` to the global `AuthManager` and triggers an `ApiClient.rebuild()`. This resolves the issue where a failed connection attempt would overwrite active and verified profiles. Extracted `createTempService` factory to `ApiClient` for robustness and clean tests.

Fixes #260

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-23 20:49:58 +03:00
M57 3798d0330f Fix main-thread decryption block by caching token in StateFlow (#322)
Issue #278 reported that `AuthManager.getToken()` (which reads from
`EncryptedSharedPreferences`) was being called synchronously inside the
`MainNavigation` composable, causing UI thread blocks during navigation
transitions (PERF-10).

This commit resolves the issue by caching the token in a new `tokenFlow`
(`MutableStateFlow`) within `AuthManager`.
- The flow is initialised with the token during `AuthManager.init()`.
- Updates to the token (`setToken`, `setSelectedProfileId`,
  `setProfileToken`) are synchronised with `tokenFlow`.
- `MainNavigation` now correctly observes this state using
  `collectAsState()`, preventing disk-read blocking on recompositions.

Impact: Navigation transitions are now fully non-blocking. No side effects
are expected as state synchronisation maintains parity with persistent storage.

Resolves #278
2026-06-23 12:19:33 +03:00
M57andM57 60bf6e8a33 feat: UI Changes
* fix(#220): implement edit soul and set model dialogs

* fix(#211): make UI more compact and information dense

* fix(#211): make navigation drawer sidebar more compact

* feat(#252): move settings item to end of navigation drawer

* feat(#250): add bottom navigation bar display mode settings

* feat(#225): add search bar filtering to remaining screens

* fix: make bottom navigation bar display modes more compact

* fix: resolve compilation error in KanbanScreen by referencing assignedTo

* feat: add search to achievements screen and top padding for icon-only navigation bar

* fix: adjust icon-only bottom bar height and remove padding

* fix(#249): remove unused PaddingValues imports in 6 screens

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-21 20:42:23 +03:00
M57 57c3e468df feat(#238): update Model tab icon to Psychology (#243) 2026-06-21 19:09:16 +03:00
Hy4ri 69ff66b8de style: remove unused R import in Navigation.kt to pass ktlint 2026-06-21 12:00:08 +03:00
Hy4ri c34f6f1e47 refactor(#78): extract navigation and drawer labels to string resources 2026-06-21 11:09:44 +03:00
M57 081996d376 refactor: extract entryProvider from MainNavigation (#197)
Extract the overly long `entryProvider` lambda out of `MainNavigation` into a separate `appEntryProvider` function to improve code readability and maintainability.
2026-06-21 00:31:59 +03:00
M57 045932ca8b Optimize collection creation in Navigation.kt (#180)
* ⚡ Optimize collection creation in Navigation.kt

Replaced uses of `.map { ... }.toSet()` with `.mapTo(mutableSetOf()) { ... }` in Navigation.kt. This avoids the creation of intermediate ArrayList objects, saving unnecessary memory allocations.

* ⚡ Optimize collection creation in Navigation.kt

Replaced uses of `.map { ... }.toSet()` with `.mapTo(mutableSetOf()) { ... }` in Navigation.kt. This avoids the creation of intermediate ArrayList objects, saving unnecessary memory allocations. Fixed ktlint formatting issues causing CI failure.
2026-06-20 23:44:39 +03:00
M57 34af34af6d perf: avoid intermediate allocation in bottomNavKeys (#184)
Replaces `.map { ... }.toSet()` with `.mapTo(mutableSetOf()) { ... }`
when resolving `bottomNavKeys` to avoid creating and discarding an
intermediate `ArrayList` during recomposition.
2026-06-20 23:42:40 +03:00
M57 64a047f095 feat: move session history to a dedicated history screen (#175)
* feat: move session history to a dedicated history screen

Closes #159.

* fix(ci): fix ktlint style issues and unresolved NavigationController reference
2026-06-20 22:27:54 +03:00
M57 8c9c11df23 refactor(#103): centralize navigation mutations through NavigationController.resetTo() (#164)
* refactor(#103): centralize navigation mutations through NavigationController.resetTo()

* fix(chat): fix scroll-to-bottom FAB compilation errors
2026-06-20 17:01:37 +03:00
M57andM57 3f19224228 feat(#123): add primary screens to drawer categorically (#158)
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-20 13:46:08 +03:00
M57andM57 f5edf1569c fix(#141): notification tap opens original session instead of new session (#147)
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-20 10:10:10 +03:00
M57andronia 913c6fa878 fix(#134): remove settings button from chat top bar (#138)
Co-authored-by: ronia <ronia@m57>
2026-06-20 02:28:36 +03:00
Hy4ri 8755338636 Revert "Merge pull request #42 from Hy4ri/feat/sessions-screen"
This reverts commit 7d50b5acd7, reversing
changes made to ee97be50cb.
2026-06-19 23:18:26 +03:00
M57 7d50b5acd7 Merge pull request #42 from Hy4ri/feat/sessions-screen
feat: dedicated Sessions browser screen (Issue #40)
2026-06-19 23:14:40 +03:00
M57andM57 abcec14cb5 feat(#76): add testTag identifiers to composable elements for UI test targeting (#98)
Adds testTag modifiers to key interactive elements across the core
composables, enabling Espresso/Compose UI tests to locate them:

Navigation.kt  — 'nav_*' on bottom bar items, 'drawer_*' on drawer items
HermesScaffold — 'back_button', 'menu_button', 'refresh_button'
StateViews.kt  — 'loading_state', 'loading_spinner', 'error_retry_button',
                 'empty_state_action'
ChatScreen.kt  — 'chat_input', 'send_button', 'interrupt_button'

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-19 22:15:53 +03:00
11d97a2d5f fix(#75): replace non-null assertion on simpleName with safe mapNotNull
* ci: prevent concurrency cancellation on rapid main merges

The concurrency group used github.ref which is static for main
(refs/heads/main). When multiple PRs merged rapidly (~2 min apart),
each merge commit cancelled the previous CI run before it could finish.

Fix: use github.sha for push events to main (unique per commit) while
keeping the ref-based group for PR branches (cancels on new commits to
the same PR branch).

* refactor(#82): remove dead SkeletonList/SkeletonCard composables

* fix(#72): echo server's WebSocket close code instead of hardcoded 1000

* fix(#75): replace non-null assertion on simpleName with safe mapNotNull

---------

Co-authored-by: ronia <ronia@m57>
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-19 20:48:48 +03:00
Hy4ri 4ecde51e2c Consume window insets in NavDisplay to eliminate keyboard gaps (Issue #59) 2026-06-19 19:47:49 +03:00
Hy4ri 0cdf8fd779 fix(navigation): show bottom bar on all screens except ConnectScreen 2026-06-19 18:31:37 +03:00
Hy4ri 3a610c7c80 fix(ci): fix trailing spaces and revert visibility/padding changes 2026-06-19 18:23:17 +03:00
Hy4ri 9e3a7ab339 fix: always show bottom bar, resolve chat input double padding, and format codebase 2026-06-19 18:14:41 +03:00
Hy4ri 91ad09b5f2 fix(navigation): dynamically update bottom navigation items 2026-06-19 18:02:49 +03:00
ronia 4327389b32 feat: dedicated Sessions browser screen (Issue #40) 2026-06-19 16:48:16 +03:00
ronia 5d4f211f17 fix: bottom navigation bar customization not reflected in NavigationBar (Issue #37) 2026-06-19 13:35:57 +03:00
M57 66da56ca24 feat: connection status indicator in drawer (Issue #28)
feat: connection status indicator in drawer (Issue #28)
2026-06-19 12:40:32 +03:00
ronia 71d3b975af style: fix ktlint import ordering (LaunchedEffect before collectAsState) 2026-06-19 12:31:43 +03:00
ronia 1db55c57c6 style: fix ktlint import ordering in Navigation.kt 2026-06-19 12:21:20 +03:00
ronia a2c9bb638a style: fix ktlint errors in Navigation.kt 2026-06-19 12:19:29 +03:00
M57 0038606c05 feat: add connection status indicator (Issue #28)
Adds a colored dot next to the '⚡ Hermes' brand header in the
navigation drawer:
  - Green: connected
  - Yellow: connecting / reconnecting
  - Red: disconnected

Uses a StateFlow on HermesWsClient that tracks the WebSocket
connection lifecycle and is collected in the drawer header.
2026-06-19 12:07:44 +03:00
M57 1c1961426a fix: migrate deprecated APIs (Issues #25, #26, #27)
- Icons.Filled.ArrowBack/ListAlt → Icons.AutoMirrored.Filled (Issue #25)
- ScrollableTabRow → PrimaryScrollableTabRow (Issue #26)
- fallbackToDestructiveMigration() → fallbackToDestructiveMigration(false) (Issue #27)
2026-06-19 12:02:07 +03:00
M57 34df198c4d feat: configurable bottom navigation bar (Issue #23)
## 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
2026-06-18 21:16:21 +03:00
M57andM57 837678c590 fix(#21): remove double spacing above top bar and below chat input (#22)
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
2026-06-18 20:36:56 +03:00
M57 d90e36974c feat: Material You design system rewrite — Phases 1–4
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.
2026-06-18 16:34:44 +03:00
ronia f833005bec fix(settings): route topbar Settings through NavigationController + Clear Token button
B7 (Jun 18 2026): user reported Settings page unresponsive when
reached via the ChatScreen topbar gear icon, but worked fine via
the drawer sidebar. Two fixes:

1. Route topbar gear through NavigationController.navigateTo()
   instead of raw backStack.add(). The NavigationController path
   (used by the drawer) deduplicates against the current top
   entry and matches the drawer's navigation flow exactly. The
   bypass path could stack duplicate SettingsScreen entries on
   rapid taps, which likely caused the unresponsive symptom.

2. Add 'Clear Token' OutlinedButton below the Auth Token field in
   Settings. One-tap wipes a corrupted / rejected token and saves
   immediately, without having to select-and-delete the masked
   password field character by character. Recovers from the
   'I gave you a bad token' scenario in seconds.
2026-06-18 03:56:04 +03:00
7daf73ce0d feat(ui): modern theme, sectioned drawer, shared components (v1) (#1)
* feat(ui): modern theme, sectioned drawer, shared components (v1)

Foundation for the modern redesign — fixes the biggest UX problems
(that vague "better ui ux" ticket) without rewriting all 20 screens
at once. This puts the infrastructure in place and modernizes the
highest-traffic screens.

Theme (
  - Disable Material You dynamic color by default — brand identity
    (Voltage Purple) wins. Can opt back in via HermesControlTheme.
  - 3-step elevation ladder (surface / surfaceVariant / surfaceHigh)
    with subtle blue tint so dark mode stops reading as flat black.
  - Full Material 3 type hierarchy — every style explicitly tuned,
    tighter letter spacing, comfortable line heights.
  - New Shapes.kt (xs→xl rounded corner tokens) and Spacing.kt
    (xs/sm/md/lg/xl/xxl spacing tokens) — no more ad-hoc dp values.

Navigation (
  - Sectioned drawer: 17 items were dumped at one indent level with
    duplicate icons (Channels & Chat both used the Chat icon!). Now
    grouped into 4 logical sections — Converse / Automate / Configure
    / Inspect — with section headers and sane per-item icons.
  - Settings added to the drawer (was previously hidden behind
    ChatScreen's gear icon — bad IA).
  - gesturesEnabled check collapsed from an 18-term OR chain into a
    single set-membership test.

Common components (
  - HermesScaffold: shared drawer-aware Scaffold + TopAppBar with
    slots for refresh / actions. Removes the per-screen duplication
    seen in SkillsScreen, CronJobsScreen, ChannelsScreen, etc.
  - StateViews: LoadingState / ErrorState / EmptyState / list content
    padding tokens — every list screen now renders loading/error/
    empty identically instead of ad-hoc per screen.

Modernized screens:
  - ConnectScreen: hero brand badge (was a lone "⚡" glyph), pairing
    as the primary path, manual token/host/port collapsed behind a
    toggle (was always-visible clutter), Card-in-Card nesting removed.
  - SkillsScreen: now uses HermesScaffold + EmptyState + ErrorState +
    LoadingState. Adds a search field, leading icon per row, and a
    category sublabel.

Follow-up commits will migrate the remaining ~15 list screens onto
HermesScaffold; this commit stops at the foundation + the two screens
that see the most daily use.

Verified: ktlint clean across the entire tree.

Co-Authored-By: Ronia <ronia@m57>

* fix(imports): add missing safeDrawingPadding + dp imports

CI caught three compile errors that ktlint doesn't flag (unresolved
references are not lint errors, they're compile errors):

- Navigation.kt:239  — Modifier.safeDrawingPadding() import was
  dropped when the file was rewritten for the sectioned drawer.
- SkillsScreen.kt:117 — `16.dp` and `12.dp` references had no
  `androidx.compose.ui.unit.dp` import after the file was rewritten
  onto HermesScaffold.

No code changes — pure import fixes.

Co-Authored-By: Ronia <ronia@m57>

* ci: split monolithic job into 4 parallel jobs + summary

Before — one job ran ktlint → lint → test → build sequentially. If
ktlint failed you waited ~30s to find out, and the test/build stages
never even started (no useful artifacts uploaded on partial failure).

After — 4 jobs run in parallel on every push and PR:
  1. ktlint          (fast feedback, ~30s)
  2. android-lint    (parallel, includes compileDebugKotlin)
  3. unit-tests      (parallel, JUnit 5 + mockk)
  4. build           (gated by 1+2+3, only runs if all pass)

Plus a 5th `ci-summary` job that aggregates results so branch
protection only needs a single status check configured.

Other improvements:
- concurrency cancel-in-progress — new commits on the same ref
  cancel the stale run instead of piling up.
- timeout-minutes on every job — no more hung runners burning minutes
  on a stuck Gradle daemon.
- workflow_dispatch — can trigger manually from the Actions tab.
- Per-job artifact uploads with `if: always()` — reports upload even
  when the job fails, so you can download test/lint reports to debug.
- Removed the monolithic "verification-reports" artifact that tried
  to upload three unrelated paths and failed silently with "No files
  were found" when an early step bailed.

Co-Authored-By: Ronia <ronia@m57>

* ci: silence ktlint artifact-not-found annotation

Adds `if-no-files-found: ignore` to the ktlint artifact upload step
because ktlint 1.2.1 does not produce HTML reports on success — only
on failure. The previous config `if-no-files-found: warn` (default)
emitted a noisy annotation on every green run.

Co-Authored-By: Ronia <ronia@m57>

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
Co-authored-by: Ronia <ronia@m57>
2026-06-18 02:59:43 +03:00
Hy4ri 3830236585 feat: slash command autocomplete, dynamic theme colors, interactive model selection & drawer icons 2026-06-16 18:15:01 +03:00
Hy4ri 9b2aeae836 Add vertical scrolling modifier to sidebar drawer navigation 2026-06-16 00:16:33 +03:00
Hy4ri 03916014c0 Implement Logs, Plugins, Channels, Keys, System, and Kanban screens with full integration tests and code formatting checks 2026-06-16 00:13:18 +03:00
Hy4ri 43dfbc5470 Implement MCP Servers, Webhooks, and Models screens 2026-06-16 00:06:43 +03:00
Hy4ri a8cf79d91c Implement Device Pairing and Config screens 2026-06-16 00:02:05 +03:00
Hy4ri d6ff3de594 Initial commit of HermesControl Android app 2026-06-16 00:00:36 +03:00