diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt index 4b7e59b38..29eb4d8a1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt @@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.PaddingHorizontal12Modifier import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW @Composable @@ -79,17 +80,9 @@ fun SensitivityWarning( ) { val hasSensitiveContent = remember(event) { event.isSensitiveOrNSFW() } - SensitivityWarning(hasSensitiveContent, accountViewModel, content) -} - -@Composable -fun SensitivityWarning( - hasSensitiveContent: Boolean, - accountViewModel: AccountViewModel, - content: @Composable () -> Unit, -) { if (hasSensitiveContent) { - SensitivityWarning(accountViewModel, content) + val reason = remember(event) { event.contentWarningReason() } + ObserveSensitivityWarning(reason, accountViewModel, content) } else { content() } @@ -97,6 +90,20 @@ fun SensitivityWarning( @Composable fun SensitivityWarning( + reason: String?, + accountViewModel: AccountViewModel, + content: @Composable () -> Unit, +) { + if (reason != null) { + ObserveSensitivityWarning(reason, accountViewModel, content) + } else { + content() + } +} + +@Composable +fun ObserveSensitivityWarning( + reason: String?, accountViewModel: AccountViewModel, content: @Composable () -> Unit, ) { @@ -106,7 +113,7 @@ fun SensitivityWarning( CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) { if (it) { - ContentWarningNote { showContentWarningNote = false } + ContentWarningNote(reason) { showContentWarningNote = false } } else { content() } @@ -117,12 +124,31 @@ fun SensitivityWarning( @Composable fun ContentWarningNotePreview() { ThemeComparisonColumn { - ContentWarningNote {} + ContentWarningNote(null) {} + } +} + +@Preview +@Composable +fun ContentWarningNoteWithReasonPreview() { + ThemeComparisonColumn { + ContentWarningNote("Spoilers") {} + } +} + +@Preview +@Composable +fun ContentWarningNoteWithBigReasonPreview() { + ThemeComparisonColumn { + ContentWarningNote("Spoilers, monkeys, bannanas, and other things") {} } } @Composable -fun ContentWarningNote(onDismiss: () -> Unit) { +fun ContentWarningNote( + reason: String?, + onDismiss: () -> Unit, +) { Column { Row(modifier = PaddingHorizontal12Modifier) { Column(modifier = Modifier.padding(start = 10.dp)) { @@ -155,19 +181,28 @@ fun ContentWarningNote(onDismiss: () -> Unit) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Text( - text = stringRes(R.string.content_warning), + text = + if (reason.isNullOrBlank()) { + stringRes(R.string.content_warning) + } else { + stringRes(R.string.content_warning_with_reason, reason) + }, fontWeight = FontWeight.Bold, fontSize = 18.sp, + softWrap = true, + textAlign = TextAlign.Center, ) } - Row { - Text( - text = stringRes(R.string.content_warning_explanation), - color = Color.Gray, - modifier = Modifier.padding(top = 10.dp), - textAlign = TextAlign.Center, - ) + if (reason.isNullOrBlank()) { + Row { + Text( + text = stringRes(R.string.content_warning_explanation), + color = Color.Gray, + modifier = Modifier.padding(top = 10.dp), + textAlign = TextAlign.Center, + ) + } } Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index f8cc1c82a..e998711ae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -140,7 +140,7 @@ fun ZoomableContentView( when (content) { is MediaUrlImage -> { - SensitivityWarning(content.contentWarning != null, accountViewModel) { + SensitivityWarning(content.contentWarning, accountViewModel) { TwoSecondController(content) { controllerVisible -> val mainImageModifier = Modifier @@ -153,7 +153,7 @@ fun ZoomableContentView( } is MediaUrlVideo -> { - SensitivityWarning(content.contentWarning != null, accountViewModel) { + SensitivityWarning(content.contentWarning, accountViewModel) { Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { VideoView( videoUri = content.url, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt index 2ab349bb5..b153ef37e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt @@ -171,10 +171,13 @@ fun GalleryContentView( AutoNonlazyGrid(contentList.size, modifier = Modifier.fillMaxSize()) { contentIndex -> when (val content = contentList[contentIndex]) { is MediaUrlContent -> { - val hasSensitiveContent = - (content is MediaUrlVideo && content.contentWarning != null) || - (content is MediaUrlImage && content.contentWarning != null) - SensitivityWarning(hasSensitiveContent, accountViewModel) { + val sensitivityReason = + when (content) { + is MediaUrlVideo -> content.contentWarning + is MediaUrlImage -> content.contentWarning + else -> null + } + SensitivityWarning(sensitivityReason, accountViewModel) { UrlImageView(content, accountViewModel) } } diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index c4b7440bf..799135f7d 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -743,6 +743,7 @@ Today Content warning + Warning: %1$s This post contains sensitive content which some people may find offensive or disturbing Always hide sensitive content Always show sensitive content diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt index 54ebe8424..af4214f66 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip36SensitiveContent import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.utils.arrayOfNotNull +import com.vitorpamplona.quartz.utils.ensure class ContentWarningTag( val reason: String? = null, @@ -33,9 +34,9 @@ class ContentWarningTag( fun isTag(tag: Array) = tag.has(0) && tag[0] == TAG_NAME - fun parse(tags: Array): ContentWarningTag { - require(tags[0] == TAG_NAME) - return ContentWarningTag(tags.getOrNull(1)) + fun parse(tags: Array): ContentWarningTag? { + ensure(tags[0] == TAG_NAME) { return null } + return ContentWarningTag(tags.getOrNull(1).ifBlank { null }) } fun assemble() = arrayOfNotNull(TAG_NAME) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt index a44200487..9251bb305 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt @@ -29,4 +29,4 @@ fun TagArray.isSensitive() = this.any(ContentWarningTag::isTag) fun TagArray.isSensitiveOrNSFW() = this.any { ContentWarningTag.isTag(it) || HashtagTag.isAnyTagged(it, nsfwTags) } -fun TagArray.contentWarningReason() = this.firstOrNull(ContentWarningTag::isTag)?.getOrNull(1) +fun TagArray.contentWarningReason() = this.firstNotNullOfOrNull(ContentWarningTag::parse)?.reason