- 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.
This commit is contained in:
@@ -258,7 +258,9 @@ open class Note(
|
|||||||
if (repliesChanged) liveSet?.innerReplies?.invalidateData()
|
if (repliesChanged) liveSet?.innerReplies?.invalidateData()
|
||||||
if (reactionsChanged) liveSet?.innerReactions?.invalidateData()
|
if (reactionsChanged) liveSet?.innerReactions?.invalidateData()
|
||||||
if (boostsChanged) liveSet?.innerBoosts?.invalidateData()
|
if (boostsChanged) liveSet?.innerBoosts?.invalidateData()
|
||||||
if (reportsChanged) liveSet?.innerReports?.invalidateData()
|
if (reportsChanged) {
|
||||||
|
flowSet?.reports?.invalidateData()
|
||||||
|
}
|
||||||
if (zapsChanged) liveSet?.innerZaps?.invalidateData()
|
if (zapsChanged) liveSet?.innerZaps?.invalidateData()
|
||||||
|
|
||||||
return toBeRemoved
|
return toBeRemoved
|
||||||
@@ -290,7 +292,7 @@ open class Note(
|
|||||||
if (reports[author]?.contains(deleteNote) == true) {
|
if (reports[author]?.contains(deleteNote) == true) {
|
||||||
reports[author]?.let {
|
reports[author]?.let {
|
||||||
reports = reports + Pair(author, it.minus(deleteNote))
|
reports = reports + Pair(author, it.minus(deleteNote))
|
||||||
liveSet?.innerReports?.invalidateData()
|
flowSet?.reports?.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,10 +401,10 @@ open class Note(
|
|||||||
|
|
||||||
if (reportsByAuthor == null) {
|
if (reportsByAuthor == null) {
|
||||||
reports = reports + Pair(author, listOf(note))
|
reports = reports + Pair(author, listOf(note))
|
||||||
liveSet?.innerReports?.invalidateData()
|
flowSet?.reports?.invalidateData()
|
||||||
} else if (!reportsByAuthor.contains(note)) {
|
} else if (!reportsByAuthor.contains(note)) {
|
||||||
reports = reports + Pair(author, reportsByAuthor + note)
|
reports = reports + Pair(author, reportsByAuthor + note)
|
||||||
liveSet?.innerReports?.invalidateData()
|
flowSet?.reports?.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,11 +846,13 @@ class NoteFlowSet(
|
|||||||
) {
|
) {
|
||||||
// Observers line up here.
|
// Observers line up here.
|
||||||
val metadata = NoteBundledRefresherFlow(u)
|
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() {
|
fun destroy() {
|
||||||
metadata.destroy()
|
metadata.destroy()
|
||||||
|
reports.destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,7 +865,6 @@ class NoteLiveSet(
|
|||||||
val innerReactions = NoteBundledRefresherLiveData(u)
|
val innerReactions = NoteBundledRefresherLiveData(u)
|
||||||
val innerBoosts = NoteBundledRefresherLiveData(u)
|
val innerBoosts = NoteBundledRefresherLiveData(u)
|
||||||
val innerReplies = NoteBundledRefresherLiveData(u)
|
val innerReplies = NoteBundledRefresherLiveData(u)
|
||||||
val innerReports = NoteBundledRefresherLiveData(u)
|
|
||||||
val innerRelays = NoteBundledRefresherLiveData(u)
|
val innerRelays = NoteBundledRefresherLiveData(u)
|
||||||
val innerZaps = NoteBundledRefresherLiveData(u)
|
val innerZaps = NoteBundledRefresherLiveData(u)
|
||||||
val innerOts = NoteBundledRefresherLiveData(u)
|
val innerOts = NoteBundledRefresherLiveData(u)
|
||||||
@@ -871,7 +874,6 @@ class NoteLiveSet(
|
|||||||
val reactions = innerReactions.map { it }
|
val reactions = innerReactions.map { it }
|
||||||
val boosts = innerBoosts.map { it }
|
val boosts = innerBoosts.map { it }
|
||||||
val replies = innerReplies.map { it }
|
val replies = innerReplies.map { it }
|
||||||
val reports = innerReports.map { it }
|
|
||||||
val relays = innerRelays.map { it }
|
val relays = innerRelays.map { it }
|
||||||
val zaps = innerZaps.map { it }
|
val zaps = innerZaps.map { it }
|
||||||
|
|
||||||
@@ -907,7 +909,6 @@ class NoteLiveSet(
|
|||||||
reactions.hasObservers() ||
|
reactions.hasObservers() ||
|
||||||
boosts.hasObservers() ||
|
boosts.hasObservers() ||
|
||||||
replies.hasObservers() ||
|
replies.hasObservers() ||
|
||||||
reports.hasObservers() ||
|
|
||||||
relays.hasObservers() ||
|
relays.hasObservers() ||
|
||||||
zaps.hasObservers() ||
|
zaps.hasObservers() ||
|
||||||
hasEvent.hasObservers() ||
|
hasEvent.hasObservers() ||
|
||||||
@@ -923,7 +924,6 @@ class NoteLiveSet(
|
|||||||
innerReactions.destroy()
|
innerReactions.destroy()
|
||||||
innerBoosts.destroy()
|
innerBoosts.destroy()
|
||||||
innerReplies.destroy()
|
innerReplies.destroy()
|
||||||
innerReports.destroy()
|
|
||||||
innerRelays.destroy()
|
innerRelays.destroy()
|
||||||
innerZaps.destroy()
|
innerZaps.destroy()
|
||||||
innerOts.destroy()
|
innerOts.destroy()
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -38,12 +36,12 @@ fun CheckHiddenFeedWatchBlockAndReport(
|
|||||||
note: Note,
|
note: Note,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
showHiddenWarning: Boolean,
|
showHiddenWarning: Boolean,
|
||||||
showHidden: Boolean = false,
|
ignoreAllBlocksAndReports: Boolean = false,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
normalNote: @Composable (canPreview: Boolean) -> Unit,
|
normalNote: @Composable (canPreview: Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
if (showHidden) {
|
if (ignoreAllBlocksAndReports) {
|
||||||
// Ignores reports as well
|
// Ignores reports as well
|
||||||
normalNote(true)
|
normalNote(true)
|
||||||
} else {
|
} else {
|
||||||
@@ -62,19 +60,28 @@ fun WatchBlockAndReport(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
normalNote: @Composable (canPreview: Boolean) -> Unit,
|
normalNote: @Composable (canPreview: Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
val isHiddenState by accountViewModel.createIsHiddenFlow(note).collectAsStateWithLifecycle()
|
val hiddenState by accountViewModel.createIsHiddenFlow(note).collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val showAnyway =
|
val showAnyway =
|
||||||
remember {
|
remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Crossfade(targetState = isHiddenState, label = "CheckHiddenNoteCompose") { isHidden ->
|
Crossfade(targetState = hiddenState, label = "CheckHiddenNoteCompose") { isHidden ->
|
||||||
if (showAnyway.value) {
|
if (showAnyway.value) {
|
||||||
normalNote(true)
|
normalNote(true)
|
||||||
} else if (!isHidden) {
|
} else if (!isHidden.isPostHidden) {
|
||||||
LoadReportsNoteCompose(note, modifier, accountViewModel, nav) { canPreview ->
|
if (isHidden.isAcceptable) {
|
||||||
normalNote(canPreview)
|
normalNote(isHidden.canPreview)
|
||||||
|
} else {
|
||||||
|
HiddenNote(
|
||||||
|
isHidden.relevantReports,
|
||||||
|
isHidden.isHiddenAuthor,
|
||||||
|
accountViewModel,
|
||||||
|
modifier,
|
||||||
|
nav,
|
||||||
|
onClick = { showAnyway.value = true },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else if (showHiddenWarning) {
|
} else if (showHiddenWarning) {
|
||||||
// if it is a quoted or boosted note, how the hidden warning.
|
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.BottomStart
|
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.CenterVertically
|
||||||
import androidx.compose.ui.Alignment.Companion.TopEnd
|
import androidx.compose.ui.Alignment.Companion.TopEnd
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -124,7 +123,7 @@ fun ChannelCardCompose(
|
|||||||
CheckHiddenFeedWatchBlockAndReport(
|
CheckHiddenFeedWatchBlockAndReport(
|
||||||
note = baseNote,
|
note = baseNote,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
showHidden = isHiddenFeed,
|
ignoreAllBlocksAndReports = isHiddenFeed,
|
||||||
showHiddenWarning = false,
|
showHiddenWarning = false,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
@@ -308,8 +307,7 @@ fun RenderClassifiedsThumb(
|
|||||||
title = noteEvent?.title(),
|
title = noteEvent?.title(),
|
||||||
price = noteEvent?.price(),
|
price = noteEvent?.price(),
|
||||||
)
|
)
|
||||||
}
|
}.distinctUntilChanged()
|
||||||
.distinctUntilChanged()
|
|
||||||
.observeAsState(
|
.observeAsState(
|
||||||
ClassifiedsThumb(
|
ClassifiedsThumb(
|
||||||
image = noteEvent.image(),
|
image = noteEvent.image(),
|
||||||
@@ -437,8 +435,7 @@ fun RenderLiveActivityThumb(
|
|||||||
status = noteEvent?.status(),
|
status = noteEvent?.status(),
|
||||||
starts = noteEvent?.starts(),
|
starts = noteEvent?.starts(),
|
||||||
)
|
)
|
||||||
}
|
}.distinctUntilChanged()
|
||||||
.distinctUntilChanged()
|
|
||||||
.observeAsState(
|
.observeAsState(
|
||||||
LiveActivityCard(
|
LiveActivityCard(
|
||||||
name = noteEvent.dTag(),
|
name = noteEvent.dTag(),
|
||||||
@@ -567,8 +564,7 @@ fun RenderCommunitiesThumb(
|
|||||||
cover = noteEvent?.image()?.ifBlank { null },
|
cover = noteEvent?.image()?.ifBlank { null },
|
||||||
moderators = noteEvent?.moderators()?.toImmutableList() ?: persistentListOf(),
|
moderators = noteEvent?.moderators()?.toImmutableList() ?: persistentListOf(),
|
||||||
)
|
)
|
||||||
}
|
}.distinctUntilChanged()
|
||||||
.distinctUntilChanged()
|
|
||||||
.observeAsState(
|
.observeAsState(
|
||||||
CommunityCard(
|
CommunityCard(
|
||||||
name = noteEvent.dTag(),
|
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 =
|
val allParticipants =
|
||||||
ParticipantListBuilder().followsThatParticipateOn(baseNote, followingKeySet).minus(hosts)
|
ParticipantListBuilder().followsThatParticipateOn(baseNote, followingKeySet).minus(hosts)
|
||||||
|
|
||||||
@@ -723,7 +721,9 @@ private fun LoadParticipants(
|
|||||||
|
|
||||||
val hostsAuthor = hosts + (baseNote.author?.let { listOf(it) } ?: emptyList<User>())
|
val hostsAuthor = hosts + (baseNote.author?.let { listOf(it) } ?: emptyList<User>())
|
||||||
|
|
||||||
val followingKeySet = accountViewModel.account.liveDiscoveryFollowLists.value?.users
|
val followingKeySet =
|
||||||
|
accountViewModel.account.liveDiscoveryFollowLists.value
|
||||||
|
?.users
|
||||||
|
|
||||||
val allParticipants =
|
val allParticipants =
|
||||||
ParticipantListBuilder()
|
ParticipantListBuilder()
|
||||||
@@ -760,7 +760,11 @@ fun RenderContentDVMThumb(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
// downloads user metadata to pre-load the NIP-65 relays.
|
// 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)
|
val card = observeAppDefinition(appDefinitionNote = baseNote)
|
||||||
|
|
||||||
@@ -875,7 +879,9 @@ fun RenderChannelThumb(
|
|||||||
|
|
||||||
LaunchedEffect(key1 = channelUpdates) {
|
LaunchedEffect(key1 = channelUpdates) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
val followingKeySet = accountViewModel.account.liveDiscoveryFollowLists.value?.users
|
val followingKeySet =
|
||||||
|
accountViewModel.account.liveDiscoveryFollowLists.value
|
||||||
|
?.users
|
||||||
val allParticipants =
|
val allParticipants =
|
||||||
ParticipantListBuilder()
|
ParticipantListBuilder()
|
||||||
.followsThatParticipateOn(baseNote, followingKeySet)
|
.followsThatParticipateOn(baseNote, followingKeySet)
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ fun NoteCompose(
|
|||||||
CheckHiddenFeedWatchBlockAndReport(
|
CheckHiddenFeedWatchBlockAndReport(
|
||||||
note = baseNote,
|
note = baseNote,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
showHidden = isHiddenFeed,
|
ignoreAllBlocksAndReports = isHiddenFeed,
|
||||||
showHiddenWarning = isQuotedNote || isBoostedNote,
|
showHiddenWarning = isQuotedNote || isBoostedNote,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
@@ -264,9 +264,7 @@ fun AcceptableNote(
|
|||||||
}
|
}
|
||||||
is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote)
|
is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote)
|
||||||
else ->
|
else ->
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) {
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
showPopup,
|
|
||||||
->
|
|
||||||
CheckNewAndRenderNote(
|
CheckNewAndRenderNote(
|
||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
routeForLastRead = routeForLastRead,
|
routeForLastRead = routeForLastRead,
|
||||||
|
|||||||
@@ -36,11 +36,8 @@ import androidx.compose.foundation.lazy.LazyListState
|
|||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
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.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ProvideTextStyle
|
import androidx.compose.material3.ProvideTextStyle
|
||||||
@@ -49,9 +46,9 @@ import androidx.compose.material3.TextField
|
|||||||
import androidx.compose.material3.TextFieldDefaults
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
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.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
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.LoadNote
|
||||||
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
||||||
import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel
|
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.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.DisplayDraft
|
||||||
import com.vitorpamplona.amethyst.ui.note.DisplayOtsIfInOriginal
|
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.LoadAddressableNote
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
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.NoteUsernameDisplay
|
||||||
import com.vitorpamplona.amethyst.ui.note.ReactionsRow
|
import com.vitorpamplona.amethyst.ui.note.ReactionsRow
|
||||||
import com.vitorpamplona.amethyst.ui.note.RenderDraft
|
import com.vitorpamplona.amethyst.ui.note.RenderDraft
|
||||||
import com.vitorpamplona.amethyst.ui.note.RenderRepost
|
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.DefaultImageHeader
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayEditStatus
|
import com.vitorpamplona.amethyst.ui.note.elements.DisplayEditStatus
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingCommunityInPost
|
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.DisplayReward
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayZapSplits
|
import com.vitorpamplona.amethyst.ui.note.elements.DisplayZapSplits
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.ForkInformationRow
|
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.Reward
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
|
||||||
import com.vitorpamplona.amethyst.ui.note.observeEdits
|
import com.vitorpamplona.amethyst.ui.note.observeEdits
|
||||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
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.AudioHeader
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader
|
import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay
|
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.DisplayPeopleList
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet
|
import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.EditState
|
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.RenderGitIssueEvent
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent
|
import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent
|
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.RenderLiveActivityChatMessage
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent
|
import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPoll
|
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.EditFieldBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.EditFieldTrailingIconModifier
|
import com.vitorpamplona.amethyst.ui.theme.EditFieldTrailingIconModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size24Modifier
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
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.VideoEvent
|
||||||
import com.vitorpamplona.quartz.events.WikiNoteEvent
|
import com.vitorpamplona.quartz.events.WikiNoteEvent
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -225,7 +221,10 @@ fun RenderThreadFeed(
|
|||||||
LaunchedEffect(noteId) {
|
LaunchedEffect(noteId) {
|
||||||
// waits to load the thread to scroll to item.
|
// waits to load the thread to scroll to item.
|
||||||
delay(100)
|
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)
|
var position = state.feed.value.indexOf(noteForPosition)
|
||||||
|
|
||||||
if (position >= 0) {
|
if (position >= 0) {
|
||||||
@@ -321,347 +320,314 @@ fun Modifier.drawReplyLevel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return@drawBehind
|
return@drawBehind
|
||||||
}
|
}.padding(start = (2 + (level * 3)).dp)
|
||||||
.padding(start = (2 + (level * 3)).dp)
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteMaster(
|
fun NoteMaster(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
parentBackgroundColor: MutableState<Color>? = null,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val noteState by baseNote.live().metadata.observeAsState()
|
WatchNoteEvent(
|
||||||
val note = noteState?.note
|
baseNote = baseNote,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
val noteReportsState by baseNote.live().reports.observeAsState()
|
modifier,
|
||||||
val noteForReports = noteReportsState?.note ?: return
|
) {
|
||||||
|
CheckHiddenFeedWatchBlockAndReport(
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
note = baseNote,
|
||||||
val account = accountState?.account ?: return
|
modifier = modifier,
|
||||||
|
ignoreAllBlocksAndReports = false,
|
||||||
var showHiddenNote by remember { mutableStateOf(false) }
|
showHiddenWarning = true,
|
||||||
|
|
||||||
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<Color>(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<EditState>)?.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 = { },
|
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
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<Color>?,
|
||||||
|
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<EditState>)?.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+59
-51
@@ -254,16 +254,70 @@ class AccountViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val noteIsHiddenFlows = LruCache<Note, StateFlow<Boolean>>(300)
|
@Immutable
|
||||||
|
data class NoteComposeReportState(
|
||||||
|
val isPostHidden: Boolean = false,
|
||||||
|
val isAcceptable: Boolean = true,
|
||||||
|
val canPreview: Boolean = true,
|
||||||
|
val isHiddenAuthor: Boolean = false,
|
||||||
|
val relevantReports: ImmutableSet<Note> = persistentSetOf(),
|
||||||
|
)
|
||||||
|
|
||||||
fun createIsHiddenFlow(note: Note): StateFlow<Boolean> =
|
fun isNoteAcceptable(
|
||||||
|
note: Note,
|
||||||
|
accountChoices: Account.LiveHiddenUsers,
|
||||||
|
followUsers: Set<HexKey>,
|
||||||
|
): 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<Note, StateFlow<NoteComposeReportState>>(300)
|
||||||
|
|
||||||
|
fun createIsHiddenFlow(note: Note): StateFlow<NoteComposeReportState> =
|
||||||
noteIsHiddenFlows.get(note)
|
noteIsHiddenFlows.get(note)
|
||||||
?: combineTransform(account.flowHiddenUsers, note.flow().metadata.stateFlow) { hiddenUsers, metadata ->
|
?: combineTransform(
|
||||||
emit(metadata.note.isHiddenFor(hiddenUsers))
|
account.flowHiddenUsers,
|
||||||
|
account.liveKind3FollowsFlow,
|
||||||
|
note.flow().metadata.stateFlow,
|
||||||
|
note.flow().reports.stateFlow,
|
||||||
|
) { hiddenUsers, followingUsers, metadata, reports ->
|
||||||
|
emit(
|
||||||
|
isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.users),
|
||||||
|
)
|
||||||
}.stateIn(
|
}.stateIn(
|
||||||
viewModelScope,
|
viewModelScope,
|
||||||
SharingStarted.Eagerly,
|
SharingStarted.Eagerly,
|
||||||
false,
|
NoteComposeReportState(),
|
||||||
).also {
|
).also {
|
||||||
noteIsHiddenFlows.put(note, it)
|
noteIsHiddenFlows.put(note, it)
|
||||||
}
|
}
|
||||||
@@ -761,52 +815,6 @@ class AccountViewModel(
|
|||||||
|
|
||||||
fun defaultZapType(): LnZapEvent.ZapType = account.defaultZapType
|
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<Note> = 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(
|
fun unwrap(
|
||||||
event: GiftWrapEvent,
|
event: GiftWrapEvent,
|
||||||
onReady: (Event) -> Unit,
|
onReady: (Event) -> Unit,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import androidx.compose.animation.Crossfade
|
|||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
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.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
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.components.ObserveDisplayNip05Status
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
||||||
import com.vitorpamplona.amethyst.ui.note.BoostReaction
|
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.LikeReaction
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay
|
import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay
|
||||||
import com.vitorpamplona.amethyst.ui.note.RenderRelay
|
import com.vitorpamplona.amethyst.ui.note.RenderRelay
|
||||||
import com.vitorpamplona.amethyst.ui.note.ReplyReaction
|
import com.vitorpamplona.amethyst.ui.note.ReplyReaction
|
||||||
import com.vitorpamplona.amethyst.ui.note.ViewCountReaction
|
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.ZapReaction
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu
|
import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu
|
||||||
import com.vitorpamplona.amethyst.ui.note.types.FileHeaderDisplay
|
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.FileStorageHeaderEvent
|
||||||
import com.vitorpamplona.quartz.events.VideoEvent
|
import com.vitorpamplona.quartz.events.VideoEvent
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoScreen(
|
fun VideoScreen(
|
||||||
@@ -249,75 +246,24 @@ fun SlidingCarousel(
|
|||||||
key = { index -> feed.value.getOrNull(index)?.idHex ?: "$index" },
|
key = { index -> feed.value.getOrNull(index)?.idHex ?: "$index" },
|
||||||
) { index ->
|
) { index ->
|
||||||
feed.value.getOrNull(index)?.let { note ->
|
feed.value.getOrNull(index)?.let { note ->
|
||||||
LoadedVideoCompose(note, showHidden, accountViewModel, nav)
|
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
}
|
CheckHiddenFeedWatchBlockAndReport(
|
||||||
}
|
note = note,
|
||||||
}
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
showHiddenWarning = true,
|
||||||
@Composable
|
ignoreAllBlocksAndReports = showHidden,
|
||||||
fun LoadedVideoCompose(
|
accountViewModel = accountViewModel,
|
||||||
note: Note,
|
nav = nav,
|
||||||
showHidden: Boolean,
|
) {
|
||||||
accountViewModel: AccountViewModel,
|
RenderVideoOrPictureNote(
|
||||||
nav: (String) -> Unit,
|
note,
|
||||||
) {
|
accountViewModel,
|
||||||
var state by
|
nav,
|
||||||
remember(note) {
|
)
|
||||||
mutableStateOf(
|
}
|
||||||
AccountViewModel.NoteComposeReportState(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!showHidden) {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
WatchForReports(note, accountViewModel) { newState ->
|
|
||||||
if (state != newState) {
|
|
||||||
scope.launch(Dispatchers.Main) { state = newState }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Composable
|
||||||
@@ -478,8 +424,7 @@ fun ReactionsColumn(
|
|||||||
routeFor(
|
routeFor(
|
||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel.userProfile(),
|
accountViewModel.userProfile(),
|
||||||
)
|
)?.let { nav(it) }
|
||||||
?.let { nav(it) }
|
|
||||||
}
|
}
|
||||||
BoostReaction(
|
BoostReaction(
|
||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
|
|||||||
Reference in New Issue
Block a user