From fb099442a08c58a0aaf88f4735ddeca59a555b3b Mon Sep 17 00:00:00 2001 From: Paul Hitt Date: Wed, 26 Aug 2026 08:10:38 -0400 Subject: [PATCH] Stories verified, and errors stop blaming Contacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stories driven end to end on Android against relay.flamenet.io: Post opens the scoped photo picker, a selected image is encrypted and uploaded, it appears in the strip as "You", and opening it decrypts and renders the picture. Together with groups, that leaves iOS voice notes as the only feature still unverified — and that one needs a physical device, because a simulator has no audio input. ⚠️ **The screen has ONE error slot and it lived inside BuddyList**, so everything that failed anywhere reported itself underneath the Contacts heading. A rate-limited story post read as a contacts problem, which is how somebody ends up re-adding a contact to fix a story. It now renders at screen level, under the call banner, where it belongs to the screen rather than to one section of it. ⚠️ Worth knowing for later runs: the relay enforces per-account rate limits, and a session that has been driving both apps hard will hit them. "Too many attempts. Wait a few minutes." is the app reporting a real server response, not a bug — the story posted on the retry after the window cleared. Co-Authored-By: Claude Opus 5 --- .../kotlin/io/flamenet/messenger/app/ChatScreens.kt | 4 ---- .../io/flamenet/messenger/app/MainActivity.kt | 13 +++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt b/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt index e9eb87f..d63178f 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt @@ -140,10 +140,6 @@ fun ColumnScope.BuddyList(model: MessengerViewModel, phase: MessengerViewModel.P ) { Text("Add contact") } } - phase.error?.let { - Text(it, color = MaterialTheme.colorScheme.error, modifier = Modifier.testTag("error")) - } - if (phase.buddies.isEmpty()) { // Says what to do, not merely that there is nothing. An empty state // that only reports emptiness leaves the person stuck. diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt b/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt index ed95827..21cf7d8 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt @@ -318,6 +318,19 @@ private fun ColumnScope.SignedIn( // whatever screen somebody is on. CallBanner(model, phase) + // ⚠️ **Screen level, not inside Contacts.** There is ONE error slot shared + // by everything on this screen, and it used to be rendered inside + // BuddyList — so a story that failed to post, or a group that could not be + // created, appeared underneath the Contacts heading and read as a contacts + // problem. Observed with a rate-limited story post reported under Contacts. + phase.error?.let { + Text( + it, + color = MaterialTheme.colorScheme.error, + modifier = Modifier.testTag("error").padding(top = Space.sm), + ) + } + // Each section on its own card. ⚠️ The sections themselves are unchanged — // same composables, same testTags, same order — because this is a skin over // screens that work, and moving them would mean re-pointing the UI tests