Station scope is explicit
Metadata, Queue, History, Chat, requests, Favorites, activity, and sessions all carry a station identity. State cannot silently leak between stations.
Engineering the player
Development proceeds in evidence-backed vertical slices: research the station contract, define domain boundaries, implement native behavior, validate narrowly, then record the result before moving on.
Dependency direction
Compose never imports network, cookie, WebSocket, ExoPlayer, or station protocol implementations. Screens receive immutable state and emit actions upward; ViewModels depend on domain repository and playback interfaces.
Design principles
Metadata, Queue, History, Chat, requests, Favorites, activity, and sessions all carry a station identity. State cannot silently leak between stations.
A feature appears only when the station contract says it is supported. Missing evidence produces an unavailable or unknown state, never invented behavior.
Polling intervals, response sizes, row counts, character limits, same-origin rules, and redirect policies are enforced by the data layer.
Chat, song requests, request messages, and abuse reports require explicit user actions and are not retried automatically when the result is indeterminate.
Credentials, cookies, CSRF values, signing material, reviewer accounts, HAR files, and unsanitized captures never belong in repository history.
App features use Compose and repository contracts. Selected public pages may open in a trusted Custom Tab, but the application itself is not a WebView shell.
Milestone lifecycle
Each milestone is sized before work begins and closes only after implementation, proportionate validation, evidence, documentation, and focused Git history are complete.
Read the smallest relevant source and evidence set. Reproduce the behavior before editing, and preserve unrelated user work.
Verify station responses, Android behavior, policy boundaries, and capability differences. Unknowns remain explicit.
Model immutable state and repository contracts, then identify UI actions, data adapters, playback boundaries, and failure states.
Compose renders state, ViewModels coordinate, repository implementations own protocols, and Media3 remains service-owned.
Target affected unit tests and Kotlin compilation before broader lint, bundle, emulator, or physical-device checks.
Update milestone documents and the chronological README roadmap with verified results, limitations, and remaining device or owner checks.
Create a focused commit and PR, let GitHub Actions validate it, post the change summary to Discord, and verify the merged result.
Repository map
app/src/main/.../uiAdaptive screens, immutable UI state, actions, navigation shell, dialogs, and Material theme.
app/src/main/.../domainStation identities, capabilities, repository interfaces, playback boundary, and trust policies.
app/src/main/.../dataRemote adapters, defensive parsers, encrypted session persistence, polling limits, and local preferences.
app/src/main/.../playbackExoPlayer, MediaSession, MediaController adapter, notification behavior, stream fallback, and recovery.
app/src/testDomain rules, parsers, repositories, ViewModels, state transitions, and release helpers.
app/src/androidTestCompose semantics, adaptive layouts, navigation, accessibility, screenshots, and device-state behavior.
docsProtocol research, validation records, station certifications, device matrices, Play readiness, and release notes.
.github/workflowsAndroid build/test/lint assembly, Pages generation/deployment, and Discord result notification.
Current candidate toolchain
The project remains a single Android application module. It will split only when stable boundaries justify the added Gradle complexity.
Contribute responsibly
Open an issue before a large feature or protocol change, branch from main, preserve layer boundaries, add tests, and never publish protected station or signing data.