Files
amethyst/nestsClient/plans/2026-04-26-tier3-coding-plan.md
T
Claude e71a2b26ef docs(audio-rooms): coding plans for Tier 1-4, one file per tier
The earlier integration audit identified the gaps; this is the
how-to-build-them. Split across four files plus an index so each
review / commit stays small:

  - 2026-04-26-tier-plans-index.md — top-level pointer + sequence
    dependencies + what's deliberately out of scope.

  - 2026-04-26-tier1-coding-plan.md — listener counter, presence
    aggregation, augmented kind-10312 tags (publishing/onstage),
    live chat (kind 1311), reactions (kind 7 / 9735), edit + close
    + scheduled rooms, role parsing + promote/demote, hand-raise
    queue, kick (kind 4312). Concrete file-level wiring for each
    step + suggested commit order (six independent PRs).

  - 2026-04-26-tier2-coding-plan.md — participant grid,
    per-avatar context menu (follow / mute / zap / promote / kick),
    zap entry points (room + speaker), share-via-naddr.

  - 2026-04-26-tier3-coding-plan.md — room theming PARSER ONLY
    (graceful fallback for themed rooms; full theming behind a
    later phase), background-audio + wake-lock audit checklist.

  - 2026-04-26-tier4-coding-plan.md — moq-auth token re-mint on
    long sessions and moq-lite Connection.Reload-equivalent
    reconnect with backoff. Step 1 is subsumed by Step 2 once the
    reconnect path is in.

No code changes — pure docs. Each plan names exact file paths,
new types, reused helpers, strings, tests, and call-out risks so
an implementer (or follow-up agent) can pick up Step N without
re-deriving the surrounding context.
2026-04-26 19:52:07 +00:00

126 lines
4.7 KiB
Markdown

# Tier 3 — coding plan (room theming, background-audio audit)
Tier 3 of `2026-04-26-nostrnests-integration-audit.md`. These are
larger or lower-priority items; do them after Tier 1 and Tier 2 ship.
## Step 1 — Room theming PARSER ONLY (#14, partial)
The minimum-viable slice. Goal: **don't render themed rooms badly.**
We parse the theme tags and either honour them with Compose color
overrides or ignore them with a graceful fallback (current visual).
Skip the kind 36767 / 16767 Ditto-theme refs and the per-user
profile theme — those are full features deferable to a later phase.
### Quartz
- `quartz/.../nip53LiveActivities/meetingSpaces/tags/ColorTag.kt`
(NEW) — parser for `["c", hex, "background"|"text"|"primary"]`.
`assemble(hex, target)` builder.
- `quartz/.../meetingSpaces/tags/FontTag.kt` (NEW) —
parser for `["f", family, optionalUrl]`. Builder.
- `quartz/.../meetingSpaces/tags/BackgroundTag.kt` (NEW) —
parser for `["bg", "url <u>", "mode tile|cover"]`. Builder.
- `quartz/.../meetingSpaces/MeetingSpaceEvent.kt` — accessors:
`colors(): List<ColorTag>`, `font(): FontTag?`,
`background(): BackgroundTag?`.
- `quartz/.../meetingSpaces/TagArrayBuilderExt.kt``colors`,
`font`, `background` DSL functions.
### Commons / Amethyst
- `commons/.../viewmodels/AudioRoomViewModel.kt` — expose
`roomTheme: RoomTheme?` derived from the event.
- `commons/.../viewmodels/RoomTheme.kt` (NEW):
```kotlin
data class RoomTheme(
val background: Color?,
val text: Color?,
val primary: Color?,
val backgroundImageUrl: String?,
val backgroundMode: BgMode = BgMode.COVER,
)
enum class BgMode { TILE, COVER }
```
- `amethyst/.../audiorooms/room/AudioRoomThemedScope.kt` (NEW) —
Composable wrapper that takes a `RoomTheme?` and overrides
Material3 `colorScheme` for its content. If null → no override.
Wrap `AudioRoomFullScreen` body in this.
- Background image: render via Coil `AsyncImage` behind everything,
honouring `backgroundMode` (cover via `ContentScale.Crop`, tile
via custom `Modifier.repeatedBackground`).
### Skip / defer
- Font loading (`["f", family, url]`) — would need a
`FontFamily` loader. Not user-blocking for parity.
- Kind 36767 (Ditto themes) and kind 16767 (per-user profile
themes). Mark as out-of-scope for now.
### Strings
None — pure visual.
### Tests
- `quartz/.../ColorTagTest.kt` — round-trip + invalid hex / target.
- `commons/.../AudioRoomViewModelTest.kt` — `roomTheme` populates
from a fake `MeetingSpaceEvent` with `c` / `bg` tags.
### Risk
- Some rooms use unusual hex shapes (`#abc`, named colors). Keep
the parser strict (`^#?[0-9a-fA-F]{6}$`) and fall back on parse
failure rather than crashing.
---
## Step 2 — Background audio + wake-lock audit (#15)
### Audit checklist
For each item, look in the named file and either confirm the
behaviour or open a follow-up bullet:
1. **`PARTIAL_WAKE_LOCK`** during a broadcast.
File: `amethyst/src/main/java/com/vitorpamplona/amethyst/service/audiorooms/AudioRoomForegroundService.kt`.
Check: is `PowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "...")`
acquired in `promoteToMicrophone(...)` and released in
`stop(...)`? If not, add it.
2. **Foreground service type `microphone`** for Android 14+.
Same file. Confirm the manifest declares
`android:foregroundServiceType="microphone"` and the service
call uses `ServiceCompat.startForeground(..., FOREGROUND_SERVICE_TYPE_MICROPHONE)`.
3. **Listener-only foreground type** when not broadcasting.
`AudioRoomForegroundService.startListening(context)` should use
`FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK` (NOT microphone — Play
Store rejects the elevated permission for listen-only users).
4. **Audio focus**. AudioTrack alone doesn't request focus; verify
`AudioManager.requestAudioFocus(AudioFocusRequest.Builder(...))`
is called in `AudioTrackPlayer.start()` and abandoned in
`stop()`. If not, add it (so a phone call ducks the room).
5. **PIP keep-alive**. Confirm `AudioRoomActivity` survives the
transition to PIP without dropping the foreground service —
should already be the case (commit history shows this was
audited previously).
### Output
A short audit notes file under `nestsClient/plans/` if any item
turns up missing — otherwise mark this step done.
---
## Suggested commit order
1. theme parser (Quartz: tags + accessors + tests) — small, safe
2. theme renderer (Compose: themed scope + background image)
3. background-audio audit notes (and any fixes that surface)
## Out of scope for Tier 3
- Kind 36767 (Ditto theme reference) and kind 16767 (per-user
profile theme) — these are full sub-features behind the basic
theming. Defer to a separate phase if needed.
- Per-user font loading — defer.