perf(feeds): remember isSensitive and content warning reasons per note

These derivations iterate every tag and parse every iMeta, so running
them on each recomposition churns through feed scrolls. Cache them in
remember(note) alongside the other per-note derivations.
This commit is contained in:
Claude
2026-04-19 14:47:20 +00:00
parent 60a56440d1
commit dcaa6607ea
5 changed files with 17 additions and 17 deletions
@@ -67,9 +67,9 @@ fun PictureDisplay(
nav: INav, nav: INav,
) { ) {
val event = (note.event as? PictureEvent) ?: return val event = (note.event as? PictureEvent) ?: return
val uri = note.toNostrUri() val uri = remember(note) { note.toNostrUri() }
val isSensitive = event.isSensitiveOrNSFW() val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
val reasons = collectContentWarningReasons(event) val reasons = remember(note) { collectContentWarningReasons(event) }
val images by val images by
remember(note) { remember(note) {
@@ -53,9 +53,9 @@ fun JustVideoDisplay(
val event = (videoEvent as? Event) ?: return val event = (videoEvent as? Event) ?: return
val imeta = videoEvent.imetaTags().getOrNull(0) ?: return val imeta = videoEvent.imetaTags().getOrNull(0) ?: return
val isSensitive = event.isSensitiveOrNSFW() val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
val reasons = collectContentWarningReasons(event) val reasons = remember(note) { collectContentWarningReasons(event) }
val isImage = imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url) val isImage = remember(note) { imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url) }
val content by val content by
remember(note) { remember(note) {
@@ -97,9 +97,9 @@ private fun PictureCardImage(
backgroundColor: MutableState<Color>, backgroundColor: MutableState<Color>,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
) { ) {
val uri = note.toNostrUri() val uri = remember(note) { note.toNostrUri() }
val isSensitive = event.isSensitiveOrNSFW() val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
val reasons = collectContentWarningReasons(event) val reasons = remember(note) { collectContentWarningReasons(event) }
val images by val images by
remember(note) { remember(note) {
@@ -103,9 +103,9 @@ private fun VideoCardImage(
val event = (event as? Event) ?: return val event = (event as? Event) ?: return
val imeta = videoEvent.imetaTags().getOrNull(0) ?: return val imeta = videoEvent.imetaTags().getOrNull(0) ?: return
val isSensitive = event.isSensitiveOrNSFW() val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
val reasons = collectContentWarningReasons(event) val reasons = remember(note) { collectContentWarningReasons(event) }
val isImage = imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url) val isImage = remember(note) { imeta.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(imeta.url) }
val content by val content by
remember(note) { remember(note) {
@@ -100,11 +100,11 @@ private fun FileHeaderCardImage(
) { ) {
val fullUrl = event.url() ?: return val fullUrl = event.url() ?: return
val isSensitive = event.isSensitiveOrNSFW() val isSensitive = remember(note) { event.isSensitiveOrNSFW() }
val reasons = collectContentWarningReasons(event) val reasons = remember(note) { collectContentWarningReasons(event) }
val isImage = event.mimeType()?.startsWith("image/") == true || RichTextParser.isImageUrl(fullUrl) val isImage = remember(note) { event.mimeType()?.startsWith("image/") == true || RichTextParser.isImageUrl(fullUrl) }
val blurHash = event.blurhash() val blurHash = remember(note) { event.blurhash() }
val dimensions = event.dimensions() val dimensions = remember(note) { event.dimensions() }
val content by remember(note) { val content by remember(note) {
val hash = event.hash() val hash = event.hash()