Display content warning reason
This commit is contained in:
+56
-21
@@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonPadding
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.PaddingHorizontal12Modifier
|
import com.vitorpamplona.amethyst.ui.theme.PaddingHorizontal12Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason
|
||||||
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW
|
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -79,17 +80,9 @@ fun SensitivityWarning(
|
|||||||
) {
|
) {
|
||||||
val hasSensitiveContent = remember(event) { event.isSensitiveOrNSFW() }
|
val hasSensitiveContent = remember(event) { event.isSensitiveOrNSFW() }
|
||||||
|
|
||||||
SensitivityWarning(hasSensitiveContent, accountViewModel, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SensitivityWarning(
|
|
||||||
hasSensitiveContent: Boolean,
|
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
content: @Composable () -> Unit,
|
|
||||||
) {
|
|
||||||
if (hasSensitiveContent) {
|
if (hasSensitiveContent) {
|
||||||
SensitivityWarning(accountViewModel, content)
|
val reason = remember(event) { event.contentWarningReason() }
|
||||||
|
ObserveSensitivityWarning(reason, accountViewModel, content)
|
||||||
} else {
|
} else {
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@@ -97,6 +90,20 @@ fun SensitivityWarning(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SensitivityWarning(
|
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,
|
accountViewModel: AccountViewModel,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -106,7 +113,7 @@ fun SensitivityWarning(
|
|||||||
|
|
||||||
CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) {
|
CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) {
|
||||||
if (it) {
|
if (it) {
|
||||||
ContentWarningNote { showContentWarningNote = false }
|
ContentWarningNote(reason) { showContentWarningNote = false }
|
||||||
} else {
|
} else {
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@@ -117,12 +124,31 @@ fun SensitivityWarning(
|
|||||||
@Composable
|
@Composable
|
||||||
fun ContentWarningNotePreview() {
|
fun ContentWarningNotePreview() {
|
||||||
ThemeComparisonColumn {
|
ThemeComparisonColumn {
|
||||||
ContentWarningNote {}
|
ContentWarningNote(null) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ContentWarningNoteWithReasonPreview() {
|
||||||
|
ThemeComparisonColumn {
|
||||||
|
ContentWarningNote("Spoilers") {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ContentWarningNoteWithBigReasonPreview() {
|
||||||
|
ThemeComparisonColumn {
|
||||||
|
ContentWarningNote("Spoilers, monkeys, bannanas, and other things") {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ContentWarningNote(onDismiss: () -> Unit) {
|
fun ContentWarningNote(
|
||||||
|
reason: String?,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
) {
|
||||||
Column {
|
Column {
|
||||||
Row(modifier = PaddingHorizontal12Modifier) {
|
Row(modifier = PaddingHorizontal12Modifier) {
|
||||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||||
@@ -155,19 +181,28 @@ fun ContentWarningNote(onDismiss: () -> Unit) {
|
|||||||
|
|
||||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||||
Text(
|
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,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
|
softWrap = true,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
if (reason.isNullOrBlank()) {
|
||||||
Text(
|
Row {
|
||||||
text = stringRes(R.string.content_warning_explanation),
|
Text(
|
||||||
color = Color.Gray,
|
text = stringRes(R.string.content_warning_explanation),
|
||||||
modifier = Modifier.padding(top = 10.dp),
|
color = Color.Gray,
|
||||||
textAlign = TextAlign.Center,
|
modifier = Modifier.padding(top = 10.dp),
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||||
|
|||||||
+2
-2
@@ -140,7 +140,7 @@ fun ZoomableContentView(
|
|||||||
|
|
||||||
when (content) {
|
when (content) {
|
||||||
is MediaUrlImage -> {
|
is MediaUrlImage -> {
|
||||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
SensitivityWarning(content.contentWarning, accountViewModel) {
|
||||||
TwoSecondController(content) { controllerVisible ->
|
TwoSecondController(content) { controllerVisible ->
|
||||||
val mainImageModifier =
|
val mainImageModifier =
|
||||||
Modifier
|
Modifier
|
||||||
@@ -153,7 +153,7 @@ fun ZoomableContentView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is MediaUrlVideo -> {
|
is MediaUrlVideo -> {
|
||||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
SensitivityWarning(content.contentWarning, accountViewModel) {
|
||||||
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||||
VideoView(
|
VideoView(
|
||||||
videoUri = content.url,
|
videoUri = content.url,
|
||||||
|
|||||||
+7
-4
@@ -171,10 +171,13 @@ fun GalleryContentView(
|
|||||||
AutoNonlazyGrid(contentList.size, modifier = Modifier.fillMaxSize()) { contentIndex ->
|
AutoNonlazyGrid(contentList.size, modifier = Modifier.fillMaxSize()) { contentIndex ->
|
||||||
when (val content = contentList[contentIndex]) {
|
when (val content = contentList[contentIndex]) {
|
||||||
is MediaUrlContent -> {
|
is MediaUrlContent -> {
|
||||||
val hasSensitiveContent =
|
val sensitivityReason =
|
||||||
(content is MediaUrlVideo && content.contentWarning != null) ||
|
when (content) {
|
||||||
(content is MediaUrlImage && content.contentWarning != null)
|
is MediaUrlVideo -> content.contentWarning
|
||||||
SensitivityWarning(hasSensitiveContent, accountViewModel) {
|
is MediaUrlImage -> content.contentWarning
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
SensitivityWarning(sensitivityReason, accountViewModel) {
|
||||||
UrlImageView(content, accountViewModel)
|
UrlImageView(content, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -743,6 +743,7 @@
|
|||||||
<string name="today">Today</string>
|
<string name="today">Today</string>
|
||||||
|
|
||||||
<string name="content_warning">Content warning</string>
|
<string name="content_warning">Content warning</string>
|
||||||
|
<string name="content_warning_with_reason">Warning: %1$s</string>
|
||||||
<string name="content_warning_explanation">This post contains sensitive content which some people may find offensive or disturbing</string>
|
<string name="content_warning_explanation">This post contains sensitive content which some people may find offensive or disturbing</string>
|
||||||
<string name="content_warning_hide_all_sensitive_content">Always hide sensitive content</string>
|
<string name="content_warning_hide_all_sensitive_content">Always hide sensitive content</string>
|
||||||
<string name="content_warning_show_all_sensitive_content">Always show sensitive content</string>
|
<string name="content_warning_show_all_sensitive_content">Always show sensitive content</string>
|
||||||
|
|||||||
+4
-3
@@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip36SensitiveContent
|
|||||||
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
class ContentWarningTag(
|
class ContentWarningTag(
|
||||||
val reason: String? = null,
|
val reason: String? = null,
|
||||||
@@ -33,9 +34,9 @@ class ContentWarningTag(
|
|||||||
|
|
||||||
fun isTag(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun isTag(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
||||||
|
|
||||||
fun parse(tags: Array<String>): ContentWarningTag {
|
fun parse(tags: Array<String>): ContentWarningTag? {
|
||||||
require(tags[0] == TAG_NAME)
|
ensure(tags[0] == TAG_NAME) { return null }
|
||||||
return ContentWarningTag(tags.getOrNull(1))
|
return ContentWarningTag(tags.getOrNull(1).ifBlank { null })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assemble() = arrayOfNotNull(TAG_NAME)
|
fun assemble() = arrayOfNotNull(TAG_NAME)
|
||||||
|
|||||||
+1
-1
@@ -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.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
|
||||||
|
|||||||
Reference in New Issue
Block a user