wtclaude 09eb101c52
All checks were successful
PR Checks / android-build (pull_request) Successful in 9m53s
feat(rust): the map on a phone (module-rust phase 15, M17)
A fifth tab on the Rust server screen, between Online and Wipes, shown
when the site's module declares `map` under the app's one capability
rule (D122). `?tab=map` opens it; on a site without a map it opens the
feed.

The phone draws the map itself (D121): Coil loads the picture once per
map as RGB_565, and a Compose Canvas draws the grid and the markers,
with pinch, pan and double tap. The frame is §30.3's transform, ported
from the web's mapGeometry.js with its test cases. Markers keep their
size on screen; a zone is drawn on the ground. Nothing here gates a
layer: map/live is projected per viewer on the server, and the app
draws what it is sent.

- The legend: a switch per layer the viewer was sent, and who can see
  each one they were not (with the D113 line). The mates row offers
  the Steam link to a signed-in, unlinked viewer.
- The tap card: what a marker is, its grid square, and what its layer
  carried. A site-event marker whose run core's public calendar lists
  (D125) has Open event, which opens the app's own event page on that
  run (D123). A rehearsal's or unlisted event's marker says only
  "Site event".
- The poll: map/live every pollMs (10 s) while RESUMED on the Map tab
  (D124), and not at all for a viewer sent nothing that moves. A new
  mapKey re-reads the map, so a new seed's picture follows in place.
- Per account: the map's state is dropped and re-asked on a change of
  signed-in account, and an answer asked for the previous account is
  discarded when it lands.

Found on the emulator walk and fixed here: the reader's zoom was lost
on the way back from the event page, and again whenever the status line
under the map changed length (a resize was treated as a rotation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-25 08:28:26 -05:00
2026-07-19 01:38:07 -05:00
2026-07-19 01:38:07 -05:00
2026-07-19 01:38:07 -05:00
2026-07-19 01:38:07 -05:00
2026-07-19 01:38:07 -05:00

Runic Gateway — Android app

A native Android client for a Runic Gateway shard's public site + player self-service. It is purely an API client of the website backend — it never talks to the link/ sidecar or the game shard directly, and it ships none of the shard/sidecar wiring. It surfaces the same content and player features as the website's browser client, minus every administrative/management console.

The authoritative design contract is docs/android/PLAN.md in the RunicGateway/docs repo. The authoritative API reference is the committed OpenAPI spec at website/server/swagger/swagger-output.json.

Status

M0 — repo scaffold. Gradle + Compose + Hilt skeleton with CI (lint + unit test + debug build). The functional Kotlin pass (M1–M4) and the design pass (M5) follow — see the plan's milestones (§9).

Stack

Concern Choice
Language / UI Kotlin + Jetpack Compose (Material 3)
Navigation Navigation-Compose, single-activity
HTTP Retrofit + OkHttp, kotlinx.serialization
Async Coroutines + Flow
DI Hilt
Prefs / base URL Jetpack DataStore
Tokens at rest EncryptedSharedPreferences
Images Coil
Min SDK Android 10 (API 29)
Target / compile SDK 35

Dependency and plugin versions are pinned in gradle/libs.versions.toml.

Build

Requires JDK 17 and the Android SDK (ANDROID_HOME / local.properties).

./gradlew assembleDebug     # build a debug APK -> app/build/outputs/apk/debug/
./gradlew test              # JVM unit tests
./gradlew lint              # Android lint
./gradlew installDebug      # install on a connected device/emulator

The app self-configures its server URL on first run (PLAN.md §3), so a single build works against any shard's website — there is no compiled-in API host.

CI

.gitea/workflows/pr-checks.yml gates PRs into main and edge with ./gradlew lint test assembleDebug on the org's self-hosted runner (JDK 17 + Android SDK). Debug builds are auto-signed, so the gate needs no secrets. This pipeline is verified green end-to-end on the runner (M0). A signed release APK attached to a Gitea release comes at M6.

edge is in the trigger deliberately: a workstream that lands its phases on a working branch before one cutover PR into main otherwise gets no CI at all until the cutover — which is what happened to all nine M12 phase PRs (docs/website/ENGAGEMENT.md §7.1 Q8). sonarqube.yml is unaffected: it is a push-on-main analysis, not a PR gate.

The workflow carries a few runner-specific accommodations (each explained in comments in the file), because this self-hosted runner differs from a stock GitHub runner:

  • JDK 17 is installed via apt (not actions/setup-java) — the runner can't resolve api.adoptium.net, while the Ubuntu mirrors are reachable.
  • SDK packages are installed explicitly via sdkmanager, with set +o pipefail so yes dying of SIGPIPE doesn't fail the step.
  • gradlew is chmod +x'd in the run step — the runner's checkout does not preserve the git executable bit, so ./gradlew alone fails with "Permission denied".

Contributing

See CONTRIBUTING.md. AI-assisted contributions must be disclosed (org policy): tick the PR box naming the tool and add a Co-Authored-By trailer to AI-authored commits. Licensed GPL-3.0-or-later.

Description
No description provided
Readme 11 MiB
v0.5.0 Latest
2026-08-08 16:28:50 +00:00
Languages
Kotlin 99.9%
Python 0.1%