From 45445c03e556f72746bc7ece83ecd88475d956e4 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 12 Jun 2024 16:54:39 -0400 Subject: [PATCH] - Merges Hidden and Reporting flows - Removes Report Live data - Refactors Full Bleed design - Unifies Hidden and Report checks between the Video Feed, the Full Bleed Design and the Card layout. --- .../com/vitorpamplona/amethyst/model/Note.kt | 18 +- .../amethyst/ui/note/BlockReportChecker.kt | 97 +-- .../amethyst/ui/note/ChannelCardCompose.kt | 30 +- .../amethyst/ui/note/NoteCompose.kt | 6 +- .../amethyst/ui/screen/ThreadFeedView.kt | 654 +++++++++--------- .../ui/screen/loggedIn/AccountViewModel.kt | 110 +-- .../ui/screen/loggedIn/VideoScreen.kt | 91 +-- 7 files changed, 432 insertions(+), 574 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 0e5f62e69..fe54cb03f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -258,7 +258,9 @@ open class Note( if (repliesChanged) liveSet?.innerReplies?.invalidateData() if (reactionsChanged) liveSet?.innerReactions?.invalidateData() if (boostsChanged) liveSet?.innerBoosts?.invalidateData() - if (reportsChanged) liveSet?.innerReports?.invalidateData() + if (reportsChanged) { + flowSet?.reports?.invalidateData() + } if (zapsChanged) liveSet?.innerZaps?.invalidateData() return toBeRemoved @@ -290,7 +292,7 @@ open class Note( if (reports[author]?.contains(deleteNote) == true) { reports[author]?.let { reports = reports + Pair(author, it.minus(deleteNote)) - liveSet?.innerReports?.invalidateData() + flowSet?.reports?.invalidateData() } } } @@ -399,10 +401,10 @@ open class Note( if (reportsByAuthor == null) { reports = reports + Pair(author, listOf(note)) - liveSet?.innerReports?.invalidateData() + flowSet?.reports?.invalidateData() } else if (!reportsByAuthor.contains(note)) { reports = reports + Pair(author, reportsByAuthor + note) - liveSet?.innerReports?.invalidateData() + flowSet?.reports?.invalidateData() } } @@ -844,11 +846,13 @@ class NoteFlowSet( ) { // Observers line up here. val metadata = NoteBundledRefresherFlow(u) + val reports = NoteBundledRefresherFlow(u) - fun isInUse(): Boolean = metadata.stateFlow.subscriptionCount.value > 0 + fun isInUse(): Boolean = metadata.stateFlow.subscriptionCount.value > 0 || reports.stateFlow.subscriptionCount.value > 0 fun destroy() { metadata.destroy() + reports.destroy() } } @@ -861,7 +865,6 @@ class NoteLiveSet( val innerReactions = NoteBundledRefresherLiveData(u) val innerBoosts = NoteBundledRefresherLiveData(u) val innerReplies = NoteBundledRefresherLiveData(u) - val innerReports = NoteBundledRefresherLiveData(u) val innerRelays = NoteBundledRefresherLiveData(u) val innerZaps = NoteBundledRefresherLiveData(u) val innerOts = NoteBundledRefresherLiveData(u) @@ -871,7 +874,6 @@ class NoteLiveSet( val reactions = innerReactions.map { it } val boosts = innerBoosts.map { it } val replies = innerReplies.map { it } - val reports = innerReports.map { it } val relays = innerRelays.map { it } val zaps = innerZaps.map { it } @@ -907,7 +909,6 @@ class NoteLiveSet( reactions.hasObservers() || boosts.hasObservers() || replies.hasObservers() || - reports.hasObservers() || relays.hasObservers() || zaps.hasObservers() || hasEvent.hasObservers() || @@ -923,7 +924,6 @@ class NoteLiveSet( innerReactions.destroy() innerBoosts.destroy() innerReplies.destroy() - innerReports.destroy() innerRelays.destroy() innerZaps.destroy() innerOts.destroy() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt index 11ff460d7..1bc61848b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt @@ -22,9 +22,7 @@ package com.vitorpamplona.amethyst.ui.note import androidx.compose.animation.Crossfade import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -38,12 +36,12 @@ fun CheckHiddenFeedWatchBlockAndReport( note: Note, modifier: Modifier = Modifier, showHiddenWarning: Boolean, - showHidden: Boolean = false, + ignoreAllBlocksAndReports: Boolean = false, accountViewModel: AccountViewModel, nav: (String) -> Unit, normalNote: @Composable (canPreview: Boolean) -> Unit, ) { - if (showHidden) { + if (ignoreAllBlocksAndReports) { // Ignores reports as well normalNote(true) } else { @@ -62,19 +60,28 @@ fun WatchBlockAndReport( nav: (String) -> Unit, normalNote: @Composable (canPreview: Boolean) -> Unit, ) { - val isHiddenState by accountViewModel.createIsHiddenFlow(note).collectAsStateWithLifecycle() + val hiddenState by accountViewModel.createIsHiddenFlow(note).collectAsStateWithLifecycle() val showAnyway = remember { mutableStateOf(false) } - Crossfade(targetState = isHiddenState, label = "CheckHiddenNoteCompose") { isHidden -> + Crossfade(targetState = hiddenState, label = "CheckHiddenNoteCompose") { isHidden -> if (showAnyway.value) { normalNote(true) - } else if (!isHidden) { - LoadReportsNoteCompose(note, modifier, accountViewModel, nav) { canPreview -> - normalNote(canPreview) + } else if (!isHidden.isPostHidden) { + if (isHidden.isAcceptable) { + normalNote(isHidden.canPreview) + } else { + HiddenNote( + isHidden.relevantReports, + isHidden.isHiddenAuthor, + accountViewModel, + modifier, + nav, + onClick = { showAnyway.value = true }, + ) } } else if (showHiddenWarning) { // if it is a quoted or boosted note, how the hidden warning. @@ -84,75 +91,3 @@ fun WatchBlockAndReport( } } } - -@Composable -private fun LoadReportsNoteCompose( - note: Note, - modifier: Modifier = Modifier, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, - normalNote: @Composable (canPreview: Boolean) -> Unit, -) { - var state by - remember(note) { - mutableStateOf( - AccountViewModel.NoteComposeReportState(), - ) - } - - WatchForReports(note, accountViewModel) { newState -> - if (state != newState) { - state = newState - } - } - - Crossfade(targetState = state, label = "LoadedNoteCompose") { - RenderReportState(state = it, note = note, modifier = modifier, accountViewModel = accountViewModel, nav = nav) { canPreview -> - normalNote(canPreview) - } - } -} - -@Composable -private fun RenderReportState( - state: AccountViewModel.NoteComposeReportState, - note: Note, - modifier: Modifier = Modifier, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, - normalNote: @Composable (canPreview: Boolean) -> Unit, -) { - var showReportedNote by remember(note) { mutableStateOf(false) } - - Crossfade(targetState = !state.isAcceptable && !showReportedNote, label = "RenderReportState") { showHiddenNote -> - if (showHiddenNote) { - HiddenNote( - state.relevantReports, - state.isHiddenAuthor, - accountViewModel, - modifier, - nav, - onClick = { showReportedNote = true }, - ) - } else { - val canPreview = (!state.isAcceptable && showReportedNote) || state.canPreview - - normalNote(canPreview) - } - } -} - -@Composable -fun WatchForReports( - note: Note, - accountViewModel: AccountViewModel, - onChange: (AccountViewModel.NoteComposeReportState) -> Unit, -) { - val userFollowsState by accountViewModel.userFollows.observeAsState() - val noteReportsState by note.live().reports.observeAsState() - val userBlocks by accountViewModel.account.flowHiddenUsers.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = noteReportsState, key2 = userFollowsState, userBlocks) { - accountViewModel.isNoteAcceptable(note, onChange) - } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index 4411ea761..bf2a68778 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -49,7 +49,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.BottomStart -import androidx.compose.ui.Alignment.Companion.Center import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Alignment.Companion.TopEnd import androidx.compose.ui.Modifier @@ -124,7 +123,7 @@ fun ChannelCardCompose( CheckHiddenFeedWatchBlockAndReport( note = baseNote, modifier = modifier, - showHidden = isHiddenFeed, + ignoreAllBlocksAndReports = isHiddenFeed, showHiddenWarning = false, accountViewModel = accountViewModel, nav = nav, @@ -308,8 +307,7 @@ fun RenderClassifiedsThumb( title = noteEvent?.title(), price = noteEvent?.price(), ) - } - .distinctUntilChanged() + }.distinctUntilChanged() .observeAsState( ClassifiedsThumb( image = noteEvent.image(), @@ -437,8 +435,7 @@ fun RenderLiveActivityThumb( status = noteEvent?.status(), starts = noteEvent?.starts(), ) - } - .distinctUntilChanged() + }.distinctUntilChanged() .observeAsState( LiveActivityCard( name = noteEvent.dTag(), @@ -567,8 +564,7 @@ fun RenderCommunitiesThumb( cover = noteEvent?.image()?.ifBlank { null }, moderators = noteEvent?.moderators()?.toImmutableList() ?: persistentListOf(), ) - } - .distinctUntilChanged() + }.distinctUntilChanged() .observeAsState( CommunityCard( name = noteEvent.dTag(), @@ -672,7 +668,9 @@ fun LoadModerators( } } - val followingKeySet = accountViewModel.account.liveDiscoveryFollowLists.value?.users + val followingKeySet = + accountViewModel.account.liveDiscoveryFollowLists.value + ?.users val allParticipants = ParticipantListBuilder().followsThatParticipateOn(baseNote, followingKeySet).minus(hosts) @@ -723,7 +721,9 @@ private fun LoadParticipants( val hostsAuthor = hosts + (baseNote.author?.let { listOf(it) } ?: emptyList()) - val followingKeySet = accountViewModel.account.liveDiscoveryFollowLists.value?.users + val followingKeySet = + accountViewModel.account.liveDiscoveryFollowLists.value + ?.users val allParticipants = ParticipantListBuilder() @@ -760,7 +760,11 @@ fun RenderContentDVMThumb( nav: (String) -> Unit, ) { // downloads user metadata to pre-load the NIP-65 relays. - val user = baseNote.author?.live()?.metadata?.observeAsState() + val user = + baseNote.author + ?.live() + ?.metadata + ?.observeAsState() val card = observeAppDefinition(appDefinitionNote = baseNote) @@ -875,7 +879,9 @@ fun RenderChannelThumb( LaunchedEffect(key1 = channelUpdates) { launch(Dispatchers.IO) { - val followingKeySet = accountViewModel.account.liveDiscoveryFollowLists.value?.users + val followingKeySet = + accountViewModel.account.liveDiscoveryFollowLists.value + ?.users val allParticipants = ParticipantListBuilder() .followsThatParticipateOn(baseNote, followingKeySet) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index dc102e7cd..fee6e852a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -204,7 +204,7 @@ fun NoteCompose( CheckHiddenFeedWatchBlockAndReport( note = baseNote, modifier = modifier, - showHidden = isHiddenFeed, + ignoreAllBlocksAndReports = isHiddenFeed, showHiddenWarning = isQuotedNote || isBoostedNote, accountViewModel = accountViewModel, nav = nav, @@ -264,9 +264,7 @@ fun AcceptableNote( } is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote) else -> - LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { - showPopup, - -> + LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> CheckNewAndRenderNote( baseNote = baseNote, routeForLastRead = routeForLastRead, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index dfbbde3a5..8542945a7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -36,11 +36,8 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProvideTextStyle @@ -49,9 +46,9 @@ import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -62,7 +59,6 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle @@ -85,19 +81,21 @@ import com.vitorpamplona.amethyst.ui.components.InlineCarrousel import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel +import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.navigation.routeToMessage -import com.vitorpamplona.amethyst.ui.note.BlankNote +import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport import com.vitorpamplona.amethyst.ui.note.DisplayDraft import com.vitorpamplona.amethyst.ui.note.DisplayOtsIfInOriginal -import com.vitorpamplona.amethyst.ui.note.HiddenNote import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.NoteQuickActionMenu import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay import com.vitorpamplona.amethyst.ui.note.ReactionsRow import com.vitorpamplona.amethyst.ui.note.RenderDraft import com.vitorpamplona.amethyst.ui.note.RenderRepost +import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader import com.vitorpamplona.amethyst.ui.note.elements.DisplayEditStatus import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingCommunityInPost @@ -107,15 +105,14 @@ import com.vitorpamplona.amethyst.ui.note.elements.DisplayPoW import com.vitorpamplona.amethyst.ui.note.elements.DisplayReward import com.vitorpamplona.amethyst.ui.note.elements.DisplayZapSplits import com.vitorpamplona.amethyst.ui.note.elements.ForkInformationRow -import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu +import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.ui.note.elements.Reward +import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.ui.note.observeEdits import com.vitorpamplona.amethyst.ui.note.showAmount -import com.vitorpamplona.amethyst.ui.note.timeAgo import com.vitorpamplona.amethyst.ui.note.types.AudioHeader import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay -import com.vitorpamplona.amethyst.ui.note.types.DisplayHighlight import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet import com.vitorpamplona.amethyst.ui.note.types.EditState @@ -128,6 +125,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent import com.vitorpamplona.amethyst.ui.note.types.RenderPoll @@ -144,8 +142,7 @@ import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.EditFieldBorder import com.vitorpamplona.amethyst.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.theme.Size15Modifier -import com.vitorpamplona.amethyst.ui.theme.Size24Modifier +import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.lessImportantLink @@ -184,7 +181,6 @@ import com.vitorpamplona.quartz.events.TextNoteModificationEvent import com.vitorpamplona.quartz.events.VideoEvent import com.vitorpamplona.quartz.events.WikiNoteEvent import kotlinx.collections.immutable.toImmutableList -import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -225,7 +221,10 @@ fun RenderThreadFeed( LaunchedEffect(noteId) { // waits to load the thread to scroll to item. delay(100) - val noteForPosition = state.feed.value.filter { it.idHex == noteId }.firstOrNull() + val noteForPosition = + state.feed.value + .filter { it.idHex == noteId } + .firstOrNull() var position = state.feed.value.indexOf(noteForPosition) if (position >= 0) { @@ -321,347 +320,314 @@ fun Modifier.drawReplyLevel( } return@drawBehind - } - .padding(start = (2 + (level * 3)).dp) + }.padding(start = (2 + (level * 3)).dp) @OptIn(ExperimentalFoundationApi::class) @Composable fun NoteMaster( baseNote: Note, modifier: Modifier = Modifier, + parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val noteState by baseNote.live().metadata.observeAsState() - val note = noteState?.note - - val noteReportsState by baseNote.live().reports.observeAsState() - val noteForReports = noteReportsState?.note ?: return - - val accountState by accountViewModel.accountLiveData.observeAsState() - val account = accountState?.account ?: return - - var showHiddenNote by remember { mutableStateOf(false) } - - val context = LocalContext.current - - val moreActionsExpanded = remember { mutableStateOf(false) } - val enablePopup = remember { { moreActionsExpanded.value = true } } - - val noteEvent = note?.event - - var popupExpanded by remember { mutableStateOf(false) } - - val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - - if (noteEvent == null) { - BlankNote() - } else if (!account.isAcceptable(noteForReports) && !showHiddenNote) { - val reports = remember { account.getRelevantReports(noteForReports).toImmutableSet() } - - HiddenNote( - reports, - note.author?.let { account.isHidden(it) } ?: false, - accountViewModel, - Modifier.fillMaxWidth(), - nav, - onClick = { showHiddenNote = true }, - ) - } else { - Column( - modifier - .fillMaxWidth() - .padding(top = 10.dp), - ) { - val editState = observeEdits(baseNote = baseNote, accountViewModel = accountViewModel) - - Row( - modifier = - Modifier - .padding(start = 12.dp, end = 12.dp) - .clickable(onClick = { note.author?.let { nav("User/${it.pubkeyHex}") } }), - ) { - NoteAuthorPicture( - baseNote = baseNote, - nav = nav, - accountViewModel = accountViewModel, - size = 55.dp, - ) - - Column(modifier = Modifier.padding(start = 10.dp)) { - Row(verticalAlignment = Alignment.CenterVertically) { - NoteUsernameDisplay(baseNote, Modifier.weight(1f)) - - val isCommunityPost by - remember(baseNote) { - derivedStateOf { - baseNote.event?.isTaggedAddressableKind(CommunityDefinitionEvent.KIND) == true - } - } - - if (isCommunityPost) { - DisplayFollowingCommunityInPost(baseNote, accountViewModel, nav) - } else { - DisplayFollowingHashtagsInPost(baseNote, accountViewModel, nav) - } - - if (editState.value is GenericLoadable.Loaded) { - (editState.value as? GenericLoadable.Loaded)?.loaded?.let { - DisplayEditStatus(it) - } - } - - Text( - timeAgo(note.createdAt(), context = context), - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 1, - ) - - IconButton( - modifier = Size24Modifier, - onClick = enablePopup, - ) { - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(id = R.string.more_options), - modifier = Size15Modifier, - tint = MaterialTheme.colorScheme.placeholderText, - ) - - NoteDropDownMenu(baseNote, moreActionsExpanded, editState, accountViewModel, nav) - } - } - - Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status( - baseNote, - remember { Modifier.weight(1f) }, - accountViewModel, - nav, - ) - - val geo = remember { noteEvent.getGeoHash() } - if (geo != null) { - DisplayLocation(geo, nav) - } - - val baseReward = remember { noteEvent.getReward()?.let { Reward(it) } } - if (baseReward != null) { - DisplayReward(baseReward, baseNote, accountViewModel, nav) - } - - val pow = remember { noteEvent.getPoWRank() } - if (pow > 20) { - DisplayPoW(pow) - } - - if (note.isDraft()) { - DisplayDraft() - } - - DisplayOtsIfInOriginal(note, editState, accountViewModel) - } - } - } - - Spacer(modifier = Modifier.height(10.dp)) - - if (noteEvent is BadgeDefinitionEvent) { - BadgeDisplay(baseNote = note) - } else if (noteEvent is LongTextNoteEvent) { - RenderLongFormHeaderForThread(noteEvent) - } else if (noteEvent is WikiNoteEvent) { - RenderWikiHeaderForThread(noteEvent, accountViewModel, nav) - } else if (noteEvent is ClassifiedsEvent) { - RenderClassifiedsReaderForThread(noteEvent, note, accountViewModel, nav) - } - - Row( - modifier = - Modifier - .padding(horizontal = 12.dp) - .combinedClickable( - onClick = {}, - onLongClick = { popupExpanded = true }, - ), - ) { - Column { - val canPreview = - note.author == account.userProfile() || - (note.author?.let { account.userProfile().isFollowingCached(it) } ?: true) || - !noteForReports.hasAnyReports() - - if ( - (noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && - note.channelHex() != null - ) { - ChannelHeader( - channelHex = note.channelHex()!!, - showVideo = true, - sendToChannel = true, - accountViewModel = accountViewModel, - nav = nav, - ) - } else if (noteEvent is VideoEvent) { - VideoDisplay(baseNote, false, true, backgroundColor, false, accountViewModel, nav) - } else if (noteEvent is FileHeaderEvent) { - FileHeaderDisplay(baseNote, true, false, accountViewModel) - } else if (noteEvent is FileStorageHeaderEvent) { - FileStorageHeaderDisplay(baseNote, true, false, accountViewModel) - } else if (noteEvent is PeopleListEvent) { - DisplayPeopleList(baseNote, backgroundColor, accountViewModel, nav) - } else if (noteEvent is AudioTrackEvent) { - AudioTrackHeader(noteEvent, baseNote, false, accountViewModel, nav) - } else if (noteEvent is AudioHeaderEvent) { - AudioHeader(noteEvent, baseNote, false, accountViewModel, nav) - } else if (noteEvent is CommunityPostApprovalEvent) { - RenderPostApproval( - baseNote, - quotesLeft = 3, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is PinListEvent) { - RenderPinListEvent( - baseNote, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is EmojiPackEvent) { - RenderEmojiPack( - baseNote, - true, - backgroundColor, - accountViewModel, - ) - } else if (noteEvent is RelaySetEvent) { - DisplayRelaySet( - baseNote, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is FhirResourceEvent) { - RenderFhirResource(baseNote, accountViewModel, nav) - } else if (noteEvent is GitRepositoryEvent) { - RenderGitRepositoryEvent(baseNote, accountViewModel, nav) - } else if (noteEvent is GitPatchEvent) { - RenderGitPatchEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) - } else if (noteEvent is GitIssueEvent) { - RenderGitIssueEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) - } else if (noteEvent is AppDefinitionEvent) { - RenderAppDefinition(baseNote, accountViewModel, nav) - } else if (noteEvent is DraftEvent) { - RenderDraft(baseNote, 3, true, backgroundColor, accountViewModel, nav) - } else if (noteEvent is HighlightEvent) { - DisplayHighlight( - noteEvent.quote(), - noteEvent.author(), - noteEvent.inUrl(), - noteEvent.inPost(), - false, - true, - quotesLeft = 3, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) { - RenderRepost(baseNote, quotesLeft = 3, backgroundColor, accountViewModel, nav) - } else if (noteEvent is TextNoteModificationEvent) { - RenderTextModificationEvent( - note = baseNote, - makeItShort = false, - canPreview = true, - quotesLeft = 3, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is PollNoteEvent) { - RenderPoll( - baseNote, - false, - canPreview, - quotesLeft = 3, - unPackReply = false, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is PrivateDmEvent) { - RenderPrivateMessage( - baseNote, - false, - canPreview, - 3, - backgroundColor, - accountViewModel, - nav, - ) - } else if (noteEvent is ChannelMessageEvent) { - RenderChannelMessage( - baseNote, - false, - canPreview, - 3, - backgroundColor, - editState, - accountViewModel, - nav, - ) - } else if (noteEvent is LiveActivitiesChatMessageEvent) { - RenderLiveActivityChatMessage( - baseNote, - false, - canPreview, - 3, - backgroundColor, - editState, - accountViewModel, - nav, - ) - } else { - RenderTextEvent( - baseNote, - false, - canPreview, - quotesLeft = 3, - unPackReply = false, - backgroundColor, - editState, - accountViewModel, - nav, - ) - } - } - } - - val noteEvent = baseNote.event - val zapSplits = remember(noteEvent) { noteEvent?.hasZapSplitSetup() ?: false } - if (zapSplits && noteEvent != null) { - Spacer(modifier = DoubleVertSpacer) - Row( - modifier = Modifier.padding(horizontal = 12.dp), - ) { - DisplayZapSplits(noteEvent, false, accountViewModel, nav) - } - } - - ReactionsRow(note, true, true, editState, accountViewModel, nav) - } - - NoteQuickActionMenu( - note = note, - popupExpanded = popupExpanded, - onDismiss = { popupExpanded = false }, - onWantsToEditDraft = { }, + WatchNoteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + modifier, + ) { + CheckHiddenFeedWatchBlockAndReport( + note = baseNote, + modifier = modifier, + ignoreAllBlocksAndReports = false, + showHiddenWarning = true, accountViewModel = accountViewModel, nav = nav, + ) { canPreview -> + LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> + FullBleedNoteCompose( + baseNote, + modifier + .combinedClickable( + onClick = {}, + onLongClick = showPopup, + ), + canPreview, + parentBackgroundColor = parentBackgroundColor, + accountViewModel, + nav, + ) + } + } + } +} + +@Composable +private fun FullBleedNoteCompose( + baseNote: Note, + modifier: Modifier, + canPreview: Boolean, + parentBackgroundColor: MutableState?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val noteEvent = baseNote.event ?: return + + val backgroundColor = + calculateBackgroundColor( + baseNote.createdAt(), + null, + parentBackgroundColor, + accountViewModel, ) + + Column( + Modifier + .fillMaxWidth() + .padding(top = 10.dp), + ) { + val editState = observeEdits(baseNote = baseNote, accountViewModel = accountViewModel) + + Row( + modifier = + Modifier + .padding(start = 12.dp, end = 12.dp) + .clickable(onClick = { baseNote.author?.let { nav(routeFor(it)) } }), + ) { + NoteAuthorPicture( + baseNote = baseNote, + nav = nav, + accountViewModel = accountViewModel, + size = Size55dp, + ) + + Column(modifier = Modifier.padding(start = 10.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + NoteUsernameDisplay(baseNote, Modifier.weight(1f)) + + val isCommunityPost by + remember(baseNote) { + derivedStateOf { + baseNote.event?.isTaggedAddressableKind(CommunityDefinitionEvent.KIND) == true + } + } + + if (isCommunityPost) { + DisplayFollowingCommunityInPost(baseNote, accountViewModel, nav) + } else { + DisplayFollowingHashtagsInPost(baseNote, accountViewModel, nav) + } + + if (editState.value is GenericLoadable.Loaded) { + (editState.value as? GenericLoadable.Loaded)?.loaded?.let { + DisplayEditStatus(it) + } + } + + TimeAgo(note = baseNote) + + MoreOptionsButton(baseNote, editState, accountViewModel, nav) + } + + Row(verticalAlignment = Alignment.CenterVertically) { + ObserveDisplayNip05Status( + baseNote, + remember { Modifier.weight(1f) }, + accountViewModel, + nav, + ) + + val geo = remember { noteEvent.getGeoHash() } + if (geo != null) { + DisplayLocation(geo, nav) + } + + val baseReward = remember { noteEvent.getReward()?.let { Reward(it) } } + if (baseReward != null) { + DisplayReward(baseReward, baseNote, accountViewModel, nav) + } + + val pow = remember { noteEvent.getPoWRank() } + if (pow > 20) { + DisplayPoW(pow) + } + + if (baseNote.isDraft()) { + DisplayDraft() + } + + DisplayOtsIfInOriginal(baseNote, editState, accountViewModel) + } + } + } + + Spacer(modifier = Modifier.height(10.dp)) + + if (noteEvent is BadgeDefinitionEvent) { + BadgeDisplay(baseNote = baseNote) + } else if (noteEvent is LongTextNoteEvent) { + RenderLongFormHeaderForThread(noteEvent) + } else if (noteEvent is WikiNoteEvent) { + RenderWikiHeaderForThread(noteEvent, accountViewModel, nav) + } else if (noteEvent is ClassifiedsEvent) { + RenderClassifiedsReaderForThread(noteEvent, baseNote, accountViewModel, nav) + } + + Row( + modifier = + modifier + .padding(horizontal = 12.dp), + ) { + Column { + if ( + (noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && + baseNote.channelHex() != null + ) { + ChannelHeader( + channelHex = baseNote.channelHex()!!, + showVideo = true, + sendToChannel = true, + accountViewModel = accountViewModel, + nav = nav, + ) + } else if (noteEvent is VideoEvent) { + VideoDisplay(baseNote, false, true, backgroundColor, false, accountViewModel, nav) + } else if (noteEvent is FileHeaderEvent) { + FileHeaderDisplay(baseNote, true, false, accountViewModel) + } else if (noteEvent is FileStorageHeaderEvent) { + FileStorageHeaderDisplay(baseNote, true, false, accountViewModel) + } else if (noteEvent is PeopleListEvent) { + DisplayPeopleList(baseNote, backgroundColor, accountViewModel, nav) + } else if (noteEvent is AudioTrackEvent) { + AudioTrackHeader(noteEvent, baseNote, false, accountViewModel, nav) + } else if (noteEvent is AudioHeaderEvent) { + AudioHeader(noteEvent, baseNote, false, accountViewModel, nav) + } else if (noteEvent is CommunityPostApprovalEvent) { + RenderPostApproval( + baseNote, + quotesLeft = 3, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is PinListEvent) { + RenderPinListEvent( + baseNote, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is EmojiPackEvent) { + RenderEmojiPack( + baseNote, + true, + backgroundColor, + accountViewModel, + ) + } else if (noteEvent is RelaySetEvent) { + DisplayRelaySet( + baseNote, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is FhirResourceEvent) { + RenderFhirResource(baseNote, accountViewModel, nav) + } else if (noteEvent is GitRepositoryEvent) { + RenderGitRepositoryEvent(baseNote, accountViewModel, nav) + } else if (noteEvent is GitPatchEvent) { + RenderGitPatchEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) + } else if (noteEvent is GitIssueEvent) { + RenderGitIssueEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) + } else if (noteEvent is AppDefinitionEvent) { + RenderAppDefinition(baseNote, accountViewModel, nav) + } else if (noteEvent is DraftEvent) { + RenderDraft(baseNote, 3, true, backgroundColor, accountViewModel, nav) + } else if (noteEvent is HighlightEvent) { + RenderHighlight(baseNote, false, canPreview, quotesLeft = 3, backgroundColor, accountViewModel, nav) + } else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) { + RenderRepost(baseNote, quotesLeft = 3, backgroundColor, accountViewModel, nav) + } else if (noteEvent is TextNoteModificationEvent) { + RenderTextModificationEvent( + note = baseNote, + makeItShort = false, + canPreview = true, + quotesLeft = 3, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is PollNoteEvent) { + RenderPoll( + baseNote, + false, + canPreview, + quotesLeft = 3, + unPackReply = false, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is PrivateDmEvent) { + RenderPrivateMessage( + baseNote, + false, + canPreview, + 3, + backgroundColor, + accountViewModel, + nav, + ) + } else if (noteEvent is ChannelMessageEvent) { + RenderChannelMessage( + baseNote, + false, + canPreview, + 3, + backgroundColor, + editState, + accountViewModel, + nav, + ) + } else if (noteEvent is LiveActivitiesChatMessageEvent) { + RenderLiveActivityChatMessage( + baseNote, + false, + canPreview, + 3, + backgroundColor, + editState, + accountViewModel, + nav, + ) + } else { + RenderTextEvent( + baseNote, + false, + canPreview, + quotesLeft = 3, + unPackReply = false, + backgroundColor, + editState, + accountViewModel, + nav, + ) + } + } + } + + val noteEvent = baseNote.event + val zapSplits = remember(noteEvent) { noteEvent?.hasZapSplitSetup() ?: false } + if (zapSplits && noteEvent != null) { + Spacer(modifier = DoubleVertSpacer) + Row( + modifier = Modifier.padding(horizontal = 12.dp), + ) { + DisplayZapSplits(noteEvent, false, accountViewModel, nav) + } + } + + ReactionsRow(baseNote, true, true, editState, accountViewModel, nav) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 0b5fc112d..adbbd46ee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -254,16 +254,70 @@ class AccountViewModel( } } - val noteIsHiddenFlows = LruCache>(300) + @Immutable + data class NoteComposeReportState( + val isPostHidden: Boolean = false, + val isAcceptable: Boolean = true, + val canPreview: Boolean = true, + val isHiddenAuthor: Boolean = false, + val relevantReports: ImmutableSet = persistentSetOf(), + ) - fun createIsHiddenFlow(note: Note): StateFlow = + fun isNoteAcceptable( + note: Note, + accountChoices: Account.LiveHiddenUsers, + followUsers: Set, + ): NoteComposeReportState { + val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex + val isFromLoggedInFollow = note.author?.let { followUsers.contains(it.pubkeyHex) } ?: true + val isPostHidden = note.isHiddenFor(accountChoices) + val isHiddenAuthor = note.author?.let { account.isHidden(it) } == true + + return if (isPostHidden) { + // Spam + Blocked Users + Hidden Words + Sensitive Content + NoteComposeReportState(isPostHidden, false, false, isHiddenAuthor, persistentSetOf()) + } else if (isFromLoggedIn || isFromLoggedInFollow) { + // No need to process if from trusted people + NoteComposeReportState(isPostHidden, true, true, isHiddenAuthor, persistentSetOf()) + } else { + val newCanPreview = !note.hasAnyReports() + + val newIsAcceptable = account.isAcceptable(note) + + if (newCanPreview && newIsAcceptable) { + // No need to process reports if nothing is wrong + NoteComposeReportState(isPostHidden, true, true, false, persistentSetOf()) + } else { + val newRelevantReports = account.getRelevantReports(note) + + NoteComposeReportState( + isPostHidden, + newIsAcceptable, + newCanPreview, + false, + newRelevantReports.toImmutableSet(), + ) + } + } + } + + val noteIsHiddenFlows = LruCache>(300) + + fun createIsHiddenFlow(note: Note): StateFlow = noteIsHiddenFlows.get(note) - ?: combineTransform(account.flowHiddenUsers, note.flow().metadata.stateFlow) { hiddenUsers, metadata -> - emit(metadata.note.isHiddenFor(hiddenUsers)) + ?: combineTransform( + account.flowHiddenUsers, + account.liveKind3FollowsFlow, + note.flow().metadata.stateFlow, + note.flow().reports.stateFlow, + ) { hiddenUsers, followingUsers, metadata, reports -> + emit( + isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.users), + ) }.stateIn( viewModelScope, SharingStarted.Eagerly, - false, + NoteComposeReportState(), ).also { noteIsHiddenFlows.put(note, it) } @@ -761,52 +815,6 @@ class AccountViewModel( fun defaultZapType(): LnZapEvent.ZapType = account.defaultZapType - @Immutable - data class NoteComposeReportState( - val isAcceptable: Boolean = true, - val canPreview: Boolean = true, - val isHiddenAuthor: Boolean = false, - val relevantReports: ImmutableSet = persistentSetOf(), - ) - - suspend fun isNoteAcceptable( - note: Note, - onReady: (NoteComposeReportState) -> Unit, - ) { - val newState = - withContext(Dispatchers.IO) { - val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex - val isFromLoggedInFollow = note.author?.let { userProfile().isFollowingCached(it) } ?: true - - if (isFromLoggedIn || isFromLoggedInFollow) { - // No need to process if from trusted people - NoteComposeReportState(true, true, false, persistentSetOf()) - } else if (note.author?.let { account.isHidden(it) } == true) { - NoteComposeReportState(false, false, true, persistentSetOf()) - } else { - val newCanPreview = !note.hasAnyReports() - - val newIsAcceptable = account.isAcceptable(note) - - if (newCanPreview && newIsAcceptable) { - // No need to process reports if nothing is wrong - NoteComposeReportState(true, true, false, persistentSetOf()) - } else { - val newRelevantReports = account.getRelevantReports(note) - - NoteComposeReportState( - newIsAcceptable, - newCanPreview, - false, - newRelevantReports.toImmutableSet(), - ) - } - } - } - - onReady(newState) - } - fun unwrap( event: GiftWrapEvent, onReady: (Event) -> Unit, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index 447b9e482..7a4f86202 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -51,7 +52,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -70,14 +70,13 @@ import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.BoostReaction -import com.vitorpamplona.amethyst.ui.note.HiddenNote +import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay import com.vitorpamplona.amethyst.ui.note.RenderRelay import com.vitorpamplona.amethyst.ui.note.ReplyReaction import com.vitorpamplona.amethyst.ui.note.ViewCountReaction -import com.vitorpamplona.amethyst.ui.note.WatchForReports import com.vitorpamplona.amethyst.ui.note.ZapReaction import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.note.types.FileHeaderDisplay @@ -107,8 +106,6 @@ import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent import com.vitorpamplona.quartz.events.VideoEvent import kotlinx.collections.immutable.ImmutableList -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch @Composable fun VideoScreen( @@ -249,75 +246,24 @@ fun SlidingCarousel( key = { index -> feed.value.getOrNull(index)?.idHex ?: "$index" }, ) { index -> feed.value.getOrNull(index)?.let { note -> - LoadedVideoCompose(note, showHidden, accountViewModel, nav) - } - } -} - -@Composable -fun LoadedVideoCompose( - note: Note, - showHidden: Boolean, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - var state by - remember(note) { - mutableStateOf( - AccountViewModel.NoteComposeReportState(), - ) - } - - if (!showHidden) { - val scope = rememberCoroutineScope() - - WatchForReports(note, accountViewModel) { newState -> - if (state != newState) { - scope.launch(Dispatchers.Main) { state = newState } + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + CheckHiddenFeedWatchBlockAndReport( + note = note, + modifier = Modifier.fillMaxWidth(), + showHiddenWarning = true, + ignoreAllBlocksAndReports = showHidden, + accountViewModel = accountViewModel, + nav = nav, + ) { + RenderVideoOrPictureNote( + note, + accountViewModel, + nav, + ) + } } } } - - Crossfade(targetState = state, label = "LoadedVideoCompose") { - RenderReportState( - it, - note, - accountViewModel, - nav, - ) - } -} - -@Composable -fun RenderReportState( - state: AccountViewModel.NoteComposeReportState, - note: Note, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - var showReportedNote by remember { mutableStateOf(false) } - - Crossfade(targetState = (!state.isAcceptable || state.isHiddenAuthor) && !showReportedNote) { - showHiddenNote -> - if (showHiddenNote) { - Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center) { - HiddenNote( - state.relevantReports, - state.isHiddenAuthor, - accountViewModel, - Modifier.fillMaxWidth(), - nav, - onClick = { showReportedNote = true }, - ) - } - } else { - RenderVideoOrPictureNote( - note, - accountViewModel, - nav, - ) - } - } } @Composable @@ -478,8 +424,7 @@ fun ReactionsColumn( routeFor( baseNote, accountViewModel.userProfile(), - ) - ?.let { nav(it) } + )?.let { nav(it) } } BoostReaction( baseNote = baseNote,