From d83acab84bfb130611b36737de138d074ce6bdb0 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 18 Mar 2024 15:26:49 -0400 Subject: [PATCH] - Solves infinite Quotation issue. - Restructures NoteCompose for performance - Restructures markAsRead to minimize threading cost. --- .../components/TranslatableRichTextViewer.kt | 2 + .../amethyst/ui/actions/EditPostView.kt | 12 +- .../amethyst/ui/actions/NewPostView.kt | 12 +- .../ui/actions/NotifyRequestDialog.kt | 1 + .../ui/components/ClickableNoteTag.kt | 5 + .../ui/components/ExpandableRichTextViewer.kt | 2 + .../amethyst/ui/components/RichTextViewer.kt | 50 ++- .../amethyst/ui/note/BadgeCompose.kt | 46 +- .../amethyst/ui/note/BlankNote.kt | 3 +- .../amethyst/ui/note/ChannelCardCompose.kt | 43 +- .../amethyst/ui/note/ChatroomHeaderCompose.kt | 9 +- .../ui/note/ChatroomMessageCompose.kt | 9 +- .../amethyst/ui/note/MessageSetCompose.kt | 36 +- .../amethyst/ui/note/MultiSetCompose.kt | 35 +- .../amethyst/ui/note/NoteCompose.kt | 400 ++++++++---------- .../amethyst/ui/note/PollNote.kt | 17 +- .../amethyst/ui/note/ZapUserSetCompose.kt | 36 +- .../amethyst/ui/note/types/AppDefinition.kt | 1 + .../amethyst/ui/note/types/AudioTrack.kt | 1 + .../amethyst/ui/note/types/Badge.kt | 12 +- .../amethyst/ui/note/types/CommunityHeader.kt | 1 + .../amethyst/ui/note/types/Git.kt | 8 + .../amethyst/ui/note/types/Highlight.kt | 6 +- .../amethyst/ui/note/types/PinList.kt | 1 + .../amethyst/ui/note/types/Poll.kt | 4 +- .../amethyst/ui/note/types/PrivateMessage.kt | 13 +- .../amethyst/ui/note/types/Reaction.kt | 2 + .../ui/note/types/RenderPostApproval.kt | 17 +- .../amethyst/ui/note/types/Report.kt | 22 +- .../amethyst/ui/note/types/Text.kt | 2 + .../ui/note/types/TextModification.kt | 3 + .../amethyst/ui/note/types/Video.kt | 1 + .../amethyst/ui/screen/CardFeedView.kt | 6 + .../amethyst/ui/screen/FeedView.kt | 19 +- .../amethyst/ui/screen/ThreadFeedView.kt | 70 +-- .../ui/screen/loggedIn/AccountViewModel.kt | 63 +-- .../ui/screen/loggedIn/ChannelScreen.kt | 1 + .../ui/screen/loggedIn/ProfileScreen.kt | 1 + .../ui/screen/loggedIn/SearchScreen.kt | 5 + .../ui/screen/loggedIn/VideoScreen.kt | 1 - .../vitorpamplona/amethyst/ui/theme/Shape.kt | 1 + .../components/TranslatableRichTextViewer.kt | 22 +- 42 files changed, 443 insertions(+), 558 deletions(-) diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index b5f4b216b..5c3ccb366 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.events.ImmutableListOfLists fun TranslatableRichTextViewer( content: String, canPreview: Boolean, + quotesLeft: Int, modifier: Modifier = Modifier, tags: ImmutableListOfLists, backgroundColor: MutableState, @@ -40,6 +41,7 @@ fun TranslatableRichTextViewer( ) = ExpandableRichTextViewer( content, canPreview, + quotesLeft, modifier, tags, backgroundColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt index 6f46c42e1..48e094605 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt @@ -268,6 +268,7 @@ fun EditPostView( makeItShort = true, unPackReply = false, isQuotedNote = true, + quotesLeft = 1, modifier = MaterialTheme.colorScheme.replyModifier, accountViewModel = accountViewModel, nav = nav, @@ -312,11 +313,12 @@ fun EditPostView( val backgroundColor = remember { mutableStateOf(bgColor) } BechLink( - myUrlPreview, - true, - backgroundColor, - accountViewModel, - nav, + word = myUrlPreview, + canPreview = true, + quotesLeft = 1, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, ) } else if (RichTextParser.isUrlWithoutScheme(myUrlPreview)) { LoadUrlPreview("https://$myUrlPreview", myUrlPreview, accountViewModel) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 3a9ada0bb..5c1ea726f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -336,6 +336,7 @@ fun NewPostView( makeItShort = true, unPackReply = false, isQuotedNote = true, + quotesLeft = 1, modifier = MaterialTheme.colorScheme.replyModifier, accountViewModel = accountViewModel, nav = nav, @@ -413,11 +414,12 @@ fun NewPostView( val backgroundColor = remember { mutableStateOf(bgColor) } BechLink( - myUrlPreview, - true, - backgroundColor, - accountViewModel, - nav, + word = myUrlPreview, + canPreview = true, + quotesLeft = 1, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, ) } else if (RichTextParser.isUrlWithoutScheme(myUrlPreview)) { LoadUrlPreview("https://$myUrlPreview", myUrlPreview, accountViewModel) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt index 672e7acb8..430ec3f69 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt @@ -65,6 +65,7 @@ fun NotifyRequestDialog( TranslatableRichTextViewer( textContent, canPreview = true, + quotesLeft = 1, Modifier.fillMaxWidth(), EmptyTagList, background, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt index 93e279e1c..cc50e3641 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableNoteTag.kt @@ -26,13 +26,18 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.text.AnnotatedString import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.toShortenHex +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun ClickableNoteTag( baseNote: Note, + accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { + val route = routeFor(baseNote, accountViewModel.userProfile()) + ClickableText( text = AnnotatedString("@${baseNote.idNote().toShortenHex()}"), onClick = { nav("Note/${baseNote.idHex}") }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index d66a397a7..92aa4cf57 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -60,6 +60,7 @@ object ShowFullTextCache { fun ExpandableRichTextViewer( content: String, canPreview: Boolean, + quotesLeft: Int, modifier: Modifier, tags: ImmutableListOfLists, backgroundColor: MutableState, @@ -94,6 +95,7 @@ fun ExpandableRichTextViewer( RichTextViewer( text, canPreview, + quotesLeft, modifier.align(Alignment.TopStart), tags, backgroundColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 5550bcb3b..ee51500eb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -129,6 +129,7 @@ fun isMarkdown(content: String): Boolean { fun RichTextViewer( content: String, canPreview: Boolean, + quotesLeft: Int, modifier: Modifier, tags: ImmutableListOfLists, backgroundColor: MutableState, @@ -139,7 +140,7 @@ fun RichTextViewer( if (remember(content) { isMarkdown(content) }) { RenderContentAsMarkdown(content, tags, accountViewModel, nav) } else { - RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, nav) + RenderRegular(content, tags, canPreview, quotesLeft, backgroundColor, accountViewModel, nav) } } } @@ -277,6 +278,7 @@ private fun RenderRegular( content: String, tags: ImmutableListOfLists, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -287,6 +289,7 @@ private fun RenderRegular( word, state, backgroundColor, + quotesLeft, accountViewModel, nav, ) @@ -394,10 +397,10 @@ private fun RenderWordWithoutPreview( is CashuSegment -> Text(word.segmentText) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) - is BechSegment -> BechLink(word.segmentText, false, backgroundColor, accountViewModel, nav) + is BechSegment -> BechLink(word.segmentText, false, 0, backgroundColor, accountViewModel, nav) is HashTagSegment -> HashTag(word, nav) is HashIndexUserSegment -> TagLink(word, accountViewModel, nav) - is HashIndexEventSegment -> TagLink(word, false, backgroundColor, accountViewModel, nav) + is HashIndexEventSegment -> TagLink(word, false, 0, backgroundColor, accountViewModel, nav) is SchemelessUrlSegment -> NoProtocolUrlRenderer(word) is RegularTextSegment -> Text(word.segmentText) } @@ -408,6 +411,7 @@ private fun RenderWordWithPreview( word: Segment, state: RichTextViewerState, backgroundColor: MutableState, + quotesLeft: Int, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { @@ -420,10 +424,10 @@ private fun RenderWordWithPreview( is CashuSegment -> CashuPreview(word.segmentText, accountViewModel) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) - is BechSegment -> BechLink(word.segmentText, true, backgroundColor, accountViewModel, nav) + is BechSegment -> BechLink(word.segmentText, true, quotesLeft, backgroundColor, accountViewModel, nav) is HashTagSegment -> HashTag(word, nav) is HashIndexUserSegment -> TagLink(word, accountViewModel, nav) - is HashIndexEventSegment -> TagLink(word, true, backgroundColor, accountViewModel, nav) + is HashIndexEventSegment -> TagLink(word, true, quotesLeft, backgroundColor, accountViewModel, nav) is SchemelessUrlSegment -> NoProtocolUrlRenderer(word) is RegularTextSegment -> Text(word.segmentText) } @@ -643,6 +647,7 @@ private fun ObserveUser( fun BechLink( word: String, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -655,14 +660,17 @@ fun BechLink( } } - if (canPreview && loadedLink?.baseNote != null) { + val baseNote = loadedLink?.baseNote + + if (canPreview && quotesLeft > 0 && baseNote != null) { Row { DisplayFullNote( - loadedLink?.baseNote!!, - accountViewModel, - backgroundColor, - nav, - loadedLink?.nip19?.additionalChars?.ifBlank { null }, + note = baseNote, + extraChars = loadedLink?.nip19?.additionalChars?.ifBlank { null }, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, ) } } else if (loadedLink?.nip19 != null) { @@ -683,17 +691,19 @@ fun BechLink( @Composable private fun DisplayFullNote( - it: Note, - accountViewModel: AccountViewModel, - backgroundColor: MutableState, - nav: (String) -> Unit, + note: Note, extraChars: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, ) { NoteCompose( - baseNote = it, + baseNote = note, accountViewModel = accountViewModel, modifier = MaterialTheme.colorScheme.innerPostModifier, parentBackgroundColor = backgroundColor, + quotesLeft = quotesLeft - 1, isQuotedNote = true, nav = nav, ) @@ -806,6 +816,7 @@ fun LoadNote( fun TagLink( word: HashIndexEventSegment, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -819,6 +830,7 @@ fun TagLink( it, word.extras, canPreview, + quotesLeft, accountViewModel, backgroundColor, nav, @@ -833,21 +845,23 @@ private fun DisplayNoteFromTag( baseNote: Note, addedChars: String?, canPreview: Boolean, + quotesLeft: Int, accountViewModel: AccountViewModel, backgroundColor: MutableState, nav: (String) -> Unit, ) { - if (canPreview) { + if (canPreview && quotesLeft > 0) { NoteCompose( baseNote = baseNote, accountViewModel = accountViewModel, modifier = MaterialTheme.colorScheme.innerPostModifier, parentBackgroundColor = backgroundColor, isQuotedNote = true, + quotesLeft = quotesLeft - 1, nav = nav, ) } else { - ClickableNoteTag(baseNote, nav) + ClickableNoteTag(baseNote, accountViewModel, nav) } addedChars?.ifBlank { null }?.let { Text(text = it) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index f85d8fbaf..66a2f36b0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -32,13 +32,11 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MilitaryTech 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.MaterialTheme import androidx.compose.material3.Text 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 @@ -46,8 +44,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -55,11 +51,10 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu +import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay import com.vitorpamplona.amethyst.ui.screen.BadgeCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size15Modifier -import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.launch @@ -86,24 +81,12 @@ fun BadgeCompose( if (note == null) { BlankNote(Modifier, !isInnerNote) } else { - val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - - LaunchedEffect(key1 = likeSetCard) { - accountViewModel.loadAndMarkAsRead(routeForLastRead, likeSetCard.createdAt()) { isNew -> - val newBackgroundColor = - if (isNew) { - newItemColor.compositeOver(defaultBackgroundColor) - } else { - defaultBackgroundColor - } - - if (backgroundColor.value != newBackgroundColor) { - backgroundColor.value = newBackgroundColor - } - } - } + val backgroundColor = + calculateBackgroundColor( + createdAt = likeSetCard.createdAt(), + routeForLastRead = routeForLastRead, + accountViewModel = accountViewModel, + ) Column( modifier = @@ -173,21 +156,8 @@ fun BadgeCompose( } note.replyTo?.firstOrNull()?.let { - NoteCompose( - baseNote = it, - routeForLastRead = null, - isBoostedNote = true, - showHidden = showHidden, - parentBackgroundColor = backgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) + BadgeDisplay(baseNote = it) } - - HorizontalDivider( - modifier = Modifier.padding(top = 10.dp), - thickness = DividerThickness, - ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt index 6d0e75c0e..990cfba67 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt @@ -121,13 +121,12 @@ fun HiddenNote( isHiddenAuthor: Boolean, accountViewModel: AccountViewModel, modifier: Modifier = Modifier, - isQuote: Boolean = false, nav: (String) -> Unit, onClick: () -> Unit, ) { Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { Row( - modifier = Modifier.padding(start = if (!isQuote) 30.dp else 25.dp, end = 20.dp), + modifier = Modifier.padding(horizontal = 20.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { 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 7443a653f..251dfac0c 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 @@ -56,7 +56,6 @@ import androidx.compose.ui.Alignment.Companion.TopEnd import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -91,7 +90,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent @@ -258,7 +256,6 @@ fun RenderChannelCardReportState( state.isHiddenAuthor, accountViewModel, modifier, - false, nav, onClick = { showReportedNote = true }, ) @@ -307,41 +304,13 @@ private fun CheckNewAndRenderChannelCard( showPopup: () -> Unit, nav: (String) -> Unit, ) { - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - val defaultBackgroundColor = MaterialTheme.colorScheme.background val backgroundColor = - remember { - mutableStateOf( - parentBackgroundColor?.value ?: defaultBackgroundColor, - ) - } - - LaunchedEffect(key1 = routeForLastRead, key2 = parentBackgroundColor?.value) { - routeForLastRead?.let { - accountViewModel.loadAndMarkAsRead(routeForLastRead, baseNote.createdAt()) { isNew -> - val newBackgroundColor = - if (isNew) { - if (parentBackgroundColor != null) { - newItemColor.compositeOver(parentBackgroundColor.value) - } else { - newItemColor.compositeOver(defaultBackgroundColor) - } - } else { - parentBackgroundColor?.value ?: defaultBackgroundColor - } - - if (newBackgroundColor != backgroundColor.value) { - launch(Dispatchers.Main) { backgroundColor.value = newBackgroundColor } - } - } - } - ?: run { - val newBackgroundColor = parentBackgroundColor?.value ?: defaultBackgroundColor - if (newBackgroundColor != backgroundColor.value) { - launch(Dispatchers.Main) { backgroundColor.value = newBackgroundColor } - } - } - } + calculateBackgroundColor( + createdAt = baseNote.createdAt(), + routeForLastRead = routeForLastRead, + parentBackgroundColor = parentBackgroundColor, + accountViewModel = accountViewModel, + ) ClickableNote( baseNote = baseNote, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt index 689e10414..47702a68e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt @@ -77,8 +77,6 @@ import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMetadataEvent import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.ChatroomKeyable -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch @Composable fun ChatroomHeaderCompose( @@ -408,11 +406,8 @@ private fun WatchNotificationChanges( onNewStatus: (Boolean) -> Unit, ) { LaunchedEffect(key1 = note, accountViewModel.accountMarkAsReadUpdates.intValue) { - launch(Dispatchers.IO) { - note.event?.createdAt()?.let { - val lastTime = accountViewModel.account.loadLastRead(route) - onNewStatus(it > lastTime) - } + note.event?.createdAt()?.let { + onNewStatus(it > accountViewModel.account.loadLastRead(route)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 07d60234a..5a0c13d69 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -204,7 +204,6 @@ fun LoadedChatMessageCompose( state.isHiddenAuthor, accountViewModel, Modifier, - innerQuote, nav, onClick = { showReportedNote = true }, ) @@ -290,7 +289,7 @@ fun NormalChatNote( if (routeForLastRead != null) { LaunchedEffect(key1 = routeForLastRead) { - accountViewModel.loadAndMarkAsRead(routeForLastRead, note.createdAt()) {} + accountViewModel.loadAndMarkAsRead(routeForLastRead, note.createdAt()) } } @@ -445,6 +444,7 @@ private fun MessageBubbleLines( NoteRow( note = baseNote, canPreview = canPreview, + innerQuote = innerQuote, backgroundBubbleColor = backgroundBubbleColor, accountViewModel = accountViewModel, nav = nav, @@ -528,6 +528,7 @@ private fun RenderReply( private fun NoteRow( note: Note, canPreview: Boolean, + innerQuote: Boolean, backgroundBubbleColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -544,6 +545,7 @@ private fun NoteRow( RenderRegularTextNote( note, canPreview, + innerQuote, backgroundBubbleColor, accountViewModel, nav, @@ -640,6 +642,7 @@ fun ChatTimeAgo(baseNote: Note) { private fun RenderRegularTextNote( note: Note, canPreview: Boolean, + innerQuote: Boolean, backgroundBubbleColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -655,6 +658,7 @@ private fun RenderRegularTextNote( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview, + quotesLeft = if (innerQuote) 0 else 1, modifier = HalfTopPadding, tags = tags, backgroundColor = backgroundBubbleColor, @@ -667,6 +671,7 @@ private fun RenderRegularTextNote( TranslatableRichTextViewer( content = stringResource(id = R.string.could_not_decrypt_the_message), canPreview = true, + quotesLeft = 0, modifier = HalfTopPadding, tags = EmptyTagList, backgroundColor = backgroundBubbleColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt index e5beeccf9..4cc194da1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -30,24 +30,17 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.screen.MessageSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor import kotlinx.coroutines.launch @OptIn(ExperimentalFoundationApi::class) @@ -66,24 +59,12 @@ fun MessageSetCompose( val scope = rememberCoroutineScope() - val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - - LaunchedEffect(key1 = messageSetCard) { - accountViewModel.loadAndMarkAsRead(routeForLastRead, messageSetCard.createdAt()) { isNew -> - val newBackgroundColor = - if (isNew) { - newItemColor.compositeOver(defaultBackgroundColor) - } else { - defaultBackgroundColor - } - - if (backgroundColor.value != newBackgroundColor) { - backgroundColor.value = newBackgroundColor - } - } - } + val backgroundColor = + calculateBackgroundColor( + createdAt = messageSetCard.createdAt(), + routeForLastRead = routeForLastRead, + accountViewModel = accountViewModel, + ) val columnModifier = remember(backgroundColor.value) { @@ -125,6 +106,7 @@ fun MessageSetCompose( isBoostedNote = true, addMarginTop = false, showHidden = showHidden, + quotesLeft = 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, @@ -133,9 +115,5 @@ fun MessageSetCompose( NoteDropDownMenu(baseNote, popupExpanded, null, accountViewModel, nav) } } - - HorizontalDivider( - thickness = DividerThickness, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index b36e64c93..81d32bdfb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -36,7 +36,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -54,7 +53,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle @@ -74,7 +72,6 @@ import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.screen.CombinedZap import com.vitorpamplona.amethyst.ui.screen.MultiSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifier import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifierSmaller @@ -88,14 +85,12 @@ import com.vitorpamplona.amethyst.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifierWithPadding import com.vitorpamplona.amethyst.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor import com.vitorpamplona.amethyst.ui.theme.overPictureBackground import com.vitorpamplona.amethyst.ui.theme.profile35dpModifier import com.vitorpamplona.quartz.encoders.Nip30CustomEmoji import com.vitorpamplona.quartz.events.EmptyTagList import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlin.time.ExperimentalTime @@ -115,24 +110,12 @@ fun MultiSetCompose( val scope = rememberCoroutineScope() - val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - - LaunchedEffect(key1 = multiSetCard) { - accountViewModel.loadAndMarkAsRead(routeForLastRead, multiSetCard.maxCreatedAt) { isNew -> - val newBackgroundColor = - if (isNew) { - newItemColor.compositeOver(defaultBackgroundColor) - } else { - defaultBackgroundColor - } - - if (backgroundColor.value != newBackgroundColor) { - launch(Dispatchers.Main) { backgroundColor.value = newBackgroundColor } - } - } - } + val backgroundColor = + calculateBackgroundColor( + createdAt = multiSetCard.maxCreatedAt, + routeForLastRead = routeForLastRead, + accountViewModel = accountViewModel, + ) val columnModifier = remember(backgroundColor.value) { @@ -163,6 +146,7 @@ fun MultiSetCompose( modifier = HalfTopPadding, isBoostedNote = true, showHidden = showHidden, + quotesLeft = 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, @@ -170,10 +154,6 @@ fun MultiSetCompose( NoteDropDownMenu(baseNote, popupExpanded, null, accountViewModel, nav) } - - HorizontalDivider( - thickness = DividerThickness, - ) } } @@ -471,6 +451,7 @@ fun CrossfadeToDisplayComment( TranslatableRichTextViewer( content = comment, canPreview = true, + quotesLeft = 1, tags = EmptyTagList, modifier = textBoxModifier, backgroundColor = backgroundColor, 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 24b0553ac..082b102bb 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 @@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -56,7 +55,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note @@ -78,8 +76,6 @@ import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.ui.note.elements.Reward import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo -import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay -import com.vitorpamplona.amethyst.ui.note.types.CommunityHeader import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet import com.vitorpamplona.amethyst.ui.note.types.EditState @@ -110,7 +106,6 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderWikiContent import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer @@ -137,7 +132,6 @@ import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.BadgeAwardEvent -import com.vitorpamplona.quartz.events.BadgeDefinitionEvent import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent @@ -172,10 +166,8 @@ import com.vitorpamplona.quartz.events.VideoVerticalEvent import com.vitorpamplona.quartz.events.WikiNoteEvent import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -@OptIn(ExperimentalFoundationApi::class) @Composable fun NoteCompose( baseNote: Note, @@ -187,16 +179,27 @@ fun NoteCompose( makeItShort: Boolean = false, addMarginTop: Boolean = true, showHidden: Boolean = false, + quotesLeft: Int, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val hasEvent by baseNote.live().hasEvent.observeAsState(baseNote.event != null) - - Crossfade(targetState = hasEvent, label = "Event presence") { - if (it) { - CheckHiddenNoteCompose( - note = baseNote, + WatchNoteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + showDivider = !isBoostedNote && !isQuotedNote, + modifier, + ) { + CheckHiddenNoteCompose( + note = baseNote, + modifier = modifier, + showHidden = showHidden, + showHiddenWarning = isQuotedNote || isBoostedNote, + accountViewModel = accountViewModel, + nav = nav, + ) { canPreview -> + NormalNote( + baseNote = baseNote, routeForLastRead = routeForLastRead, modifier = modifier, isBoostedNote = isBoostedNote, @@ -204,22 +207,46 @@ fun NoteCompose( unPackReply = unPackReply, makeItShort = makeItShort, addMarginTop = addMarginTop, - showHidden = showHidden, + canPreview = canPreview, + quotesLeft = quotesLeft, parentBackgroundColor = parentBackgroundColor, accountViewModel = accountViewModel, nav = nav, ) - } else { - LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> - BlankNote( - remember { - modifier.combinedClickable( - onClick = {}, - onLongClick = showPopup, - ) - }, - !isBoostedNote && !isQuotedNote, - ) + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun WatchNoteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + showDivider: Boolean, + modifier: Modifier = Modifier, + onNoteEventFound: @Composable () -> Unit, +) { + if (baseNote.event != null) { + onNoteEventFound() + } else { + // avoid observing costs if already has an event. + + val hasEvent by baseNote.live().hasEvent.observeAsState(baseNote.event != null) + Crossfade(targetState = hasEvent, label = "Event presence") { + if (it) { + onNoteEventFound() + } else { + LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> + BlankNote( + remember { + modifier.combinedClickable( + onClick = {}, + onLongClick = showPopup, + ) + }, + showDivider, + ) + } } } } @@ -228,93 +255,64 @@ fun NoteCompose( @Composable fun CheckHiddenNoteCompose( note: Note, - routeForLastRead: String? = null, modifier: Modifier = Modifier, - isBoostedNote: Boolean = false, - isQuotedNote: Boolean = false, - unPackReply: Boolean = true, - makeItShort: Boolean = false, - addMarginTop: Boolean = true, + showHiddenWarning: Boolean, showHidden: Boolean = false, - parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, + normalNote: @Composable (canPreview: Boolean) -> Unit, ) { if (showHidden) { // Ignores reports as well - val state by - remember(note) { - mutableStateOf( - AccountViewModel.NoteComposeReportState(), - ) - } - - RenderReportState( - state = state, - note = note, - routeForLastRead = routeForLastRead, - modifier = modifier, - isBoostedNote = isBoostedNote, - isQuotedNote = isQuotedNote, - unPackReply = unPackReply, - makeItShort = makeItShort, - addMarginTop = addMarginTop, - parentBackgroundColor = parentBackgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) + normalNote(true) } else { - val isHidden by - remember(note) { - accountViewModel.account.liveHiddenUsers - .map { note.isHiddenFor(it) } - .distinctUntilChanged() - } - .observeAsState(accountViewModel.isNoteHidden(note)) - - val showAnyway = - remember { - mutableStateOf(false) - } - - Crossfade(targetState = isHidden, label = "CheckHiddenNoteCompose") { - if (!it || showAnyway.value) { - LoadedNoteCompose( - note = note, - routeForLastRead = routeForLastRead, - modifier = modifier, - isBoostedNote = isBoostedNote, - isQuotedNote = isQuotedNote, - unPackReply = unPackReply, - makeItShort = makeItShort, - addMarginTop = addMarginTop, - parentBackgroundColor = parentBackgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) - } else if (isQuotedNote || isBoostedNote) { - HiddenNoteByMe( - isQuote = true, - onClick = { showAnyway.value = true }, - ) + WatchIsHidden(note, showHiddenWarning, accountViewModel) { + LoadReportsNoteCompose(note, modifier, accountViewModel, nav) { canPreview -> + normalNote(canPreview) } } } } @Composable -fun LoadedNoteCompose( +fun WatchIsHidden( + note: Note, + showHiddenWarning: Boolean, + accountViewModel: AccountViewModel, + notHiddenNote: @Composable () -> Unit, +) { + val isHidden by remember(note) { + accountViewModel.account.liveHiddenUsers + .map { note.isHiddenFor(it) } + .distinctUntilChanged() + } + .observeAsState(accountViewModel.isNoteHidden(note)) + + val showAnyway = + remember { + mutableStateOf(false) + } + + Crossfade(targetState = isHidden, label = "CheckHiddenNoteCompose") { + if (!it || showAnyway.value) { + notHiddenNote() + } else if (showHiddenWarning) { + // if it is a quoted or boosted note, how the hidden warning. + HiddenNoteByMe( + isQuote = true, + onClick = { showAnyway.value = true }, + ) + } + } +} + +@Composable +fun LoadReportsNoteCompose( note: Note, - routeForLastRead: String? = null, modifier: Modifier = Modifier, - isBoostedNote: Boolean = false, - isQuotedNote: Boolean = false, - unPackReply: Boolean = true, - makeItShort: Boolean = false, - addMarginTop: Boolean = true, - parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, + normalNote: @Composable (canPreview: Boolean) -> Unit, ) { var state by remember(note) { @@ -330,20 +328,9 @@ fun LoadedNoteCompose( } Crossfade(targetState = state, label = "LoadedNoteCompose") { - RenderReportState( - it, - note, - routeForLastRead, - modifier, - isBoostedNote, - isQuotedNote, - unPackReply, - makeItShort, - addMarginTop, - parentBackgroundColor, - accountViewModel, - nav, - ) + RenderReportState(state = it, note = note, modifier = modifier, accountViewModel = accountViewModel, nav = nav) { canPreview -> + normalNote(canPreview) + } } } @@ -351,16 +338,10 @@ fun LoadedNoteCompose( fun RenderReportState( state: AccountViewModel.NoteComposeReportState, note: Note, - routeForLastRead: String? = null, modifier: Modifier = Modifier, - isBoostedNote: Boolean = false, - isQuotedNote: Boolean = false, - unPackReply: Boolean = true, - makeItShort: Boolean = false, - addMarginTop: Boolean = true, - parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, + normalNote: @Composable (canPreview: Boolean) -> Unit, ) { var showReportedNote by remember(note) { mutableStateOf(false) } @@ -371,27 +352,13 @@ fun RenderReportState( state.isHiddenAuthor, accountViewModel, modifier, - isBoostedNote, nav, onClick = { showReportedNote = true }, ) } else { val canPreview = (!state.isAcceptable && showReportedNote) || state.canPreview - NormalNote( - baseNote = note, - routeForLastRead = routeForLastRead, - modifier = modifier, - isBoostedNote = isBoostedNote, - isQuotedNote = isQuotedNote, - unPackReply = unPackReply, - makeItShort = makeItShort, - addMarginTop = addMarginTop, - canPreview = canPreview, - parentBackgroundColor = parentBackgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) + normalNote(canPreview) } } } @@ -422,6 +389,7 @@ fun NormalNote( makeItShort: Boolean = false, addMarginTop: Boolean = true, canPreview: Boolean = true, + quotesLeft: Int, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -439,35 +407,25 @@ fun NormalNote( accountViewModel = accountViewModel, nav = nav, ) - is CommunityDefinitionEvent -> - (baseNote as? AddressableNote)?.let { - CommunityHeader( - baseNote = it, - showBottomDiviser = true, - sendToCommunity = true, - accountViewModel = accountViewModel, - nav = nav, - ) - } - is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote) else -> LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup, -> CheckNewAndRenderNote( - baseNote, - routeForLastRead, - modifier, - isBoostedNote, - isQuotedNote, - unPackReply, - makeItShort, - addMarginTop, - canPreview, - parentBackgroundColor, - accountViewModel, - showPopup, - nav, + baseNote = baseNote, + routeForLastRead = routeForLastRead, + modifier = modifier, + isBoostedNote = isBoostedNote, + isQuotedNote = isQuotedNote, + unPackReply = unPackReply, + makeItShort = makeItShort, + addMarginTop = addMarginTop, + canPreview = canPreview, + quotesLeft = quotesLeft, + parentBackgroundColor = parentBackgroundColor, + accountViewModel = accountViewModel, + showPopup = showPopup, + nav = nav, ) } } @@ -484,17 +442,6 @@ fun NormalNote( accountViewModel = accountViewModel, nav = nav, ) - is CommunityDefinitionEvent -> - (baseNote as? AddressableNote)?.let { - CommunityHeader( - baseNote = it, - showBottomDiviser = true, - sendToCommunity = true, - accountViewModel = accountViewModel, - nav = nav, - ) - } - is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote) is FileHeaderEvent -> FileHeaderDisplay(baseNote, false, accountViewModel) is FileStorageHeaderEvent -> FileStorageHeaderDisplay(baseNote, false, accountViewModel) else -> @@ -511,6 +458,7 @@ fun NormalNote( makeItShort = makeItShort, addMarginTop = addMarginTop, canPreview = canPreview, + quotesLeft = quotesLeft, parentBackgroundColor = parentBackgroundColor, accountViewModel = accountViewModel, showPopup = showPopup, @@ -521,6 +469,36 @@ fun NormalNote( } } +@Composable +fun calculateBackgroundColor( + createdAt: Long?, + routeForLastRead: String? = null, + parentBackgroundColor: MutableState? = null, + accountViewModel: AccountViewModel, +): MutableState { + val defaultBackgroundColor = MaterialTheme.colorScheme.background + val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor + return remember(createdAt) { + mutableStateOf( + if (routeForLastRead != null) { + val isNew = accountViewModel.loadAndMarkAsRead(routeForLastRead, createdAt) + + if (isNew) { + if (parentBackgroundColor != null) { + newItemColor.compositeOver(parentBackgroundColor.value) + } else { + newItemColor.compositeOver(defaultBackgroundColor) + } + } else { + parentBackgroundColor?.value ?: defaultBackgroundColor + } + } else { + parentBackgroundColor?.value ?: defaultBackgroundColor + }, + ) + } +} + @Composable private fun CheckNewAndRenderNote( baseNote: Note, @@ -532,45 +510,19 @@ private fun CheckNewAndRenderNote( makeItShort: Boolean = false, addMarginTop: Boolean = true, canPreview: Boolean = true, + quotesLeft: Int, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showPopup: () -> Unit, nav: (String) -> Unit, ) { - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - val defaultBackgroundColor = MaterialTheme.colorScheme.background val backgroundColor = - remember(baseNote) { - mutableStateOf(parentBackgroundColor?.value ?: defaultBackgroundColor) - } - - LaunchedEffect(key1 = routeForLastRead, key2 = parentBackgroundColor?.value) { - routeForLastRead?.let { - accountViewModel.loadAndMarkAsRead(it, baseNote.createdAt()) { isNew -> - val newBackgroundColor = - if (isNew) { - if (parentBackgroundColor != null) { - newItemColor.compositeOver(parentBackgroundColor.value) - } else { - newItemColor.compositeOver(defaultBackgroundColor) - } - } else { - parentBackgroundColor?.value ?: defaultBackgroundColor - } - - if (newBackgroundColor != backgroundColor.value) { - launch(Dispatchers.Main) { backgroundColor.value = newBackgroundColor } - } - } - } - ?: run { - val newBackgroundColor = parentBackgroundColor?.value ?: defaultBackgroundColor - - if (newBackgroundColor != backgroundColor.value) { - launch(Dispatchers.Main) { backgroundColor.value = newBackgroundColor } - } - } - } + calculateBackgroundColor( + baseNote.createdAt(), + routeForLastRead, + parentBackgroundColor, + accountViewModel, + ) ClickableNote( baseNote = baseNote, @@ -589,6 +541,7 @@ private fun CheckNewAndRenderNote( unPackReply = unPackReply, makeItShort = makeItShort, canPreview = canPreview, + quotesLeft = quotesLeft, accountViewModel = accountViewModel, nav = nav, ) @@ -641,6 +594,7 @@ fun InnerNoteWithReactions( unPackReply: Boolean, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { @@ -675,6 +629,7 @@ fun InnerNoteWithReactions( makeItShort = makeItShort, canPreview = canPreview, showSecondRow = showSecondRow, + quotesLeft = quotesLeft, backgroundColor = backgroundColor, editState = editState, accountViewModel = accountViewModel, @@ -701,12 +656,6 @@ fun InnerNoteWithReactions( ) } } - - if (notBoostedNorQuote) { - HorizontalDivider( - thickness = DividerThickness, - ) - } } @Composable @@ -717,6 +666,7 @@ fun NoteBody( makeItShort: Boolean = false, canPreview: Boolean = true, showSecondRow: Boolean, + quotesLeft: Int, backgroundColor: MutableState, editState: State>, accountViewModel: AccountViewModel, @@ -758,6 +708,7 @@ fun NoteBody( makeItShort = makeItShort, canPreview = canPreview, editState = editState, + quotesLeft = quotesLeft, accountViewModel = accountViewModel, nav = nav, ) @@ -776,6 +727,7 @@ private fun RenderNoteRow( backgroundColor: MutableState, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, editState: State>, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -792,16 +744,16 @@ private fun RenderNoteRow( RenderAudioHeader(baseNote, accountViewModel, nav) } is ReactionEvent -> { - RenderReaction(baseNote, backgroundColor, accountViewModel, nav) + RenderReaction(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) } is RepostEvent -> { - RenderRepost(baseNote, backgroundColor, accountViewModel, nav) + RenderRepost(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) } is GenericRepostEvent -> { - RenderRepost(baseNote, backgroundColor, accountViewModel, nav) + RenderRepost(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) } is ReportEvent -> { - RenderReport(baseNote, backgroundColor, accountViewModel, nav) + RenderReport(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) } is LongTextNoteEvent -> { RenderLongFormContent(baseNote, accountViewModel, nav) @@ -838,6 +790,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -848,6 +801,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -858,6 +812,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -876,6 +831,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -886,6 +842,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -906,8 +863,7 @@ private fun RenderNoteRow( is CommunityPostApprovalEvent -> { RenderPostApproval( baseNote, - makeItShort, - canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -918,6 +874,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -928,6 +885,7 @@ private fun RenderNoteRow( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, editState, accountViewModel, @@ -940,18 +898,18 @@ private fun RenderNoteRow( @Composable fun RenderRepost( note: Note, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val boostedNote = remember { note.replyTo?.lastOrNull() } - - boostedNote?.let { + note.replyTo?.lastOrNull()?.let { NoteCompose( it, modifier = Modifier, isBoostedNote = true, unPackReply = false, + quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, @@ -1048,21 +1006,19 @@ private fun ReplyNoteComposition( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val replyBackgroundColor = remember { mutableStateOf(backgroundColor.value) } val defaultReplyBackground = MaterialTheme.colorScheme.replyBackground - LaunchedEffect(key1 = backgroundColor.value, key2 = defaultReplyBackground) { - launch(Dispatchers.Default) { - val newReplyBackgroundColor = defaultReplyBackground.compositeOver(backgroundColor.value) - if (replyBackgroundColor.value != newReplyBackgroundColor) { - replyBackgroundColor.value = newReplyBackgroundColor - } + val replyBackgroundColor = + remember { + mutableStateOf( + defaultReplyBackground.compositeOver(backgroundColor.value), + ) } - } NoteCompose( baseNote = replyingDirectlyTo, isQuotedNote = true, + quotesLeft = 0, modifier = MaterialTheme.colorScheme.replyModifier, unPackReply = false, makeItShort = true, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index 5b3d75f7c..5a53f964b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -76,6 +76,7 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.routeToMessage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.StringToastMsg +import com.vitorpamplona.amethyst.ui.theme.BigPadding import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.Font14SP @@ -271,6 +272,7 @@ private fun RenderOptionAfterVote( TranslatableRichTextViewer( poolOption.descriptor, canPreview, + quotesLeft = 1, Modifier, tags, backgroundColor, @@ -303,14 +305,15 @@ private fun RenderOptionBeforeVote( ), ) { TranslatableRichTextViewer( - description, - canPreview, - remember { Modifier.padding(15.dp) }, - tags, - backgroundColor, + content = description, + canPreview = canPreview, + quotesLeft = 1, + modifier = BigPadding, + tags = tags, + backgroundColor = backgroundColor, id = description, - accountViewModel, - nav, + accountViewModel = accountViewModel, + nav = nav, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt index 2400fc84e..3a440f4d1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt @@ -29,25 +29,17 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.ui.screen.ZapUserSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.Size25dp import com.vitorpamplona.amethyst.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.ui.theme.Size55dp -import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor @Composable fun ZapUserSetCompose( @@ -57,24 +49,12 @@ fun ZapUserSetCompose( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } - val newItemColor = MaterialTheme.colorScheme.newItemBackgroundColor - - LaunchedEffect(key1 = zapSetCard.createdAt()) { - accountViewModel.loadAndMarkAsRead(routeForLastRead, zapSetCard.createdAt) { isNew -> - val newBackgroundColor = - if (isNew) { - newItemColor.compositeOver(defaultBackgroundColor) - } else { - defaultBackgroundColor - } - - if (backgroundColor.value != newBackgroundColor) { - backgroundColor.value = newBackgroundColor - } - } - } + val backgroundColor = + calculateBackgroundColor( + createdAt = zapSetCard.createdAt, + routeForLastRead = routeForLastRead, + accountViewModel = accountViewModel, + ) Column( modifier = @@ -131,9 +111,5 @@ fun ZapUserSetCompose( Spacer(DoubleVertSpacer) } } - - HorizontalDivider( - thickness = DividerThickness, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt index fc602fabf..9da87947d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt @@ -232,6 +232,7 @@ fun RenderAppDefinition( TranslatableRichTextViewer( content = it, canPreview = false, + quotesLeft = 1, tags = tags, backgroundColor = backgroundColor, id = note.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index 78f442277..0a28b3656 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -216,6 +216,7 @@ fun AudioHeader( TranslatableRichTextViewer( content = it, canPreview = true, + quotesLeft = 1, tags = tags, backgroundColor = background, id = note.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt index f6deaa3fe..1d48419f1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt @@ -62,7 +62,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink @@ -219,15 +218,6 @@ fun RenderBadgeAward( } note.replyTo?.firstOrNull()?.let { - NoteCompose( - it, - modifier = Modifier, - isBoostedNote = false, - isQuotedNote = true, - unPackReply = false, - parentBackgroundColor = backgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) + BadgeDisplay(baseNote = it) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index d3d29c557..5d4dc7884 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -180,6 +180,7 @@ fun LongCommunityHeader( TranslatableRichTextViewer( content = summary ?: stringResource(id = R.string.community_no_descriptor), canPreview = false, + quotesLeft = 1, tags = EmptyTagList, backgroundColor = background, id = baseNote.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index 9be1ef012..9707b8d51 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -74,6 +74,7 @@ fun RenderGitPatchEvent( baseNote: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -85,6 +86,7 @@ fun RenderGitPatchEvent( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -129,6 +131,7 @@ private fun RenderGitPatchEvent( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -180,6 +183,7 @@ private fun RenderGitPatchEvent( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, modifier = modifier, tags = tags, backgroundColor = backgroundColor, @@ -205,6 +209,7 @@ fun RenderGitIssueEvent( baseNote: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -216,6 +221,7 @@ fun RenderGitIssueEvent( baseNote, makeItShort, canPreview, + quotesLeft, backgroundColor, accountViewModel, nav, @@ -228,6 +234,7 @@ private fun RenderGitIssueEvent( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -279,6 +286,7 @@ private fun RenderGitIssueEvent( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, modifier = modifier, tags = tags, backgroundColor = backgroundColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index 3c6f83281..e25cf31b4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -62,6 +62,7 @@ fun RenderHighlight( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -78,6 +79,7 @@ fun RenderHighlight( postAddress = postHex, makeItShort = makeItShort, canPreview = canPreview, + quotesLeft = quotesLeft, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, @@ -92,6 +94,7 @@ fun DisplayHighlight( postAddress: ATag?, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -104,7 +107,8 @@ fun DisplayHighlight( TranslatableRichTextViewer( quote, canPreview = canPreview && !makeItShort, - remember { Modifier.fillMaxWidth() }, + quotesLeft, + Modifier.fillMaxWidth(), EmptyTagList, backgroundColor, id = quote, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt index 4ab4876bb..389505ec4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt @@ -105,6 +105,7 @@ fun RenderPinListEvent( TranslatableRichTextViewer( content = pin, canPreview = true, + quotesLeft = 1, tags = EmptyTagList, backgroundColor = backgroundColor, id = baseNote.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index f9bd72547..9984ecc79 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -46,6 +46,7 @@ fun RenderPoll( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -70,7 +71,8 @@ fun RenderPoll( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview && !makeItShort, - modifier = remember { Modifier.fillMaxWidth() }, + quotesLeft = quotesLeft, + modifier = Modifier.fillMaxWidth(), tags = tags, backgroundColor = backgroundColor, id = note.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt index 84fbc70de..67d88ca68 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt @@ -50,6 +50,7 @@ fun RenderPrivateMessage( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -81,6 +82,7 @@ fun RenderPrivateMessage( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, modifier = modifier, tags = tags, backgroundColor = backgroundColor, @@ -109,12 +111,13 @@ fun RenderPrivateMessage( "@$recipient", ), canPreview = !makeItShort, - Modifier.fillMaxWidth(), - EmptyTagList, - backgroundColor, + quotesLeft = 0, + modifier = Modifier.fillMaxWidth(), + tags = EmptyTagList, + backgroundColor = backgroundColor, id = note.idHex, - accountViewModel, - nav, + accountViewModel = accountViewModel, + nav = nav, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt index d42515700..17a655c2b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun RenderReaction( note: Note, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -42,6 +43,7 @@ fun RenderReaction( modifier = Modifier, isBoostedNote = true, unPackReply = false, + quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt index d9e3c4197..dfa972402 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt @@ -45,8 +45,7 @@ import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent @Composable fun RenderPostApproval( note: Note, - makeItShort: Boolean, - canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -56,12 +55,13 @@ fun RenderPostApproval( val noteEvent = note.event as? CommunityPostApprovalEvent ?: return Column(Modifier.fillMaxWidth()) { - noteEvent.communities().forEach { - LoadAddressableNote(it, accountViewModel) { - it?.let { - NoteCompose( - it, - parentBackgroundColor = backgroundColor, + noteEvent.communities().forEach { tag -> + LoadAddressableNote(tag, accountViewModel) { baseNote -> + baseNote?.let { + CommunityHeader( + baseNote = it, + showBottomDiviser = false, + sendToCommunity = true, accountViewModel = accountViewModel, nav = nav, ) @@ -88,6 +88,7 @@ fun RenderPostApproval( unPackReply = false, makeItShort = true, isQuotedNote = true, + quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt index 7075af94c..6b5fdc63f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt @@ -20,31 +20,26 @@ */ package com.vitorpamplona.amethyst.ui.note.types -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.QuoteBorder -import com.vitorpamplona.amethyst.ui.theme.subtleBorder +import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.ReportEvent @Composable fun RenderReport( note: Note, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -81,6 +76,7 @@ fun RenderReport( tags = EmptyTagList, backgroundColor = backgroundColor, id = note.idHex, + quotesLeft = 1, accountViewModel = accountViewModel, nav = nav, ) @@ -89,18 +85,10 @@ fun RenderReport( NoteCompose( baseNote = it, isQuotedNote = true, - modifier = - Modifier - .padding(top = 5.dp) - .fillMaxWidth() - .clip(shape = QuoteBorder) - .border( - 1.dp, - MaterialTheme.colorScheme.subtleBorder, - QuoteBorder, - ), + modifier = MaterialTheme.colorScheme.replyModifier, unPackReply = false, makeItShort = true, + quotesLeft = quotesLeft - 1, parentBackgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt index 538e4f6a3..8cebd27f4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt @@ -51,6 +51,7 @@ fun RenderTextEvent( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, editState: State>, accountViewModel: AccountViewModel, @@ -103,6 +104,7 @@ fun RenderTextEvent( TranslatableRichTextViewer( content = eventContent, canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, modifier = modifier, tags = tags, backgroundColor = backgroundColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt index 2920ae174..342e0a17c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt @@ -67,6 +67,7 @@ fun RenderTextModificationEvent( note: Note, makeItShort: Boolean, canPreview: Boolean, + quotesLeft: Int, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -113,6 +114,7 @@ fun RenderTextModificationEvent( TranslatableRichTextViewer( content = it, canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, modifier = Modifier.fillMaxWidth(), tags = EmptyTagList, backgroundColor = backgroundColor, @@ -182,6 +184,7 @@ fun RenderTextModificationEvent( makeItShort = false, canPreview = true, showSecondRow = false, + quotesLeft = quotesLeft, backgroundColor = backgroundColor, editState = editState, accountViewModel = accountViewModel, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt index 3137be370..6bb41c231 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt @@ -163,6 +163,7 @@ fun VideoDisplay( TranslatableRichTextViewer( content = it, canPreview = canPreview && !makeItShort, + quotesLeft = 1, modifier = Modifier.fillMaxWidth(), tags = tags, backgroundColor = backgroundColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt index 8bea5062e..4e3a9bfe2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt @@ -31,6 +31,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.pullrefresh.PullRefreshIndicator import androidx.compose.material3.pullrefresh.pullRefresh import androidx.compose.material3.pullrefresh.rememberPullRefreshState @@ -55,6 +56,7 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.ZapTheDevsCard import com.vitorpamplona.amethyst.ui.note.ZapUserSetCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding @Composable @@ -196,6 +198,9 @@ private fun FeedLoaded( nav, ) } + HorizontalDivider( + thickness = DividerThickness, + ) } } } @@ -302,6 +307,7 @@ fun NoteCardCompose( makeItShort = makeItShort, addMarginTop = addMarginTop, showHidden = showHidden, + quotesLeft = 3, parentBackgroundColor = parentBackgroundColor, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index 4330347e0..7ee3b49e3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -38,6 +38,7 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Button +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.material3.pullrefresh.PullRefreshIndicator @@ -56,6 +57,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -227,24 +229,15 @@ private fun FeedLoaded( modifier = Modifier, isBoostedNote = false, showHidden = state.showHidden.value, + quotesLeft = 3, accountViewModel = accountViewModel, nav = nav, ) } - /*var see by - remember { - mutableStateOf(false) - } - - if (see) { - } else { - Row(defaultModifier) { - Button(onClick = { see = true }) { - Text("Show") - } - } - }*/ + HorizontalDivider( + thickness = DividerThickness, + ) } } } 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 f22263a33..052ae3802 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 @@ -263,34 +263,35 @@ fun ThreadFeedView( ) } } else { - Column { - Row { - val selectedNoteColor = MaterialTheme.colorScheme.selectedNote - val background = - remember { - if (item.idHex == noteId) mutableStateOf(selectedNoteColor) else null - } - - NoteCompose( - item, - modifier = - Modifier.drawReplyLevel( - item.replyLevel(), - MaterialTheme.colorScheme.placeholderText, - if (item.idHex == noteId) { - MaterialTheme.colorScheme.lessImportantLink - } else { - MaterialTheme.colorScheme.placeholderText - }, - ), - parentBackgroundColor = background, - isBoostedNote = false, - unPackReply = false, - accountViewModel = accountViewModel, - nav = nav, - ) + val selectedNoteColor = MaterialTheme.colorScheme.selectedNote + val background = + remember { + if (item.idHex == noteId) mutableStateOf(selectedNoteColor) else null } - } + + NoteCompose( + item, + modifier = + Modifier.drawReplyLevel( + item.replyLevel(), + MaterialTheme.colorScheme.placeholderText, + if (item.idHex == noteId) { + MaterialTheme.colorScheme.lessImportantLink + } else { + MaterialTheme.colorScheme.placeholderText + }, + ), + parentBackgroundColor = background, + isBoostedNote = false, + unPackReply = false, + quotesLeft = 3, + accountViewModel = accountViewModel, + nav = nav, + ) + + HorizontalDivider( + thickness = DividerThickness, + ) } } } @@ -376,7 +377,6 @@ fun NoteMaster( note.author?.let { account.isHidden(it) } ?: false, accountViewModel, Modifier, - false, nav, onClick = { showHiddenNote = true }, ) @@ -522,8 +522,7 @@ fun NoteMaster( } else if (noteEvent is CommunityPostApprovalEvent) { RenderPostApproval( baseNote, - false, - true, + quotesLeft = 3, backgroundColor, accountViewModel, nav, @@ -554,9 +553,9 @@ fun NoteMaster( } else if (noteEvent is GitRepositoryEvent) { RenderGitRepositoryEvent(baseNote, accountViewModel, nav) } else if (noteEvent is GitPatchEvent) { - RenderGitPatchEvent(baseNote, false, true, backgroundColor, accountViewModel, nav) + RenderGitPatchEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) } else if (noteEvent is GitIssueEvent) { - RenderGitIssueEvent(baseNote, false, true, backgroundColor, accountViewModel, nav) + RenderGitIssueEvent(baseNote, false, true, quotesLeft = 3, backgroundColor, accountViewModel, nav) } else if (noteEvent is AppDefinitionEvent) { RenderAppDefinition(baseNote, accountViewModel, nav) } else if (noteEvent is HighlightEvent) { @@ -567,17 +566,19 @@ fun NoteMaster( noteEvent.inPost(), false, true, + quotesLeft = 3, backgroundColor, accountViewModel, nav, ) } else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) { - RenderRepost(baseNote, backgroundColor, accountViewModel, nav) + RenderRepost(baseNote, quotesLeft = 3, backgroundColor, accountViewModel, nav) } else if (noteEvent is TextNoteModificationEvent) { RenderTextModificationEvent( note = baseNote, makeItShort = false, canPreview = true, + quotesLeft = 3, backgroundColor, accountViewModel, nav, @@ -592,6 +593,7 @@ fun NoteMaster( baseNote, false, canPreview, + quotesLeft = 3, backgroundColor, accountViewModel, nav, @@ -606,6 +608,7 @@ fun NoteMaster( baseNote, false, canPreview, + quotesLeft = 3, backgroundColor, editState, accountViewModel, @@ -885,6 +888,7 @@ private fun RenderWikiHeaderForThreadPreview() { baseNote!!, false, true, + quotesLeft = 3, backgroundColor, editState, accountViewModel, 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 decf7c3bd..e52c4d40c 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 @@ -681,41 +681,42 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View val relevantReports: ImmutableSet = persistentSetOf(), ) - fun isNoteAcceptable( + suspend fun isNoteAcceptable( note: Note, onReady: (NoteComposeReportState) -> Unit, ) { - viewModelScope.launch(Dispatchers.IO) { - val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex - val isFromLoggedInFollow = note.author?.let { userProfile().isFollowingCached(it) } ?: true + 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 - onReady(NoteComposeReportState(true, true, false, persistentSetOf())) - } else if (note.author?.let { account.isHidden(it) } == true) { - onReady(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 - onReady(NoteComposeReportState(true, true, false, persistentSetOf())) + 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 newRelevantReports = account.getRelevantReports(note) + 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) - onReady( NoteComposeReportState( newIsAcceptable, newCanPreview, false, newRelevantReports.toImmutableSet(), - ), - ) + ) + } } } - } + + onReady(newState) } fun unwrap( @@ -1067,20 +1068,22 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View fun loadAndMarkAsRead( routeForLastRead: String, createdAt: Long?, - onIsNew: (Boolean) -> Unit, - ) { - viewModelScope.launch(Dispatchers.IO) { - val lastTime = account.loadLastRead(routeForLastRead) + ): Boolean { + if (createdAt == null) return false - if (createdAt != null) { + val lastTime = account.loadLastRead(routeForLastRead) + + val onIsNew = createdAt > lastTime + + if (onIsNew) { + viewModelScope.launch(Dispatchers.IO) { if (account.markAsRead(routeForLastRead, createdAt)) { refreshMarkAsReadObservers() } - onIsNew(createdAt > lastTime) - } else { - onIsNew(false) } } + + return onIsNew } fun markAllAsRead( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index ffd73bf12..4bd0fc4a2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -809,6 +809,7 @@ fun LongChannelHeader( TranslatableRichTextViewer( content = summary ?: stringResource(id = R.string.groups_no_descriptor), canPreview = false, + quotesLeft = 1, tags = tags, backgroundColor = background, id = baseChannel.idHex, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 42266113c..ef2cda5e0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1103,6 +1103,7 @@ private fun DrawAdditionalInfo( TranslatableRichTextViewer( content = it, canPreview = false, + quotesLeft = 1, tags = EmptyTagList, backgroundColor = background, id = it, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index 437c0e12b..3663ebf77 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -411,9 +411,14 @@ private fun DisplaySearchResults( ) { _, item -> NoteCompose( item, + quotesLeft = 1, accountViewModel = accountViewModel, nav = nav, ) + + HorizontalDivider( + thickness = DividerThickness, + ) } } } 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 cf77d9a21..5c9ca3a4c 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 @@ -303,7 +303,6 @@ fun RenderReportState( state.isHiddenAuthor, accountViewModel, Modifier.fillMaxWidth(), - false, nav, onClick = { showReportedNote = true }, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index 96424ca0a..c11f32632 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -99,6 +99,7 @@ val HalfTopPadding = Modifier.padding(top = 5.dp) val HalfPadding = Modifier.padding(5.dp) val StdPadding = Modifier.padding(10.dp) +val BigPadding = Modifier.padding(15.dp) val HalfHorzPadding = Modifier.padding(horizontal = 5.dp) val HalfVertPadding = Modifier.padding(vertical = 5.dp) diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 4b27d4234..6f8aab924 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -71,6 +71,7 @@ import java.util.Locale fun TranslatableRichTextViewer( content: String, canPreview: Boolean, + quotesLeft: Int, modifier: Modifier = Modifier, tags: ImmutableListOfLists, backgroundColor: MutableState, @@ -93,15 +94,16 @@ fun TranslatableRichTextViewer( Crossfade(targetState = translatedTextState) { RenderText( - it, - content, - canPreview, - modifier, - tags, - backgroundColor, - id, - accountViewModel, - nav, + translatedTextState = it, + content = content, + canPreview = canPreview, + quotesLeft = quotesLeft, + modifier = modifier, + tags = tags, + backgroundColor = backgroundColor, + id = id, + accountViewModel = accountViewModel, + nav = nav, ) } } @@ -111,6 +113,7 @@ private fun RenderText( translatedTextState: TranslationConfig, content: String, canPreview: Boolean, + quotesLeft: Int, modifier: Modifier, tags: ImmutableListOfLists, backgroundColor: MutableState, @@ -130,6 +133,7 @@ private fun RenderText( ExpandableRichTextViewer( toBeViewed, canPreview, + quotesLeft, modifier, tags, backgroundColor,