perf(note types): cache event-derived values and hoist static modifiers
Reduce per-recomposition allocation cost for note rows that render inside
LazyColumn feeds:
- AudioTrack: add `noteEvent` keys to `remember` for media/cover/subject/
participants/waveform/content so the cached values invalidate when the
underlying event changes
- Classifieds: wrap `imageMetas().map { MediaUrlImage(...) }`, title,
summary, price and location in `remember(noteEvent)` so they aren't
recomputed on every recomposition; hoist the static price-tag modifier
to a top-level `val`
- Report: collapse the per-recomposition `map { stringRes(...) }` chain
into a single `remember(reportTypes, noteEvent)` over a deduplicated
set of report types, and key the `base` collection by `noteEvent`
- Highlight: key the URL-parse `remember` by `url` so it actually
re-validates when the parameter changes
- PrivateMessage: key `remember { noteEvent.with(...) }` by `noteEvent`,
drop the silly `remember { Modifier.fillMaxWidth() }` wrapper, and
key `isLoggedUser` by `note.author` instead of `note.event?.id`
- PictureDisplay / FileHeader / Video: drop the unnecessary
`mutableStateOf(...)` wrap inside `remember` blocks that produce
immutable `BaseMediaContent` values; cache `images.map { it.url }`
preload list, and key `title`/`summary`/`image`/`isYouTube` by event
- Poll: add the missing `it.label` and `card` keys to `remember` blocks
that derive booleans from those parameters
- MeetingSpace: hoist the three `MeetingSpace*Flag` modifier chains to
top-level `val`s instead of allocating them each composition
This commit is contained in:
@@ -80,10 +80,10 @@ fun AudioTrackHeader(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val media = remember { noteEvent.media() }
|
val media = remember(noteEvent) { noteEvent.media() }
|
||||||
val cover = remember { noteEvent.cover() }
|
val cover = remember(noteEvent) { noteEvent.cover() }
|
||||||
val subject = remember { noteEvent.subject() }
|
val subject = remember(noteEvent) { noteEvent.subject() }
|
||||||
val participants = remember { noteEvent.participants() }
|
val participants = remember(noteEvent) { noteEvent.participants() }
|
||||||
|
|
||||||
var participantUsers by remember { mutableStateOf<List<Pair<ParticipantTag, User>>>(emptyList()) }
|
var participantUsers by remember { mutableStateOf<List<Pair<ParticipantTag, User>>>(emptyList()) }
|
||||||
|
|
||||||
@@ -183,9 +183,9 @@ fun AudioHeader(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val media = remember { noteEvent.stream() ?: noteEvent.download() }
|
val media = remember(noteEvent) { noteEvent.stream() ?: noteEvent.download() }
|
||||||
val waveform = remember { noteEvent.wavefrom()?.let { WaveformData(it.wave) } }
|
val waveform = remember(noteEvent) { noteEvent.wavefrom()?.let { WaveformData(it.wave) } }
|
||||||
val content = remember { noteEvent.content.ifBlank { null } }
|
val content = remember(noteEvent) { noteEvent.content.ifBlank { null } }
|
||||||
|
|
||||||
val defaultBackground = MaterialTheme.colorScheme.background
|
val defaultBackground = MaterialTheme.colorScheme.background
|
||||||
val background = remember { mutableStateOf(defaultBackground) }
|
val background = remember { mutableStateOf(defaultBackground) }
|
||||||
|
|||||||
@@ -51,8 +51,14 @@ import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.SmallBorder
|
import com.vitorpamplona.amethyst.ui.theme.SmallBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||||
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
private val PriceTagModifier =
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.padding(start = 5.dp)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RenderClassifieds(
|
fun RenderClassifieds(
|
||||||
noteEvent: ClassifiedsEvent,
|
noteEvent: ClassifiedsEvent,
|
||||||
@@ -60,23 +66,31 @@ fun RenderClassifieds(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val imageSet =
|
val imageSet: ImmutableList<MediaUrlImage>? =
|
||||||
noteEvent.imageMetas().ifEmpty { null }?.map {
|
remember(noteEvent) {
|
||||||
MediaUrlImage(
|
noteEvent
|
||||||
url = it.url,
|
.imageMetas()
|
||||||
description = it.alt,
|
.ifEmpty { null }
|
||||||
hash = it.hash,
|
?.map {
|
||||||
blurhash = it.blurhash,
|
MediaUrlImage(
|
||||||
dim = it.dimension,
|
url = it.url,
|
||||||
uri = note.toNostrUri(),
|
description = it.alt,
|
||||||
mimeType = it.mimeType,
|
hash = it.hash,
|
||||||
thumbhash = it.thumbhash,
|
blurhash = it.blurhash,
|
||||||
)
|
dim = it.dimension,
|
||||||
|
uri = note.toNostrUri(),
|
||||||
|
mimeType = it.mimeType,
|
||||||
|
thumbhash = it.thumbhash,
|
||||||
|
)
|
||||||
|
}?.toImmutableList()
|
||||||
}
|
}
|
||||||
val title = noteEvent.title()
|
val title = remember(noteEvent) { noteEvent.title() }
|
||||||
val summary = noteEvent.summary() ?: noteEvent.content.take(200).ifBlank { null }
|
val summary =
|
||||||
val price = noteEvent.price()
|
remember(noteEvent) {
|
||||||
val location = noteEvent.location()
|
noteEvent.summary() ?: noteEvent.content.take(200).ifBlank { null }
|
||||||
|
}
|
||||||
|
val price = remember(noteEvent) { noteEvent.price() }
|
||||||
|
val location = remember(noteEvent) { noteEvent.location() }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -94,7 +108,7 @@ fun RenderClassifieds(
|
|||||||
AutoNonlazyGrid(images.size) {
|
AutoNonlazyGrid(images.size) {
|
||||||
ZoomableContentView(
|
ZoomableContentView(
|
||||||
content = images[it],
|
content = images[it],
|
||||||
images = images.toImmutableList(),
|
images = images,
|
||||||
roundedCorner = false,
|
roundedCorner = false,
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
@@ -140,12 +154,7 @@ fun RenderClassifieds(
|
|||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier =
|
modifier = PriceTagModifier,
|
||||||
remember {
|
|
||||||
Modifier
|
|
||||||
.clip(SmallBorder)
|
|
||||||
.padding(start = 5.dp)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.note.types
|
package com.vitorpamplona.amethyst.ui.note.types
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent
|
import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent
|
||||||
@@ -46,7 +44,7 @@ fun FileHeaderDisplay(
|
|||||||
val event = (note.event as? FileHeaderEvent) ?: return
|
val event = (note.event as? FileHeaderEvent) ?: return
|
||||||
val fullUrl = event.url() ?: return
|
val fullUrl = event.url() ?: return
|
||||||
|
|
||||||
val content by
|
val content: BaseMediaContent =
|
||||||
remember(note) {
|
remember(note) {
|
||||||
val blurHash = event.blurhash()
|
val blurHash = event.blurhash()
|
||||||
val thumbHash = event.thumbhash()
|
val thumbHash = event.thumbhash()
|
||||||
@@ -57,32 +55,30 @@ fun FileHeaderDisplay(
|
|||||||
val uri = note.toNostrUri()
|
val uri = note.toNostrUri()
|
||||||
val mimeType = event.mimeType()
|
val mimeType = event.mimeType()
|
||||||
|
|
||||||
mutableStateOf<BaseMediaContent>(
|
if (isImage) {
|
||||||
if (isImage) {
|
MediaUrlImage(
|
||||||
MediaUrlImage(
|
url = fullUrl,
|
||||||
url = fullUrl,
|
description = description,
|
||||||
description = description,
|
hash = hash,
|
||||||
hash = hash,
|
blurhash = blurHash,
|
||||||
blurhash = blurHash,
|
dim = dimensions,
|
||||||
dim = dimensions,
|
uri = uri,
|
||||||
uri = uri,
|
mimeType = mimeType,
|
||||||
mimeType = mimeType,
|
thumbhash = thumbHash,
|
||||||
thumbhash = thumbHash,
|
)
|
||||||
)
|
} else {
|
||||||
} else {
|
MediaUrlVideo(
|
||||||
MediaUrlVideo(
|
url = fullUrl,
|
||||||
url = fullUrl,
|
description = description,
|
||||||
description = description,
|
hash = hash,
|
||||||
hash = hash,
|
blurhash = blurHash,
|
||||||
blurhash = blurHash,
|
dim = dimensions,
|
||||||
dim = dimensions,
|
uri = uri,
|
||||||
uri = uri,
|
authorName = note.author?.toBestDisplayName(),
|
||||||
authorName = note.author?.toBestDisplayName(),
|
mimeType = mimeType,
|
||||||
mimeType = mimeType,
|
thumbhash = thumbHash,
|
||||||
thumbhash = thumbHash,
|
)
|
||||||
)
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SensitivityWarning(note = note, accountViewModel = accountViewModel) {
|
SensitivityWarning(note = note, accountViewModel = accountViewModel) {
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ fun DisplayEntryForAUrl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val validatedUrl =
|
val validatedUrl =
|
||||||
remember {
|
remember(url) {
|
||||||
try {
|
try {
|
||||||
URL(url)
|
URL(url)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
|
|||||||
@@ -278,6 +278,24 @@ private fun RenderParticipants(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MeetingSpaceOpenModifier =
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.background(Color(0xFF4CAF50))
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
|
||||||
|
private val MeetingSpacePrivateModifier =
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.background(Color(0xFFFF9800))
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
|
||||||
|
private val MeetingSpaceClosedModifier =
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.background(Color.Black)
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MeetingSpaceOpenFlag() {
|
fun MeetingSpaceOpenFlag() {
|
||||||
Text(
|
Text(
|
||||||
@@ -285,13 +303,7 @@ fun MeetingSpaceOpenFlag() {
|
|||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
modifier =
|
modifier = MeetingSpaceOpenModifier,
|
||||||
remember {
|
|
||||||
Modifier
|
|
||||||
.clip(SmallBorder)
|
|
||||||
.background(Color(0xFF4CAF50))
|
|
||||||
.padding(horizontal = 5.dp)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,13 +314,7 @@ fun MeetingSpacePrivateFlag() {
|
|||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
modifier =
|
modifier = MeetingSpacePrivateModifier,
|
||||||
remember {
|
|
||||||
Modifier
|
|
||||||
.clip(SmallBorder)
|
|
||||||
.background(Color(0xFFFF9800))
|
|
||||||
.padding(horizontal = 5.dp)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,12 +325,6 @@ fun MeetingSpaceClosedFlag() {
|
|||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
modifier =
|
modifier = MeetingSpaceClosedModifier,
|
||||||
remember {
|
|
||||||
Modifier
|
|
||||||
.clip(SmallBorder)
|
|
||||||
.background(Color.Black)
|
|
||||||
.padding(horizontal = 5.dp)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -71,30 +69,29 @@ fun PictureDisplay(
|
|||||||
val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
|
val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
|
||||||
val reasons = remember(note) { collectContentWarningReasons(event) }
|
val reasons = remember(note) { collectContentWarningReasons(event) }
|
||||||
|
|
||||||
val images by
|
val images =
|
||||||
remember(note) {
|
remember(note) {
|
||||||
mutableStateOf(
|
event
|
||||||
event
|
.imetaTags()
|
||||||
.imetaTags()
|
.map {
|
||||||
.map {
|
MediaUrlImage(
|
||||||
MediaUrlImage(
|
url = it.url,
|
||||||
url = it.url,
|
description = it.alt,
|
||||||
description = it.alt,
|
hash = it.hash,
|
||||||
hash = it.hash,
|
blurhash = it.blurhash,
|
||||||
blurhash = it.blurhash,
|
dim = it.dimension,
|
||||||
dim = it.dimension,
|
uri = uri,
|
||||||
uri = uri,
|
mimeType = it.mimeType,
|
||||||
mimeType = it.mimeType,
|
thumbhash = it.thumbhash,
|
||||||
thumbhash = it.thumbhash,
|
)
|
||||||
)
|
}.toImmutableList()
|
||||||
}.toImmutableList(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val first = images.firstOrNull()
|
val first = images.firstOrNull()
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
val title = event.title()
|
val title = remember(event) { event.title() }
|
||||||
|
val preloadUrls = remember(images) { images.map { it.url } }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
@@ -114,7 +111,7 @@ fun PictureDisplay(
|
|||||||
ContentWarningGate(
|
ContentWarningGate(
|
||||||
isSensitive = isSensitive,
|
isSensitive = isSensitive,
|
||||||
reasons = reasons,
|
reasons = reasons,
|
||||||
preloadUrls = listOf(first.url),
|
preloadUrls = preloadUrls,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
modifier = mediaSizingModifier(ratio, ContentScale.FillWidth),
|
modifier = mediaSizingModifier(ratio, ContentScale.FillWidth),
|
||||||
backdrop = (first.thumbhash ?: first.blurhash)?.let { { BlurhashBackdrop(first.blurhash, first.description, first.thumbhash) } },
|
backdrop = (first.thumbhash ?: first.blurhash)?.let { { BlurhashBackdrop(first.blurhash, first.description, first.thumbhash) } },
|
||||||
@@ -131,7 +128,7 @@ fun PictureDisplay(
|
|||||||
ContentWarningGate(
|
ContentWarningGate(
|
||||||
isSensitive = isSensitive,
|
isSensitive = isSensitive,
|
||||||
reasons = reasons,
|
reasons = reasons,
|
||||||
preloadUrls = images.map { it.url },
|
preloadUrls = preloadUrls,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
modifier = Modifier.fillMaxWidth().aspectRatio(1f),
|
modifier = Modifier.fillMaxWidth().aspectRatio(1f),
|
||||||
backdrop = { BlurhashGridBackdrop(images) },
|
backdrop = { BlurhashGridBackdrop(images) },
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ private fun ColumnScope.RenderSingleChoiceOptions(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
val hasSpaceToClick =
|
val hasSpaceToClick =
|
||||||
remember {
|
remember(it.label) {
|
||||||
it.label.contains(' ') || it.label.contains('\n')
|
it.label.contains(' ') || it.label.contains('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ private fun RenderResults(
|
|||||||
labelContent: @Composable (ColumnScope.(code: String, label: String) -> Unit),
|
labelContent: @Composable (ColumnScope.(code: String, label: String) -> Unit),
|
||||||
) {
|
) {
|
||||||
val showGallery =
|
val showGallery =
|
||||||
remember {
|
remember(card) {
|
||||||
card.options.all {
|
card.options.all {
|
||||||
it.label.length < 50
|
it.label.length < 50
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,11 @@ fun RenderPrivateMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val withMe = remember { noteEvent.with(accountViewModel.userProfile().pubkeyHex) }
|
val withMe = remember(noteEvent) { noteEvent.with(accountViewModel.userProfile().pubkeyHex) }
|
||||||
if (withMe) {
|
if (withMe) {
|
||||||
LoadDecryptedContent(note, accountViewModel) { eventContent ->
|
LoadDecryptedContent(note, accountViewModel) { eventContent ->
|
||||||
val modifier = remember(note.event?.id) { Modifier.fillMaxWidth() }
|
|
||||||
val isAuthorTheLoggedUser =
|
val isAuthorTheLoggedUser =
|
||||||
remember(note.event?.id) { accountViewModel.isLoggedUser(note.author) }
|
remember(note.author) { accountViewModel.isLoggedUser(note.author) }
|
||||||
|
|
||||||
val tags =
|
val tags =
|
||||||
remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList }
|
remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList }
|
||||||
@@ -113,7 +112,7 @@ fun RenderPrivateMessage(
|
|||||||
content = eventContent,
|
content = eventContent,
|
||||||
canPreview = canPreview && !makeItShort,
|
canPreview = canPreview && !makeItShort,
|
||||||
quotesLeft = quotesLeft,
|
quotesLeft = quotesLeft,
|
||||||
modifier = modifier,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
tags = tags,
|
tags = tags,
|
||||||
backgroundColor = backgroundColor,
|
backgroundColor = backgroundColor,
|
||||||
id = note.idHex,
|
id = note.idHex,
|
||||||
|
|||||||
@@ -48,35 +48,43 @@ fun RenderReport(
|
|||||||
) {
|
) {
|
||||||
val noteEvent = note.event as? ReportEvent ?: return
|
val noteEvent = note.event as? ReportEvent ?: return
|
||||||
|
|
||||||
val base = remember { (noteEvent.reportedPost() + noteEvent.reportedAuthor()) }
|
val reportTypes =
|
||||||
|
remember(noteEvent) {
|
||||||
|
(noteEvent.reportedPost() + noteEvent.reportedAuthor())
|
||||||
|
.mapTo(LinkedHashSet()) { it.type }
|
||||||
|
}
|
||||||
|
|
||||||
val reportType =
|
val explicitContent = stringRes(R.string.explicit_content)
|
||||||
base
|
val nudity = stringRes(R.string.nudity)
|
||||||
.map {
|
val profanity = stringRes(R.string.profanity_hateful_speech)
|
||||||
when (it.type) {
|
val spam = stringRes(R.string.spam)
|
||||||
ReportType.EXPLICIT -> stringRes(R.string.explicit_content)
|
val impersonation = stringRes(R.string.impersonation)
|
||||||
ReportType.NUDITY -> stringRes(R.string.nudity)
|
val illegal = stringRes(R.string.illegal_behavior)
|
||||||
ReportType.PROFANITY -> stringRes(R.string.profanity_hateful_speech)
|
val malware = stringRes(R.string.malware)
|
||||||
ReportType.SPAM -> stringRes(R.string.spam)
|
val other = stringRes(R.string.other)
|
||||||
ReportType.IMPERSONATION -> stringRes(R.string.impersonation)
|
val harassment = stringRes(R.string.harassment)
|
||||||
ReportType.ILLEGAL -> stringRes(R.string.illegal_behavior)
|
val violence = stringRes(R.string.violence)
|
||||||
ReportType.MALWARE -> stringRes(R.string.malware)
|
|
||||||
ReportType.OTHER -> stringRes(R.string.other)
|
|
||||||
ReportType.HARASSMENT -> stringRes(R.string.harassment)
|
|
||||||
ReportType.VIOLENCE -> stringRes(R.string.violence)
|
|
||||||
null -> stringRes(R.string.other)
|
|
||||||
}
|
|
||||||
}.toSet()
|
|
||||||
.joinToString(", ")
|
|
||||||
|
|
||||||
val content =
|
val content =
|
||||||
remember {
|
remember(reportTypes, noteEvent) {
|
||||||
reportType + (
|
val reportTypeText =
|
||||||
note.event
|
reportTypes.joinToString(", ") {
|
||||||
?.content
|
when (it) {
|
||||||
?.ifBlank { null }
|
ReportType.EXPLICIT -> explicitContent
|
||||||
?.let { ": $it" } ?: ""
|
ReportType.NUDITY -> nudity
|
||||||
)
|
ReportType.PROFANITY -> profanity
|
||||||
|
ReportType.SPAM -> spam
|
||||||
|
ReportType.IMPERSONATION -> impersonation
|
||||||
|
ReportType.ILLEGAL -> illegal
|
||||||
|
ReportType.MALWARE -> malware
|
||||||
|
ReportType.OTHER -> other
|
||||||
|
ReportType.HARASSMENT -> harassment
|
||||||
|
ReportType.VIOLENCE -> violence
|
||||||
|
null -> other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val extra = noteEvent.content.ifBlank { null }?.let { ": $it" } ?: ""
|
||||||
|
reportTypeText + extra
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslatableRichTextViewer(
|
TranslatableRichTextViewer(
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -81,45 +79,43 @@ fun VideoDisplay(
|
|||||||
|
|
||||||
val imeta = videoEvent.imetaTags().firstOrNull() ?: return
|
val imeta = videoEvent.imetaTags().firstOrNull() ?: return
|
||||||
|
|
||||||
val title = videoEvent.title()
|
val title = remember(videoEvent) { videoEvent.title() }
|
||||||
val summary = videoEvent.content.ifBlank { null }?.takeIf { title != it }
|
val summary = remember(videoEvent, title) { videoEvent.content.ifBlank { null }?.takeIf { title != it } }
|
||||||
val image = imeta.image.firstOrNull()
|
val image = remember(imeta) { imeta.image.firstOrNull() }
|
||||||
val isYouTube = imeta.url.contains("youtube.com") || imeta.url.contains("youtu.be")
|
val isYouTube = remember(imeta) { imeta.url.contains("youtube.com") || imeta.url.contains("youtu.be") }
|
||||||
val tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList }
|
val tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList }
|
||||||
|
|
||||||
val content by
|
val content: BaseMediaContent =
|
||||||
remember(note) {
|
remember(note) {
|
||||||
val description = videoEvent.content.ifBlank { null } ?: event.alt()
|
val description = videoEvent.content.ifBlank { null } ?: event.alt()
|
||||||
val isImage = imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url)
|
val isImage = imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url)
|
||||||
val uri = note.toNostrUri()
|
val uri = note.toNostrUri()
|
||||||
|
|
||||||
mutableStateOf<BaseMediaContent>(
|
if (isImage) {
|
||||||
if (isImage) {
|
MediaUrlImage(
|
||||||
MediaUrlImage(
|
url = imeta.url,
|
||||||
url = imeta.url,
|
description = description,
|
||||||
description = description,
|
hash = imeta.hash,
|
||||||
hash = imeta.hash,
|
blurhash = imeta.blurhash,
|
||||||
blurhash = imeta.blurhash,
|
dim = imeta.dimension,
|
||||||
dim = imeta.dimension,
|
uri = uri,
|
||||||
uri = uri,
|
mimeType = imeta.mimeType,
|
||||||
mimeType = imeta.mimeType,
|
thumbhash = imeta.thumbhash,
|
||||||
thumbhash = imeta.thumbhash,
|
)
|
||||||
)
|
} else {
|
||||||
} else {
|
MediaUrlVideo(
|
||||||
MediaUrlVideo(
|
url = imeta.url,
|
||||||
url = imeta.url,
|
description = description,
|
||||||
description = description,
|
hash = imeta.hash,
|
||||||
hash = imeta.hash,
|
dim = imeta.dimension,
|
||||||
dim = imeta.dimension,
|
uri = uri,
|
||||||
uri = uri,
|
authorName = note.author?.toBestDisplayName(),
|
||||||
authorName = note.author?.toBestDisplayName(),
|
artworkUri = imeta.image.firstOrNull(),
|
||||||
artworkUri = imeta.image.firstOrNull(),
|
mimeType = imeta.mimeType,
|
||||||
mimeType = imeta.mimeType,
|
blurhash = imeta.blurhash,
|
||||||
blurhash = imeta.blurhash,
|
thumbhash = imeta.thumbhash,
|
||||||
thumbhash = imeta.thumbhash,
|
)
|
||||||
)
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SensitivityWarning(note = note, accountViewModel = accountViewModel) {
|
SensitivityWarning(note = note, accountViewModel = accountViewModel) {
|
||||||
|
|||||||
Reference in New Issue
Block a user