Skip to content

feat(settings): Settings screen MVP — theme, ADB override, hosting & polling defaults#34

Merged
manjees merged 2 commits into
mainfrom
feature/issue-33
May 14, 2026
Merged

feat(settings): Settings screen MVP — theme, ADB override, hosting & polling defaults#34
manjees merged 2 commits into
mainfrom
feature/issue-33

Conversation

@manjees

@manjees manjees commented May 14, 2026

Copy link
Copy Markdown
Owner

Closes part of #33.

Summary

Implements the Settings screen MVP, replacing the previous Dashboard fallback wired to Screen.Settings. README cleanup and Compose deprecated migration from #33 are split out to follow-up commits/PRs to keep this PR focused.

What's in this PR

Settings infrastructure

  • domain/model/AppSettings.kt — settings shape with safe defaults and range constants
  • domain/repository/SettingsRepository.kt — observe + atomic update API; exposes a synchronous current snapshot for callers like AdbBinaryManager that can't suspend
  • data/repository/SettingsRepositoryImpl.kt — JSON-on-disk at ~/.linkops/settings.json. Mirrors FavoriteRepositoryImpl's safety model (Mutex + Dispatchers.IO + a DTO separate from the domain model + value clamping on read so a corrupt file can't propagate bad numbers)
  • domain/usecase/settings/{Observe,Update}SettingsUseCase.kt — thin pass-throughs to keep DI/conventions consistent with the rest of the project

Settings screen

  • ui/screen/settings/SettingsViewModel.kt — form-local state with draft vs persisted separation so text fields don't write per-keystroke; explicit dirty/valid/canSave flags
  • ui/screen/settings/SettingsScreen.kt — four OutlinedCard sections built from Material3:
    1. Appearance — Light / Dark / System (SingleChoiceSegmentedButtonRow, persists instantly)
    2. ADB — override path; empty falls back to system PATH / bundled
    3. Local Hosting defaults — host + port, validated 1..65535
    4. Device detection — polling interval, validated 1..60s

Wiring

  • di/AppContainer.kt — repository + use cases registered
  • App.ktScreen.Settings now routes to SettingsScreen; LinkOpsTheme(darkTheme = ...) consumes the persisted theme preference so changes apply instantly
  • infrastructure/adb/AdbBinaryManager.kt — checks settings.adbPathOverride first; falls back gracefully if the file isn't executable
  • data/repository/DeviceRepositoryImpl.kt — polling delay re-read on every tick, so a settings change takes effect on the next iteration without restart
  • ui/screen/localhosting/LocalHostingViewModel.kt — seeds host/port from settings on open; edits stay local (don't push back to settings)

Test plan

  • ./gradlew :composeApp:compileKotlinJvm → BUILD SUCCESSFUL
  • ./gradlew :composeApp:jvmTest → all green
  • Manual: open Settings, toggle theme → entire app re-themes instantly
  • Manual: change polling interval to 10s → device list refreshes at the new cadence within one tick
  • Manual: set invalid port (e.g. 999999) → Save button disables, supporting text shows the valid range
  • Manual: set a bogus ADB override path → falls back to system ADB without crashing; correcting the path restores override priority
  • Manual: open Local Hosting → host/port pre-filled from settings
  • Manual: edit text fields, hit Discard → fields revert to persisted values

Not in this PR (follow-up for #33)

…, hosting & polling defaults

Replaces the Dashboard fallback that was wired to Screen.Settings. Settings persist to
~/.linkops/settings.json with the same Mutex + Dispatchers.IO pattern as favorites.

Sections:
- Appearance: Light / Dark / System, applied instantly via LinkOpsTheme(darkTheme = ...)
- ADB: optional override path; AdbBinaryManager prefers it over the system PATH and
  falls back gracefully if the file isn't executable
- Local Hosting defaults: default host/port seeded into LocalHostingViewModel on open
- Device detection: polling interval read on every DeviceRepositoryImpl tick so a
  change takes effect on the next iteration without an app restart

Form behavior:
- Theme writes through immediately (visual feedback is the confirmation)
- Text fields stay local until Save; port and polling inputs are validated against
  their declared ranges before the Save button enables
- Discard reverts the draft to the persisted value

Part of #33. README/Compose deprecated cleanup left for follow-up commits.
@manjees manjees added enhancement New feature or request ui User interface and visual improvements labels May 14, 2026
README:
- Features section now reflects every screen actually shipped (Verification Deep
  Dive, Local Hosting, Intent Sniffer, Topology Map, Scheme Collision, Batch Test,
  Logcat Streaming, QR, Favorites, Settings, keyboard shortcuts)
- Roadmap split into Done / Next / Later. Next items link to follow-up issues
  (#29 tunnel, #30 iOS, #31 CLI, #32 APK)
- Tech stack and project structure updated; Compose hot-reload command added

Compose deprecated migration (11 sites):
- Modifier.menuAnchor() -> .menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable)
  All call sites were read-only OutlinedTextField inside ExposedDropdownMenuBox
- TabRow(...) -> PrimaryTabRow(...)  (Diagnostics, Manifest, Sniffer)
- Icons.Default.Send -> Icons.AutoMirrored.Filled.Send

Remaining warnings deferred (different scope):
- AdbBinaryManager URL(String) constructor — Java's URL deprecation, network
  layer change; touching it risks breaking ADB auto-download
- QrCodeDialog LocalClipboardManager — Compose's new LocalClipboard API is
  suspend-based; converting requires reworking the copy flow with a coroutine
  scope. Will track separately if it actually breaks in a future Compose release.

Completes #33.
@manjees manjees added the documentation Improvements or additions to documentation label May 14, 2026
@manjees manjees merged commit 07b858f into main May 14, 2026
2 checks passed
@manjees manjees deleted the feature/issue-33 branch May 14, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request ui User interface and visual improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant