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

4.7 KiB

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.ktcolors, font, background DSL functions.

Commons / Amethyst

  • commons/.../viewmodels/AudioRoomViewModel.kt — expose roomTheme: RoomTheme? derived from the event.
  • commons/.../viewmodels/RoomTheme.kt (NEW):
    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.ktroomTheme 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.