Files
flamenet-messenger-android/app
Paul HittandClaude Opus 5 4fd648382f The mic button froze the app, and one design system for both
🔴 **Tapping "record a voice note" hung the iOS main thread.** VoiceRecorder is
@MainActor and ran AVAudioSession.setCategory/setActive and AVAudioRecorder's
init and record() directly on it. setActive(true) blocks until the audio route
is up. Measured under XCUITest: the tap was followed by SIXTY SECONDS of "App
event loop idle notification not received", after which every accessibility
query cost 31 seconds because the main thread was still stuck — which is why
the failure had been reading as a slow test rather than as a frozen app.

The blocking calls now run in a detached task; published state is still
assigned on the main actor afterwards. The stall is gone: zero idle-loop
warnings, and the test fell from 224s to 103s.

Two deadlines, because moving work off the main thread stopped it freezing the
UI without making it finish:

- The permission ask. `AVAudioSession.requestRecordPermission` is deprecated
  since iOS 17; on 17+ we now use AVAudioApplication. Either way it is raced
  against 5 seconds, because a permission API that never calls back would
  otherwise suspend start() for ever.
- Opening the route, against 6 seconds, for the same reason.

Without these, start() returned neither true nor false, so the caller showed
NO recording bar and NO error: a mic button that does nothing at all when
tapped, with no way to tell broken from slow.

⚠️ **iOS voice notes are still not verified.** The freeze is fixed and proven
gone, but recording does not start on a simulator and I could not get the app
to surface a reason there. It needs a physical device before it can be
claimed. Android voice notes ARE verified — recorded and delivered, 29s.

---

**One design system, for real this time.** Theme.kt already claimed to be
"matched to the iOS client's Theme.swift so the two apps look like the same
product" while iOS was indigo and Android was ember. Nothing checks that
claim, so it had been false for a while. Ember wins — the product is called
Flamenet.

Both files now carry the same palette under the same names, plus a shared
scale for radii, spacing, elevation and type, as hex literals that can be
compared by eye across the two. Light parchment ground, white cards, one soft
shadow, one accent.

Applied to the Android home screen: each section on its own card. The sections
themselves are untouched — same composables, same testTags, same order —
because this is a skin over screens that work.

⚠️ The contacts card is height-bounded on purpose. BuddyList's LazyColumn
carries weight(1f), which used to resolve against the whole signed-in column;
inside a card with no height of its own it resolved against infinity, grew to
fill the screen, and pushed Groups and the tab bar off the bottom.

Also: tapRow now scrolls before declaring a settings row missing. A List does
not instantiate cells below the fold, so "Privacy & Security" was correctly
absent and read as a deleted feature.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 21:36:52 -04:00
..