Finish replay implementation#94
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces the inbound share/VIEW/SEND flow on Android with an in-app replay library (Room-backed metadata + on-disk payloads), adds a Compose touch transport overlay above the native renderer driven via a new JNI control surface, and surfaces recent flights on Home. The native HUD gains a show_transport flag so Android can suppress the built-in transport bar in favor of the overlay. The renderer (HawkeyeActivity) is moved into a separate :renderer process, and the dead IntentRouterActivity/ReplayViewModel/feature:replay:domain module are removed.
Changes:
- Add
ReplayLibraryRepositoryincore:domain, Room+LibraryFileStoreimplementation infeature:replay:data, and Compose library + Home recents UIs. - Add native
replay_control(atomic request/snapshot bridge) andreplay_jniso KotlinNativeReplayControllercan pause/seek/speed the engine; ComposeTransportRootpolls status at 10 Hz and renders in aTYPE_APPLICATION_PANELwindow above raylib. - Switch Android to run
HawkeyeActivityin:renderer(Koin skipped there, hard-exit on destroy); HUD getsshow_transportplumbed into layout andhud_bar_heightfor desktop/WASM compatibility.
Reviewed changes
Copilot reviewed 86 out of 86 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/hud.h, src/hud.c |
Add show_transport flag; gate transport row + bar height on it. |
android/app/src/main/cpp/{android_main.c,replay_jni.c,replay_control.h,CMakeLists.txt} |
Atomic JNI bridge applied/published each frame; Android disables native HUD transport. |
android/app/src/main/java/.../HawkeyeActivity.kt |
Edge-to-edge, transport panel overlay, hard-halt on destroy, ditches RenderSession extras. |
android/app/src/main/java/.../HawkeyeApp.kt |
Skip Koin in :renderer process. |
android/app/src/main/java/.../render/{NativeReplayController.kt,RendererLauncher.kt} + transport/* |
New ReplayController, TransportViewModel/State/Action/Screen. |
android/app/src/main/java/.../replay/AndroidReplayPlaybackLauncher.kt, di/AppModule.kt, shell/AppShell.kt |
App-provided ReplayPlaybackLauncher and shell wiring. |
android/app/src/main/AndroidManifest.xml, res/values/{themes,strings}.xml |
Drop IntentRouterActivity/share filters/trampoline theme; add :renderer process and transport strings. |
android/app/src/main/java/.../IntentRouterActivity.kt, render/RenderSession.kt (+ test) |
Removed. |
android/app/src/test/.../render/transport/*, androidTest/.../{ShellNavigationTest,LibraryRecentsMultiItemTest}.kt |
New transport unit tests and instrumented shell/library tests. |
android/core/domain/{build.gradle.kts,LibraryEntry.kt,ReplayLibraryRepository.kt} |
New shared library entry + repository contract; expose coroutines-core as api. |
android/core/presentation/.../ReplayPlaybackLauncher.kt |
Seam so features don't depend on :app. |
android/feature/replay/data/** |
Room DB/DAO/entity, RoomReplayLibraryRepository, LibraryFileStore, AndroidReplayFileManager, schema JSON, DI, tests; replaces AndroidUlogInboxDataSource. |
android/feature/replay/presentation/** |
New ReplayLibraryScreen/ViewModel/State/Action/Event + mapper + strings + tests; removes ReplayScreen/ViewModel/... and stale tests. |
android/feature/replay/domain/** |
Module removed; types moved to core:domain. |
android/feature/home/presentation/** |
Home depends on ReplayLibraryRepository, exposes ≤3 recents, stages and launches playback; tests updated. |
android/{settings,build}.gradle.kts, gradle/libs.versions.toml, gradle.properties |
Add KSP + Room versions, drop feature:replay:domain, AGP 9 / KSP source-set opt-in. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Completes the in-app Replay experience for the Android app. The app no longer depends on sharing a
.ulginto it through Android intents. Instead it has an in-app library you import logs into, a recents shortcut on Home, and touch controls for playback on the renderer.What's included
In-app log library (
feature:replay).ulgfiles with the system document picker (ACTION_OPEN_DOCUMENT). Each file is copied into app storage (filesDir/library/<id>.ulg) with metadata in Room, so playback works offline and keeps working even if the original file goes away.Home recents peek
Touch transport overlay on the renderer
replay_*JNI control surface into the native engine. The bar lives in a dedicated full width overlay window so it composites above the GL surface and spans the screen edge to edge.Renderer process isolation
HawkeyeActivity) now runs in its own:rendererprocess and exits cleanly on teardown. This fixes a freeze (ANR) and a rotation crash that could occur after returning from a replay, and guarantees a clean start for every playback.Cleanup
IntentRouterActivity, its intent filters, and the trampoline theme) now that importing happens in app.Architecture
presentation(State/Action/Event/ViewModel plus a stateless Screen),domaincontracts, anddataimplementations.LibraryEntry,ReplayLibraryRepository) live incore:domainand the playback launch seam lives incore:presentation, so the feature modules stay decoupled.Testing
Demo
hawkeye_tour.mp4