Commit Graph

14 Commits

Author SHA1 Message Date
Brummel 506804e4cd Add tap-to-edit oneliner on case detail screen
Tap opens the Wear OS system input picker (voice/keyboard/handwriting),
pinned to de-DE for medical German vocabulary. Doctor-authored oneliners
latch a manual flag that blocks the simulated LLM burst from overwriting
them; a subsequent manual edit still wins.
2026-04-24 16:22:32 +02:00
Brummel edcee399b4 Split recording flow into case detail + recording screens
Tap on a case in the list (or Tile continue-case) now opens a new
CaseDetailScreen showing date + oneliner + record EdgeButton. Only
hitting record enters RecordingScreen, which is itself trimmed to
just a live mm:ss counter and a stop EdgeButton. Swipe-right on the
recording screen discards the in-flight recording (no confirmation).
"New case" button still bypasses the detail step.

State machine: Recording now counts elapsedSeconds (up) instead of
secondsLeft. New OnStopTap and OnDiscardTap events, new reducer
transitions. Safety cap at 300 s.

ViewModel: startRecordingFlow split into a cancellable ticker job
plus a separate finalizeAndUpload run in applicationScope so the
upload survives the pop that follows a clean stop. AtomicBoolean
finalizationStarted guards against double-finalization between the
stop, discard, and auto-stop paths.

Display: FLAG_KEEP_SCREEN_ON on the recording screen via
view.keepScreenOn. DisposableEffect.onDispose doubles as the
discard trigger for swipe-right / back / host destruction;
discardIfStillRecording() is a no-op after a clean stop.

CaseDetailScreen lays out three vertical thirds: date/time at top
(Heute/Gestern/dd.MM.yy + HH:mm:ss), oneliner in the middle,
EdgeButton at the bottom. formatTime extracted to TimeFormat.kt
so list and detail never drift apart.
2026-04-24 15:42:52 +02:00
Brummel 028342d4a4 Add "minutes ago" time formatting
Introduces a `minutesAgo` helper function and uses it in `CaseStoreStub`
to populate `CaseEntry` objects with relative timestamps for recent
activities. Also updates `formatTime` in `CaseListScreen` to display
"Gerade eben", "Vor 1 Minute", or "Vor X Minuten" for entries younger
than an hour. This provides a more user-friendly display for recent
cases.
2026-04-24 14:34:55 +02:00
Brummel 50fbc2690e Add scrolling to newest case
Display cases in reverse chronological order for better UX. Scroll to
the last item when data is loaded.
2026-04-24 14:29:46 +02:00
Brummel f653a6a447 Update demo data and time formatting
Refactor `seedDemoData` to use `java.time` for more accurate date and
time generation, including specific times for today, yesterday, and
older dates.
Update `formatTime` in `CaseListScreen` to leverage `java.time` for a
more robust and localized date and time formatting, supporting "today",
"yesterday", and older date formats.
2026-04-24 13:58:52 +02:00
Brummel 816e8b278d Add vertical spacing to case list 2026-04-24 13:44:15 +02:00
Brummel 5176ea26f4 Refactor CaseRow styling and text behavior
Improve the visual presentation of individual case entries by adjusting
styling and text handling. This includes setting a minimum height for
rows, applying consistent padding, and enabling text truncation with an
ellipsis for longer oneliner descriptions.
2026-04-24 12:46:55 +02:00
Brummel 3b2b62865c Fix: Disable auto-centering on ScalingLazyColumn 2026-04-24 12:24:42 +02:00
Brummel b02cc0c870 Add Wear OS Tile and Complication support - PoC
This commit introduces support for Wear OS Tiles and Complications,
enabling users to view case information and launch the app directly from
their watch face.

Key changes include:
- **New Complication Service:** `DoctateComplicationService.kt` provides
  a simple complication that displays "Doctate" and launches the app's
  case list upon tap.
- **New Tile Service:** `DoctateTileService.kt` serves a dynamic tile
  showing the current case's one-liner. It includes tappable areas to
  navigate to the case list, create a new case, or continue an existing
  one.
- **UI Navigation:** `AppNav.kt` and related files (`CaseListScreen.kt`,
  `MainActivity.kt`, `NavCommand.kt`) set up the navigation structure
  for the Wear OS app, handling intents from the Tile and Complication.
- **Data Structures:** `CaseEntry.kt` defines the minimal data structure
  for case information displayed on the watch.
- **In-Memory Data Store:** `CaseStoreStub.kt` acts as a temporary,
  in-memory store for case data, ensuring consistency across the
  activity, Tile, and Complication.
- **Dependency Updates:** Added necessary Wear OS libraries to
  `build.gradle.kts` and `libs.versions.toml`.
- **AndroidManifest:** Configured the `MainActivity` to handle
  `singleTask` launch mode and added necessary intent filters for
  complications.
- **Demo Data:** Seeded `CaseStoreStub` with demo data for initial
  testing and visualization.
2026-04-23 23:07:03 +02:00
Brummel 3429e8bdf7 feat(watch): support real Pixel Watch 2 via ADB-WiFi + LAN dev server
Real hardware has no USB and can't resolve 10.0.2.2, so we pair over
ADB-WiFi and point the app at the dev laptop's LAN URL. run.sh gains a
`watch`/`emulator` target prefix so both devices can be attached in
parallel without serial-picking roulette.

- network_security_config.xml: whitelist 192.168.178.27 for cleartext
- build.gradle.kts: resolveProp() threads Gradle CLI `-P` overrides
  into BuildConfig (SERVER_URL, API_KEY) ahead of local.properties
- run.sh: adb_cmd wrapper honours ADB_SERIAL; new `devices` and
  `connect [ip:port]` subcommands; `.watch_serial` caches the paired
  endpoint so `./run.sh watch install` just works on subsequent runs
- .gitignore: ignore `.watch_serial`
2026-04-23 17:54:15 +02:00
Brummel ed993a5c6d feat(watch): vertical PoC — record, upload, playback end-to-end
Completes the 5-second-record-and-upload flow:
- RecordingViewModel orchestrates recorder, countdown, and upload
- MediaRecorder wrapper produces 16kHz/AAC-LC m4a (Whisper-compatible)
- Compose RecordingScreen renders the state pyramid
  (Idle / RequestingPermission / Recording / Uploading / Success / Error)
- UiState + pure reducer with full JVM unit-test coverage
- run.sh "test" subcommand wraps the unit and instrumented tiers
  (set SKIP_INSTRUMENTED=1 to bypass the on-device tier)

Verified end-to-end: emulator captures "Hallo, hallo", lands at
tmpdata/<user>/<case>/*.m4a, Whisper transcribes, Ollama classifies,
document.md is written — full pipeline in ~5s.

Known: MockWebServer-based UploadClientTest hangs in setUp on the
Wear OS 34 emulator (likely SELinux socket policy). Deferred — the
real-server end-to-end already validates the wire protocol.
2026-04-23 16:30:57 +02:00
Brummel 8306dd8c47 feat(watch): scaffold upload client and app service locator
Builds the network foundation for the Wear OS vertical PoC:
OkHttp-based UploadClient mirroring doctate-client-core's wire protocol
(multipart /api/upload, X-API-Key, transient/terminal classification),
BuildConfig-backed Settings sourced from local.properties, CaseId factory,
DoctateApp service locator, MockWebServer-based UploadClientTest for
wire-format assertions, plus the manifest/permissions/network-security-
config plumbing for emulator-loopback cleartext.

MainActivity is still the placeholder UI; audio recording, ViewModel,
and recording screen come in follow-up commits.
2026-04-23 15:25:53 +02:00
Brummel 9a72619f23 chore(watch): set header text to "Doctate!" 2026-04-23 12:29:06 +02:00
Brummel 8956b74c09 feat(watch): scaffold Wear OS app via Android Studio
Initial skeleton for the Pixel Watch dictation client (Plan Phase 5b).
Generated by Android Studio's "Empty Wear App" template, kept verbatim
to defer bikeshedding until real friction appears.

Toolchain pinned via wrapper / version catalog:
  AGP 9.2.0, Kotlin 2.2.10, Gradle 9.4.1, JDK 21 (auto-provisioned).
  compileSdk 36, minSdk 30 — covers Pixel Watch 1/2/3.

UI starter: Wear Compose Material3 1.5.6 with TransformingLazyColumn
and EdgeButton — already close to the planned per-case full-screen
list pattern.

Manifest declares the app standalone, so the Wear OS Network Proxy
will tunnel uploads transparently when the watch lacks LTE/WiFi.
No Phone-side companion module required.

Multi-module split (:core-domain, :core-audio, :core-sync, :core-http,
:core-storage, :app-mobile) intentionally postponed — current single
:app module is the smallest thing that compiles, which gives us a
known-good baseline before restructuring.

AS's default .gitignore left as-is. A handful of .idea/ project-config
files (compiler.xml, gradle.xml, misc.xml, codeStyles, runConfigurations)
are committed by AS's design; revisit if machine-specific paths or
multi-machine drift become painful.
2026-04-23 11:52:45 +02:00