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.
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.
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.
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.
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.
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.
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`
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.
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.
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.