From 96d66646b48784d5ccb385fb8605c9b37403d179 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 11 May 2023 14:39:05 -0400 Subject: [PATCH] Displaying lists as Notes --- .../amethyst/ui/dal/NotificationFeedFilter.kt | 10 +- .../amethyst/ui/note/NoteCompose.kt | 118 ++++++++++++++++++ .../amethyst/ui/note/UserCompose.kt | 19 +-- .../amethyst/ui/screen/ThreadFeedView.kt | 5 +- 4 files changed, 143 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt index ea26abdd3..ea06b0771 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt @@ -48,7 +48,15 @@ object NotificationFeedFilter : AdditiveFeedFilter() { val event = note.event if (event is BaseTextNoteEvent) { - return (event.citedUsers().contains(author.pubkeyHex) || note.replyTo?.any { it.author === author } == true) + val isAuthoredPostCited = event.findCitations().any { + LocalCache.notes[it]?.author === author || LocalCache.addressables[it]?.author === author + } + + return isAuthoredPostCited || + ( + event.citedUsers().contains(author.pubkeyHex) || + note.replyTo?.any { it.author === author } == true + ) } if (event is ReactionEvent) { 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 0ed76233f..d1d224dbb 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 @@ -12,6 +12,7 @@ import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -24,6 +25,8 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CutCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem @@ -50,6 +53,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix @@ -81,6 +85,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent @@ -92,6 +97,7 @@ import com.vitorpamplona.amethyst.service.model.FileHeaderEvent import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent import com.vitorpamplona.amethyst.service.model.HighlightEvent import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent +import com.vitorpamplona.amethyst.service.model.PeopleListEvent import com.vitorpamplona.amethyst.service.model.PollNoteEvent import com.vitorpamplona.amethyst.service.model.PrivateDmEvent import com.vitorpamplona.amethyst.service.model.ReactionEvent @@ -366,6 +372,10 @@ fun NoteComposeInner( RenderBadgeAward(note, backgroundColor, accountViewModel, navController) } + is PeopleListEvent -> { + RenderPeopleList(noteState, backgroundColor, accountViewModel, navController) + } + is PrivateDmEvent -> { RenderPrivateMessage(note, makeItShort, isAcceptableAndCanPreview.second, backgroundColor, accountViewModel, navController) } @@ -630,6 +640,114 @@ private fun RenderPrivateMessage( ) } +@Composable +fun RenderPeopleList( + noteState: NoteState?, + backgroundColor: Color, + accountViewModel: AccountViewModel, + navController: NavController +) { + DisplayPeopleList(noteState, backgroundColor, accountViewModel, navController) + + noteState?.note?.let { + ReactionsRow(it, accountViewModel, navController) + } + + Divider( + modifier = Modifier.padding(top = 10.dp), + thickness = 0.25.dp + ) +} + +@Composable +fun DisplayPeopleList( + noteState: NoteState?, + backgroundColor: Color, + accountViewModel: AccountViewModel, + navController: NavController +) { + val note = remember(noteState) { noteState?.note } ?: return + val noteEvent = note.event as? PeopleListEvent ?: return + + var members by remember { mutableStateOf>(listOf()) } + + val account = accountViewModel.userProfile() + var expanded by remember { + mutableStateOf(false) + } + + val toMembersShow = if (expanded) { + members + } else { + members.take(3) + } + + Text( + text = "#${noteEvent.dTag()}", + fontWeight = FontWeight.Bold, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .fillMaxWidth() + .padding(5.dp), + textAlign = TextAlign.Center + ) + + LaunchedEffect(key1 = noteState) { + withContext(Dispatchers.IO) { + members = noteEvent.bookmarkedPeople().mapNotNull { hex -> + LocalCache.checkGetOrCreateUser(hex) + }.sortedBy { account.isFollowing(it) }.reversed() + } + } + + Box { + FlowRow(modifier = Modifier.padding(top = 5.dp)) { + toMembersShow.forEach { user -> + Row(modifier = Modifier.fillMaxWidth()) { + UserCompose( + user, + overallModifier = Modifier, + accountViewModel = accountViewModel, + navController = navController + ) + } + } + } + + if (members.size > 3 && !expanded) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .background( + brush = Brush.verticalGradient( + colors = listOf( + backgroundColor.copy(alpha = 0f), + backgroundColor + ) + ) + ) + ) { + Button( + modifier = Modifier.padding(top = 10.dp), + onClick = { expanded = !expanded }, + shape = RoundedCornerShape(20.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = MaterialTheme.colors.primary.copy(alpha = 0.32f) + .compositeOver(MaterialTheme.colors.background) + ), + contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp) + ) { + Text(text = stringResource(R.string.show_more), color = Color.White) + } + } + } + } +} + @Composable private fun RenderBadgeAward( note: Note, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt index ebcaca546..1164d9067 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt @@ -25,7 +25,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Composable -fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) { +fun UserCompose( + baseUser: User, + overallModifier: Modifier = Modifier + .padding( + start = 12.dp, + end = 12.dp, + top = 10.dp + ), + accountViewModel: AccountViewModel, + navController: NavController +) { val accountState by accountViewModel.accountLiveData.observeAsState() val account = accountState?.account ?: return @@ -41,12 +51,7 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle ) ) { Row( - modifier = Modifier - .padding( - start = 12.dp, - end = 12.dp, - top = 10.dp - ), + modifier = overallModifier, verticalAlignment = Alignment.CenterVertically ) { UserPicture(baseUser, navController, account.userProfile(), 55.dp) 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 0fbcd2ecc..63fb4d985 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 @@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent import com.vitorpamplona.amethyst.service.model.HighlightEvent import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent +import com.vitorpamplona.amethyst.service.model.PeopleListEvent import com.vitorpamplona.amethyst.service.model.PollNoteEvent import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer @@ -349,7 +350,9 @@ fun NoteMaster( ) ) { Column() { - if (noteEvent is HighlightEvent) { + if (noteEvent is PeopleListEvent) { + DisplayPeopleList(noteState, MaterialTheme.colors.background, accountViewModel, navController) + } else if (noteEvent is HighlightEvent) { DisplayHighlight( noteEvent.quote(), noteEvent.author(),