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 ee736d3..e58fffc 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/ChatScreens.kt @@ -4096,7 +4096,13 @@ private fun EditMessageSheet( * to somebody who may do nothing. */ @Composable -private fun ReportSheet( +/** + * ⚠️ Was `private` to this file, which is why the stories feed could not use + * it and Android had no way to report a story at all. Widened rather than + * copied: two report sheets would be two places for the consent wording to + * drift apart, and the consent is the part that matters. + */ +internal fun ReportSheet( authorName: String, preview: String, onDismiss: () -> Unit, diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/StoriesFeed.kt b/app/src/main/kotlin/io/flamenet/messenger/app/StoriesFeed.kt index 7e7c067..97baa14 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/StoriesFeed.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/StoriesFeed.kt @@ -238,7 +238,7 @@ private fun StoryCard( } Spacer(Modifier.height(Space.md)) - StoryActions(story, model) + StoryActions(story, model, authorName = author) } } @@ -253,10 +253,18 @@ private fun StoryCard( * a row of buttons that do nothing is worse than no row. */ @Composable -private fun StoryActions(story: Vault.Story, model: MessengerViewModel) { +private fun StoryActions( + story: Vault.Story, + model: MessengerViewModel, + // ⚠️ Passed in rather than resolved here: `StoryCard` already has the + // buddy list and has already done this, and two resolutions of the same + // name are two chances to disagree about who is being reported. + authorName: String = "", +) { val quick = listOf("❤️", "😂", "😮", "😢", "🔥") var replying by remember { mutableStateOf(false) } var muting by remember { mutableStateOf(false) } + var reporting by remember { mutableStateOf(false) } if (story.mine) { val tally = model.storyTally(story.id) @@ -298,6 +306,41 @@ private fun StoryActions(story: Vault.Story, model: MessengerViewModel) { Spacer(Modifier.size(12.dp)) Text("Mute", fontSize = 13.sp, color = Palette.Mist, modifier = Modifier.clickable { muting = true }.testTag("story-mute")) + // 🔴 **Reporting a story, which Android could not do.** iOS has had it + // since stories shipped; here `MessengerViewModel.reportStory` was + // written, tested by nothing, and called by no screen. A capability + // with no way in is, for Apple's Guideline 1.2 and Play's UGC policy, + // the same as no capability — and a story is the most public thing + // this app carries, so it is the surface those rules are aimed at. + // + // ⚠️ Not on your own story. Reporting yourself to the operator is not + // something anybody means to do, and offering it invites a misfire. + if (!story.mine) { + Spacer(Modifier.size(12.dp)) + Text("Report", fontSize = 13.sp, color = Palette.Mist, + modifier = Modifier.clickable { reporting = true } + .testTag("story-report")) + } + } + + if (reporting) { + // ⚠️ The SAME sheet a message report uses, deliberately. Two sheets + // would be two places for the consent wording to drift apart, and the + // consent — that sending a copy hands the operator something readable — + // is the part that matters. + ReportSheet( + authorName = authorName.ifBlank { "this person" }, + preview = story.caption, + onDismiss = { reporting = false }, + onSend = { reason, includeContent, note -> + model.reportStory(story, reason, includeContent, note) + reporting = false + }, + onBlock = { + model.setBlocked(story.authorId, true) + reporting = false + }, + ) } if (replying) {