From f2a8e51b207d626eeaaa1c606d50e8fe72baceac Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 15:18:00 -0400 Subject: [PATCH 01/15] Refactors horizontal dividers --- .../amethyst/ui/actions/EditPostView.kt | 5 + .../ui/actions/JoinUserOrChannelView.kt | 47 ++-- .../ui/actions/RelayInformationDialog.kt | 1 - .../amethyst/ui/note/ChannelCardCompose.kt | 7 +- .../amethyst/ui/note/NoteCompose.kt | 3 - .../amethyst/ui/note/RelayCompose.kt | 67 +++--- .../amethyst/ui/note/UserCompose.kt | 31 +-- .../amethyst/ui/note/types/CommunityHeader.kt | 9 - .../amethyst/ui/note/types/PeopleList.kt | 10 +- .../ui/note/types/RenderPostApproval.kt | 1 - .../amethyst/ui/screen/RelayFeedView.kt | 5 + .../amethyst/ui/screen/StringFeedView.kt | 19 +- .../amethyst/ui/screen/ThreadFeedView.kt | 201 ++++++++---------- .../amethyst/ui/screen/UserFeedView.kt | 5 + .../ui/screen/loggedIn/ChannelScreen.kt | 14 +- .../ui/screen/loggedIn/ChatroomScreen.kt | 6 + .../ui/screen/loggedIn/HashtagScreen.kt | 31 +-- .../ui/screen/loggedIn/HiddenUsersScreen.kt | 4 - .../ui/screen/loggedIn/NotificationScreen.kt | 8 +- .../ui/screen/loggedIn/ProfileScreen.kt | 23 +- .../ui/screen/loggedIn/SearchScreen.kt | 82 ++++--- .../ui/screen/loggedIn/ThreadScreen.kt | 7 +- 22 files changed, 255 insertions(+), 331 deletions(-) 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 48e094605..dd0df3768 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 @@ -46,6 +46,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CurrencyBitcoin import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle @@ -98,6 +99,7 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size5dp @@ -448,6 +450,9 @@ fun ShowUserSuggestionListForEdit( key = { _, item -> item.pubkeyHex }, ) { _, item -> UserLine(item, accountViewModel) { editPostViewModel.autocompleteWithUser(item) } + HorizontalDivider( + thickness = DividerThickness, + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt index d6bf6f367..4cda055f4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt @@ -357,6 +357,10 @@ private fun RenderSearchResults( searchBarViewModel.clear() } + + HorizontalDivider( + thickness = DividerThickness, + ) } itemsIndexed( @@ -367,6 +371,10 @@ private fun RenderSearchResults( nav("Channel/${item.idHex}") searchBarViewModel.clear() } + + HorizontalDivider( + thickness = DividerThickness, + ) } } } @@ -404,39 +412,30 @@ fun UserComposeForChat( accountViewModel: AccountViewModel, onClick: () -> Unit, ) { - Column( + Row( modifier = Modifier.clickable( onClick = onClick, + ).padding( + start = 12.dp, + end = 12.dp, + top = 10.dp, + bottom = 10.dp, ), + verticalAlignment = Alignment.CenterVertically, ) { - Row( + ClickableUserPicture(baseUser, Size55dp, accountViewModel) + + Column( modifier = - Modifier.padding( - start = 12.dp, - end = 12.dp, - top = 10.dp, - ), - verticalAlignment = Alignment.CenterVertically, + Modifier + .padding(start = 10.dp) + .weight(1f), ) { - ClickableUserPicture(baseUser, Size55dp, accountViewModel) + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } - Column( - modifier = - Modifier - .padding(start = 10.dp) - .weight(1f), - ) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } - - DisplayUserAboutInfo(baseUser) - } + DisplayUserAboutInfo(baseUser) } - - HorizontalDivider( - modifier = Modifier.padding(top = 10.dp), - thickness = DividerThickness, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelayInformationDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelayInformationDialog.kt index 464d7ec82..c8c44970e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelayInformationDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelayInformationDialog.kt @@ -294,7 +294,6 @@ private fun DisplayOwnerInformation( UserCompose( baseUser = it, accountViewModel = accountViewModel, - showDiviser = false, nav = nav, ) } 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 8b31f6994..785a92a64 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 @@ -197,7 +197,7 @@ fun InnerChannelCardWithReactions( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - when (remember { baseNote.event }) { + when (baseNote.event) { is LiveActivitiesEvent -> { InnerCardRow(baseNote, accountViewModel, nav) } @@ -496,12 +496,11 @@ fun RenderLiveActivityThumb( Spacer(modifier = DoubleVertSpacer) ChannelHeader( - channelHex = remember { baseNote.idHex }, + channelHex = baseNote.idHex, showVideo = false, - showBottomDiviser = false, showFlag = false, sendToChannel = true, - modifier = remember { Modifier.padding(start = 0.dp, end = 0.dp, top = 5.dp, bottom = 5.dp) }, + modifier = Modifier, accountViewModel = accountViewModel, nav = nav, ) 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 bbf0f7ecf..b8544aae3 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 @@ -233,7 +233,6 @@ fun AcceptableNote( ChannelHeader( channelNote = baseNote, showVideo = !makeItShort, - showBottomDiviser = true, sendToChannel = true, accountViewModel = accountViewModel, nav = nav, @@ -267,7 +266,6 @@ fun AcceptableNote( ChannelHeader( channelNote = baseNote, showVideo = !makeItShort, - showBottomDiviser = true, sendToChannel = true, accountViewModel = accountViewModel, nav = nav, @@ -742,7 +740,6 @@ private fun ReplyRow( ChannelHeader( channelHex = it, showVideo = false, - showBottomDiviser = false, sendToChannel = true, modifier = MaterialTheme.colorScheme.replyModifier.padding(10.dp), accountViewModel = accountViewModel, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt index a39aa5c26..572700fac 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.ui.note +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -47,7 +47,7 @@ import com.vitorpamplona.amethyst.model.RelayInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding -import com.vitorpamplona.amethyst.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import java.time.Instant import java.time.ZoneId @@ -62,49 +62,44 @@ fun RelayCompose( ) { val context = LocalContext.current - Column { - Row( - modifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 10.dp), + Row( + modifier = StdPadding, + verticalAlignment = Alignment.CenterVertically, + ) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.Center, ) { - Column( - modifier = Modifier.padding(start = 10.dp).weight(1f), - ) { - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { - Text( - relay.url.trim().removePrefix("wss://"), - fontWeight = FontWeight.Bold, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - - val lastTime by - remember(relay.lastEvent) { - derivedStateOf { timeAgo(relay.lastEvent, context = context) } - } - - Text( - text = lastTime, - maxLines = 1, - ) - } - + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Text( - "${relay.counter} ${stringResource(R.string.posts_received)}", - color = MaterialTheme.colorScheme.placeholderText, + relay.url.trim().removePrefix("wss://"), + fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, ) + + val lastTime by + remember(relay.lastEvent) { + derivedStateOf { timeAgo(relay.lastEvent, context = context) } + } + + Text( + text = lastTime, + maxLines = 1, + ) } - Column(modifier = Modifier.padding(start = 10.dp)) { - RelayOptions(accountViewModel, relay, onAddRelay, onRemoveRelay) - } + Text( + "${relay.counter} ${stringResource(R.string.posts_received)}", + color = MaterialTheme.colorScheme.placeholderText, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) } - HorizontalDivider( - modifier = Modifier.padding(top = 10.dp), - thickness = DividerThickness, - ) + Column(modifier = Modifier.padding(start = 10.dp)) { + RelayOptions(accountViewModel, relay, onAddRelay, onRemoveRelay) + } } } 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 6026fb233..89ef9551f 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 @@ -24,7 +24,6 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -32,7 +31,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.StdPadding @@ -40,37 +38,26 @@ import com.vitorpamplona.amethyst.ui.theme.StdPadding fun UserCompose( baseUser: User, overallModifier: Modifier = StdPadding, - showDiviser: Boolean = true, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - Column( + Row( modifier = - Modifier.clickable( + overallModifier.clickable( onClick = { nav("User/${baseUser.pubkeyHex}") }, ), + verticalAlignment = Alignment.CenterVertically, ) { - Row( - modifier = overallModifier, - verticalAlignment = Alignment.CenterVertically, - ) { - UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav) + UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav) - Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } + Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) { + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } - AboutDisplay(baseUser) - } - - Column(modifier = remember { Modifier.padding(start = 10.dp) }) { - UserActionOptions(baseUser, accountViewModel) - } + AboutDisplay(baseUser) } - if (showDiviser) { - HorizontalDivider( - thickness = DividerThickness, - ) + Column(modifier = remember { Modifier.padding(start = 10.dp) }) { + UserActionOptions(baseUser, accountViewModel) } } } 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 5d4dc7884..b38464f8d 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 @@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -68,7 +67,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.JoinCommunityButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.LeaveCommunityButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.NormalTimeAgo -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.ui.theme.Size10dp @@ -88,7 +86,6 @@ import java.util.Locale @Composable fun CommunityHeader( baseNote: AddressableNote, - showBottomDiviser: Boolean, sendToCommunity: Boolean, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, @@ -125,12 +122,6 @@ fun CommunityHeader( } } } - - if (showBottomDiviser) { - HorizontalDivider( - thickness = DividerThickness, - ) - } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt index a5d6c2ae0..59d146f47 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt @@ -23,11 +23,13 @@ package com.vitorpamplona.amethyst.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -50,6 +52,7 @@ import com.vitorpamplona.amethyst.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.quartz.events.PeopleListEvent import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -98,13 +101,16 @@ fun DisplayPeopleList( Box { FlowRow(modifier = Modifier.padding(top = 5.dp)) { toMembersShow.forEach { user -> - Row(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.fillMaxWidth()) { UserCompose( user, - overallModifier = Modifier, accountViewModel = accountViewModel, nav = nav, ) + + HorizontalDivider( + thickness = DividerThickness, + ) } } } 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 dfa972402..335ca8f7d 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 @@ -60,7 +60,6 @@ fun RenderPostApproval( baseNote?.let { CommunityHeader( baseNote = it, - showBottomDiviser = false, sendToCommunity = true, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt index 5203b1b8b..2b80040b3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn 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 @@ -47,6 +48,7 @@ import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.components.BundledUpdate import com.vitorpamplona.amethyst.ui.note.RelayCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -169,6 +171,9 @@ fun RelayFeedView( onAddRelay = { wantsToAddRelay = item.url }, onRemoveRelay = { wantsToAddRelay = item.url }, ) + HorizontalDivider( + thickness = DividerThickness, + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt index e1f3a41d6..c3561e544 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -37,17 +38,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding -@Composable -fun RefreshingFeedStringFeedView( - viewModel: StringFeedViewModel, - enablePullRefresh: Boolean = true, - inner: @Composable (String) -> Unit, -) { - RefresheableBox(viewModel, enablePullRefresh) { StringFeedView(viewModel, inner = inner) } -} - @Composable fun StringFeedView( viewModel: StringFeedViewModel, @@ -112,7 +105,13 @@ private fun FeedLoaded( ) { item { pre?.let { it() } } - itemsIndexed(state.feed.value, key = { _, item -> item }) { _, item -> inner(item) } + itemsIndexed(state.feed.value, key = { _, item -> item }) { _, item -> + inner(item) + + HorizontalDivider( + thickness = DividerThickness, + ) + } item { post?.let { it() } } } 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 5324ec45c..ac8f8125c 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 @@ -20,13 +20,10 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade -import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable 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.Row import androidx.compose.foundation.layout.Spacer @@ -35,6 +32,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size 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.foundation.text.KeyboardOptions @@ -49,9 +47,6 @@ import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.pullrefresh.PullRefreshIndicator -import androidx.compose.material3.pullrefresh.pullRefresh -import androidx.compose.material3.pullrefresh.rememberPullRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -80,7 +75,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp -import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache @@ -147,7 +141,6 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size24Modifier import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.theme.StdTopPadding import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -195,117 +188,100 @@ fun ThreadFeedView( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - val listState = rememberLazyListState() - var refreshing by remember { mutableStateOf(false) } - val refresh = { - refreshing = true - viewModel.invalidateData() - refreshing = false + RefresheableBox(viewModel) { + RenderFeedState( + viewModel = viewModel, + accountViewModel = accountViewModel, + listState = listState, + nav = nav, + routeForLastRead = null, + onLoaded = { + RenderThreadFeed(noteId, it, listState, accountViewModel, nav) + }, + ) } - val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh = refresh) +} - Box(Modifier.pullRefresh(pullRefreshState)) { - Column { - Crossfade( - targetState = feedState, - animationSpec = tween(durationMillis = 100), - label = "ThreadViewMainState", - ) { state -> - when (state) { - is FeedState.Empty -> { - FeedEmpty { refreshing = true } - } - is FeedState.FeedError -> { - FeedError(state.errorMessage) { refreshing = true } - } - is FeedState.Loaded -> { - refreshing = false - LaunchedEffect(noteId) { - launch(Dispatchers.IO) { - // waits to load the thread to scroll to item. - delay(100) - val noteForPosition = state.feed.value.filter { it.idHex == noteId }.firstOrNull() - var position = state.feed.value.indexOf(noteForPosition) +@Composable +fun RenderThreadFeed( + noteId: String, + state: FeedState.Loaded, + listState: LazyListState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + LaunchedEffect(noteId) { + // waits to load the thread to scroll to item. + delay(100) + val noteForPosition = state.feed.value.filter { it.idHex == noteId }.firstOrNull() + var position = state.feed.value.indexOf(noteForPosition) - if (position >= 0) { - if (position >= 1 && position < state.feed.value.size - 1) { - position-- // show the replying note - } - - withContext(Dispatchers.Main) { listState.scrollToItem(position) } - } - } - } - - LazyColumn( - contentPadding = FeedPadding, - state = listState, - ) { - itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { index, item -> - if (index == 0) { - ProvideTextStyle(TextStyle(fontSize = 18.sp, lineHeight = 1.20.em)) { - NoteMaster( - item, - modifier = - Modifier.drawReplyLevel( - item.replyLevel(), - MaterialTheme.colorScheme.placeholderText, - if (item.idHex == noteId) { - MaterialTheme.colorScheme.lessImportantLink - } else { - MaterialTheme.colorScheme.placeholderText - }, - ), - accountViewModel = accountViewModel, - nav = nav, - ) - } - } else { - 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( - modifier = StdTopPadding, - thickness = DividerThickness, - ) - } - } - } - FeedState.Loading -> { - LoadingFeed() - } - } + if (position >= 0) { + if (position >= 1 && position < state.feed.value.size - 1) { + position-- // show the replying note } - } - PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter)) + listState.scrollToItem(position) + } + } + + LazyColumn( + contentPadding = FeedPadding, + state = listState, + ) { + itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { index, item -> + if (index == 0) { + ProvideTextStyle(TextStyle(fontSize = 18.sp, lineHeight = 1.20.em)) { + NoteMaster( + item, + modifier = + Modifier.drawReplyLevel( + item.replyLevel(), + MaterialTheme.colorScheme.placeholderText, + if (item.idHex == noteId) { + MaterialTheme.colorScheme.lessImportantLink + } else { + MaterialTheme.colorScheme.placeholderText + }, + ), + accountViewModel = accountViewModel, + nav = nav, + ) + } + } else { + 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, + ) + } } } @@ -504,7 +480,6 @@ fun NoteMaster( ChannelHeader( channelHex = note.channelHex()!!, showVideo = true, - showBottomDiviser = false, sendToChannel = true, accountViewModel = accountViewModel, nav = nav, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt index bc52f5c4a..bc1ee84fe 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt @@ -25,11 +25,13 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding @Composable @@ -82,6 +84,9 @@ private fun FeedLoaded( ) { itemsIndexed(state.feed.value, key = { _, item -> item.pubkeyHex }) { _, item -> UserCompose(item, accountViewModel = accountViewModel, nav = nav) + HorizontalDivider( + thickness = DividerThickness, + ) } } } 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 4bd0fc4a2..774a2c432 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 @@ -53,7 +53,6 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle @@ -139,7 +138,6 @@ import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding -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.EditFieldBorder @@ -557,7 +555,6 @@ fun MyTextField( fun ChannelHeader( channelNote: Note, showVideo: Boolean, - showBottomDiviser: Boolean, sendToChannel: Boolean, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, @@ -568,8 +565,8 @@ fun ChannelHeader( ChannelHeader( channelHex = it, showVideo = showVideo, - showBottomDiviser = showBottomDiviser, sendToChannel = sendToChannel, + modifier = modifier, accountViewModel = accountViewModel, nav = nav, ) @@ -580,7 +577,6 @@ fun ChannelHeader( fun ChannelHeader( channelHex: String, showVideo: Boolean, - showBottomDiviser: Boolean, showFlag: Boolean = true, sendToChannel: Boolean = false, modifier: Modifier = StdPadding, @@ -591,7 +587,6 @@ fun ChannelHeader( ChannelHeader( it, showVideo, - showBottomDiviser, showFlag, sendToChannel, modifier, @@ -605,7 +600,6 @@ fun ChannelHeader( fun ChannelHeader( baseChannel: Channel, showVideo: Boolean, - showBottomDiviser: Boolean, showFlag: Boolean = true, sendToChannel: Boolean = false, modifier: Modifier = StdPadding, @@ -641,12 +635,6 @@ fun ChannelHeader( LongChannelHeader(baseChannel = baseChannel, accountViewModel = accountViewModel, nav = nav) } } - - if (showBottomDiviser) { - HorizontalDivider( - thickness = DividerThickness, - ) - } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index 048738d96..2e378f268 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -491,6 +491,9 @@ fun ShowUserSuggestionList( key = { _, item -> item.pubkeyHex }, ) { _, item -> UserLine(item, accountViewModel) { channelScreenModel.autocompleteWithUser(item) } + HorizontalDivider( + thickness = DividerThickness, + ) } } } @@ -807,6 +810,9 @@ fun LongRoomHeader( accountViewModel = accountViewModel, nav = nav, ) + HorizontalDivider( + thickness = DividerThickness, + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt index 2132d88ae..bce5dd76b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -47,7 +46,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.NostrHashtagDataSource import com.vitorpamplona.amethyst.ui.screen.NostrHashtagFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.StdPadding @Composable @@ -142,27 +140,18 @@ fun HashtagHeader( account: AccountViewModel, onClick: () -> Unit = {}, ) { - Column( - Modifier.fillMaxWidth().clickable { onClick() }, + Row( + modifier = Modifier.fillMaxWidth().clickable { onClick() }.then(modifier), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, ) { - Column(modifier = modifier) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - ) { - Text( - "#$tag", - fontWeight = FontWeight.Bold, - modifier = Modifier.weight(1f), - ) - - HashtagActionOptions(tag, account) - } - } - - HorizontalDivider( - thickness = DividerThickness, + Text( + "#$tag", + fontWeight = FontWeight.Bold, + modifier = Modifier.weight(1f), ) + + HashtagActionOptions(tag, account) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt index a2ff9649a..37ee700b9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt @@ -312,10 +312,6 @@ fun MutedWordHeader( MutedWordActionOptions(tag, account) } } - - HorizontalDivider( - thickness = DividerThickness, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt index 2ba1c7532..d607f0ba5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt @@ -120,7 +120,9 @@ fun NotificationScreen( SummaryBar( model = userReactionsStatsModel, ) - + HorizontalDivider( + thickness = DividerThickness, + ) RefreshableCardView( viewModel = notifFeedViewModel, accountViewModel = accountViewModel, @@ -229,10 +231,6 @@ fun SummaryBar(model: UserReactionsViewModel) { } } } - - HorizontalDivider( - thickness = DividerThickness, - ) } @Composable 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 ef2cda5e0..b6995fe4f 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 @@ -1547,18 +1547,17 @@ fun TabFollowedTags( account: AccountViewModel, nav: (String) -> Unit, ) { - Column(Modifier.fillMaxHeight()) { - Column( - modifier = Modifier.padding(vertical = 0.dp), - ) { - baseUser.latestContactList?.let { - it.unverifiedFollowTagSet().forEach { hashtag -> - HashtagHeader( - tag = hashtag, - account = account, - onClick = { nav("Hashtag/$hashtag") }, - ) - } + Column(Modifier.fillMaxHeight().padding(vertical = 0.dp)) { + baseUser.latestContactList?.let { + it.unverifiedFollowTagSet().forEach { hashtag -> + HashtagHeader( + tag = hashtag, + account = account, + onClick = { nav("Hashtag/$hashtag") }, + ) + HorizontalDivider( + thickness = DividerThickness, + ) } } } 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 026a81072..426131ee0 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 @@ -374,6 +374,11 @@ private fun DisplaySearchResults( key = { _, item -> "#$item" }, ) { _, item -> HashtagLine(item) { nav("Hashtag/$item") } + + HorizontalDivider( + modifier = Modifier.padding(top = 10.dp), + thickness = DividerThickness, + ) } itemsIndexed( @@ -381,6 +386,10 @@ private fun DisplaySearchResults( key = { _, item -> "u" + item.pubkeyHex }, ) { _, item -> UserCompose(item, accountViewModel = accountViewModel, nav = nav) + + HorizontalDivider( + thickness = DividerThickness, + ) } itemsIndexed( @@ -432,33 +441,24 @@ fun HashtagLine( tag: String, onClick: () -> Unit, ) { - Column( - modifier = Modifier.fillMaxWidth().clickable(onClick = onClick), + Row( + modifier = + Modifier.fillMaxWidth().clickable(onClick = onClick).padding( + start = 12.dp, + end = 12.dp, + top = 10.dp, + ), ) { Row( - modifier = - Modifier.padding( - start = 12.dp, - end = 12.dp, - top = 10.dp, - ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth(), ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth(), - ) { - Text( - "Search hashtag: #$tag", - fontWeight = FontWeight.Bold, - ) - } + Text( + "Search hashtag: #$tag", + fontWeight = FontWeight.Bold, + ) } - - HorizontalDivider( - modifier = Modifier.padding(top = 10.dp), - thickness = DividerThickness, - ) } } @@ -468,31 +468,23 @@ fun UserLine( accountViewModel: AccountViewModel, onClick: () -> Unit, ) { - Column( - modifier = Modifier.fillMaxWidth().clickable(onClick = onClick), + Row( + modifier = + Modifier.fillMaxWidth().clickable(onClick = onClick).padding( + start = 12.dp, + end = 12.dp, + top = 10.dp, + bottom = 10.dp, + ), ) { - Row( - modifier = - Modifier.padding( - start = 12.dp, - end = 12.dp, - top = 10.dp, - ), + ClickableUserPicture(baseUser, 55.dp, accountViewModel, Modifier, null) + + Column( + modifier = Modifier.padding(start = 10.dp).weight(1f), ) { - ClickableUserPicture(baseUser, 55.dp, accountViewModel, Modifier, null) + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } - Column( - modifier = Modifier.padding(start = 10.dp).weight(1f), - ) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } - - AboutDisplay(baseUser) - } + AboutDisplay(baseUser) } - - HorizontalDivider( - modifier = Modifier.padding(top = 10.dp), - thickness = DividerThickness, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt index 78219e9b0..9ac6ed716 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt @@ -20,11 +20,8 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -79,7 +76,5 @@ fun ThreadScreen( onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) } } - Column(Modifier.fillMaxHeight()) { - Column { ThreadFeedView(noteId, feedViewModel, accountViewModel, nav) } - } + ThreadFeedView(noteId, feedViewModel, accountViewModel, nav) } From 97cdc0bc7a08050c03ee264c3327032473a8b859 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 16:02:49 -0400 Subject: [PATCH 02/15] Fixes layout issues of LongForm content when the image is not present. --- .../ui/note/elements/DefaultImageHeader.kt | 64 ++++++++----- .../amethyst/ui/note/types/Classifieds.kt | 3 +- .../amethyst/ui/note/types/Emoji.kt | 3 +- .../amethyst/ui/note/types/LongForm.kt | 91 ++++++++++--------- .../amethyst/ui/note/types/Video.kt | 3 +- .../amethyst/ui/screen/ThreadFeedView.kt | 58 ++++++------ 6 files changed, 122 insertions(+), 100 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt index 055f77bd0..488cf5861 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt @@ -22,17 +22,23 @@ package com.vitorpamplona.amethyst.ui.note.elements import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.authorNotePictureForImageHeader @@ -43,28 +49,42 @@ fun DefaultImageHeader( note: Note, accountViewModel: AccountViewModel, ) { - Box { - note.author?.info?.banner?.let { - AsyncImage( - model = it, - contentDescription = - stringResource( - R.string.preview_card_image_for, - it, - ), - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth(), - ) - } - ?: Image( - painter = painterResource(R.drawable.profile_banner), - contentDescription = stringResource(R.string.profile_banner), - contentScale = ContentScale.FillWidth, - modifier = imageHeaderBannerSize, - ) + val authorState by note.live().authorChanges.observeAsState(note.author) - Box(authorNotePictureForImageHeader.align(Alignment.BottomStart)) { - NoteAuthorPicture(baseNote = note, accountViewModel = accountViewModel, size = Size55dp) + authorState?.let { author -> + Box { + BannerImage(author) + + Box(authorNotePictureForImageHeader.align(Alignment.BottomStart)) { + BaseUserPicture(author, Size55dp, accountViewModel, Modifier) + } } } } + +@Composable +private fun BoxScope.BannerImage(author: User) { + val currentInfo by author.live().userMetadataInfo.observeAsState() + currentInfo?.banner?.let { + AsyncImage( + model = it, + contentDescription = + stringResource( + R.string.preview_card_image_for, + it, + ), + contentScale = ContentScale.FillWidth, + modifier = + Modifier + .fillMaxWidth() + .heightIn(max = 200.dp), + ) + } ?: run { + Image( + painter = painterResource(R.drawable.profile_banner), + contentDescription = stringResource(R.string.profile_banner), + contentScale = ContentScale.FillWidth, + modifier = imageHeaderBannerSize, + ) + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt index 6d586ca52..905dd8283 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt @@ -88,8 +88,9 @@ fun RenderClassifieds( contentScale = ContentScale.FillWidth, modifier = Modifier.fillMaxWidth(), ) + } ?: run { + DefaultImageHeader(note, accountViewModel) } - ?: DefaultImageHeader(note, accountViewModel) } Row( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt index 2e767e945..6f4d32154 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt @@ -127,8 +127,9 @@ private fun WikiNoteHeader( contentScale = ContentScale.FillWidth, modifier = Modifier.fillMaxWidth(), ) + } ?: run { + DefaultImageHeader(note, accountViewModel) } - ?: DefaultImageHeader(note, accountViewModel) } title?.let { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt index f4584efbe..9ac340cf6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note.types import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -65,14 +64,14 @@ private fun LongFormHeader( note: Note, accountViewModel: AccountViewModel, ) { - val image = remember(noteEvent) { noteEvent.image() } - val title = remember(noteEvent) { noteEvent.title() } + val image = noteEvent.image() + val title = noteEvent.title() val summary = remember(noteEvent) { noteEvent.summary()?.ifBlank { null } ?: noteEvent.content.take(200).ifBlank { null } } - Row( + Column( modifier = Modifier .padding(top = Size5dp) @@ -83,51 +82,53 @@ private fun LongFormHeader( QuoteBorder, ), ) { - Column { - val automaticallyShowUrlPreview = - remember { accountViewModel.settings.showUrlPreview.value } + val automaticallyShowUrlPreview = + remember { accountViewModel.settings.showImages.value } - if (automaticallyShowUrlPreview) { - image?.let { - AsyncImage( - model = it, - contentDescription = - stringResource( - R.string.preview_card_image_for, - it, - ), - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth(), - ) - } - ?: DefaultImageHeader(note, accountViewModel) - } - - title?.let { - Text( - text = it, - style = MaterialTheme.typography.bodyLarge, - modifier = - Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp, top = 10.dp), + if (automaticallyShowUrlPreview) { + println("ImagePreview: $title $image") + image?.let { + println("ImagePreview: Drawing $title $image") + AsyncImage( + model = it, + contentDescription = + stringResource( + R.string.preview_card_image_for, + it, + ), + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxWidth(), ) + } ?: run { + println("ImagePreview: DefaultHeader $title $image") + DefaultImageHeader(note, accountViewModel) } + } - summary?.let { - Spacer(modifier = StdVertSpacer) - Text( - text = it, - style = MaterialTheme.typography.bodySmall, - modifier = - Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp, bottom = 10.dp), - color = Color.Gray, - maxLines = 3, - overflow = TextOverflow.Ellipsis, - ) - } + title?.let { + Text( + text = it, + style = MaterialTheme.typography.bodyLarge, + modifier = + Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp, top = 10.dp), + ) + } + + summary?.let { + Spacer(modifier = StdVertSpacer) + Text( + text = it, + style = MaterialTheme.typography.bodySmall, + modifier = + Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp, bottom = 10.dp), + color = Color.Gray, + maxLines = 3, + overflow = TextOverflow.Ellipsis, + ) } } } 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 6bb41c231..8f094ed55 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 @@ -135,8 +135,9 @@ fun VideoDisplay( contentScale = ContentScale.FillWidth, modifier = MaterialTheme.colorScheme.imageModifier, ) + } ?: run { + DefaultImageHeader(note, accountViewModel) } - ?: DefaultImageHeader(note, accountViewModel) } } else { ZoomableContentView( 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 ac8f8125c..dadf8f9a1 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 @@ -789,43 +789,41 @@ private fun RenderClassifiedsReaderForThread( @Composable private fun RenderLongFormHeaderForThread(noteEvent: LongTextNoteEvent) { - Row(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) { - Column { - noteEvent.image()?.let { - AsyncImage( - model = it, - contentDescription = - stringResource( - R.string.preview_card_image_for, - it, - ), - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth(), - ) - } + Column(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) { + noteEvent.image()?.let { + AsyncImage( + model = it, + contentDescription = + stringResource( + R.string.preview_card_image_for, + it, + ), + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxWidth(), + ) + } - noteEvent.title()?.let { + noteEvent.title()?.let { + Spacer(modifier = DoubleVertSpacer) + Text( + text = it, + fontSize = 28.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.fillMaxWidth(), + ) + } + + noteEvent + .summary() + ?.ifBlank { null } + ?.let { Spacer(modifier = DoubleVertSpacer) Text( text = it, - fontSize = 28.sp, - fontWeight = FontWeight.Bold, modifier = Modifier.fillMaxWidth(), + color = Color.Gray, ) } - - noteEvent - .summary() - ?.ifBlank { null } - ?.let { - Spacer(modifier = DoubleVertSpacer) - Text( - text = it, - modifier = Modifier.fillMaxWidth(), - color = Color.Gray, - ) - } - } } } From ceca149eb74e96f6a559243262f32192a3ba183c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 16:03:13 -0400 Subject: [PATCH 03/15] Doesn't show edits of blog posts in the User's Profile --- .../amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt index 63923c457..629cfa1ed 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/UserProfileNewThreadFeedFilter.kt @@ -21,9 +21,11 @@ package com.vitorpamplona.amethyst.ui.dal import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.quartz.events.AddressableEvent import com.vitorpamplona.quartz.events.AudioHeaderEvent import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent @@ -43,7 +45,7 @@ class UserProfileNewThreadFeedFilter(val user: User, val account: Account) : override fun feed(): List { val notes = LocalCache.notes.filterIntoSet { _, it -> - acceptableEvent(it) + it !is AddressableNote && it.event !is AddressableEvent && acceptableEvent(it) } val longFormNotes = From 538c0493edc9b4ae78ad7e5e20f94557255c4fb9 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 20 Mar 2024 17:20:35 -0300 Subject: [PATCH 04/15] add a lifeCycleOwner to register external signer on resume --- .../amethyst/ui/screen/AccountScreen.kt | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index 973d531ef..880e1ba63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -37,7 +37,10 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.ViewModelStore import androidx.lifecycle.ViewModelStoreOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -120,6 +123,7 @@ fun LoggedInPage( accountViewModel.serviceManager = activity.serviceManager if (accountViewModel.account.signer is NostrSignerExternal) { + val lifeCycleOwner = LocalLifecycleOwner.current val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult(), @@ -137,7 +141,30 @@ fun LoggedInPage( }, ) - DisposableEffect(accountViewModel, accountViewModel.account, launcher, activity) { + DisposableEffect(accountViewModel, accountViewModel.account, launcher, activity, lifeCycleOwner) { + val observer = + LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_RESUME) { + accountViewModel.account.signer.launcher.registerLauncher( + launcher = { + try { + activity.prepareToLaunchSigner() + launcher.launch(it) + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("Signer", "Error opening Signer app", e) + accountViewModel.toast( + R.string.error_opening_external_signer, + R.string.error_opening_external_signer_description, + ) + } + }, + contentResolver = { Amethyst.instance.contentResolver }, + ) + } + } + + lifeCycleOwner.lifecycle.addObserver(observer) accountViewModel.account.signer.launcher.registerLauncher( launcher = { try { @@ -154,7 +181,11 @@ fun LoggedInPage( }, contentResolver = { Amethyst.instance.contentResolver }, ) - onDispose { accountViewModel.account.signer.launcher.clearLauncher() } + onDispose { + Log.d("onDispose", "Called onDispose") + accountViewModel.account.signer.launcher.clearLauncher() + lifeCycleOwner.lifecycle.removeObserver(observer) + } } } From f3c4b3255b42fa499aedd83dcce68ed26f08e165 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 16:47:53 -0400 Subject: [PATCH 05/15] Fixes missing context in some replies to blog posts. --- .../amethyst/ui/note/NoteCompose.kt | 10 ++++++---- .../quartz/events/BaseTextNoteEvent.kt | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) 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 b8544aae3..32f57fac8 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 @@ -751,11 +751,13 @@ private fun ReplyRow( val replyingDirectlyTo = remember(note) { if (noteEvent is BaseTextNoteEvent) { - val replyingTo = noteEvent.replyingTo() + val replyingTo = noteEvent.replyingToAddressOrEvent() if (replyingTo != null) { - note.replyTo?.firstOrNull { - // important to test both ids in case it's a replaceable event. - it.idHex == replyingTo || it.event?.id() == replyingTo + val newNote = accountViewModel.getNoteIfExists(replyingTo) + if (newNote != null && newNote.channelHex() == null && newNote.event?.kind() != CommunityDefinitionEvent.KIND) { + newNote + } else { + note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND } } } else { note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt index aa65eb642..503944e38 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt @@ -79,6 +79,22 @@ open class BaseTextNoteEvent( return newStyleReply ?: newStyleRoot ?: oldStylePositional } + fun replyingToAddress(): ATag? { + val oldStylePositional = tags.lastOrNull { it.size > 1 && it[0] == "a" }?.let { ATag.parseAtag(it[1], it[2]) } + val newStyleReply = tags.lastOrNull { it.size > 3 && it[0] == "a" && it[3] == "reply" }?.let { ATag.parseAtag(it[1], it[2]) } + val newStyleRoot = tags.lastOrNull { it.size > 3 && it[0] == "a" && it[3] == "root" }?.let { ATag.parseAtag(it[1], it[2]) } + + return newStyleReply ?: newStyleRoot ?: oldStylePositional + } + + fun replyingToAddressOrEvent(): String? { + val oldStylePositional = tags.lastOrNull { it.size > 1 && (it[0] == "e" || it[0] == "a") }?.get(1) + val newStyleReply = tags.lastOrNull { it.size > 3 && (it[0] == "e" || it[0] == "a") && it[3] == "reply" }?.get(1) + val newStyleRoot = tags.lastOrNull { it.size > 3 && (it[0] == "e" || it[0] == "a") && it[3] == "root" }?.get(1) + + return newStyleReply ?: newStyleRoot ?: oldStylePositional + } + @Transient private var citedUsersCache: Set? = null @Transient private var citedNotesCache: Set? = null From fd39ff24e1f5f7e39ba0e680d2dad467b39974dc Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 16:48:24 -0400 Subject: [PATCH 06/15] Adds a space after the Channel header in the reply rows --- .../main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt | 1 + 1 file changed, 1 insertion(+) 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 32f57fac8..4dd648350 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 @@ -745,6 +745,7 @@ private fun ReplyRow( accountViewModel = accountViewModel, nav = nav, ) + Spacer(modifier = StdVertSpacer) } if (showReply) { From 3b982b89628226144be47adff757834bade2c201 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 20 Mar 2024 17:02:13 -0400 Subject: [PATCH 07/15] Fixes the centralizing of the counter after the list of participants in a live event. --- .../vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 785a92a64..222a748fa 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 @@ -48,6 +48,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment.Companion.BottomStart +import androidx.compose.ui.Alignment.Companion.Center +import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Alignment.Companion.TopEnd import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -255,7 +257,7 @@ private fun RenderNoteRow( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - when (remember { baseNote.event }) { + when (baseNote.event) { is LiveActivitiesEvent -> { RenderLiveActivityThumb(baseNote, accountViewModel, nav) } @@ -828,7 +830,7 @@ fun RenderChannelThumb( onBottomRow = { if (participantUsers.isNotEmpty()) { Spacer(modifier = StdVertSpacer) - Row { Gallery(participantUsers, accountViewModel) } + Gallery(participantUsers, accountViewModel) } }, ) @@ -845,9 +847,10 @@ fun Gallery( if (users.size > 6) { Text( - text = remember(users) { " + " + (showCount(users.size - 6)) }, + text = " + " + showCount(users.size - 6), fontSize = 13.sp, color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.align(CenterVertically), ) } } From bdf41f53fb64fcd77955967243adc9f1b487272b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 08:41:29 -0400 Subject: [PATCH 08/15] Removes logs --- .../java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt index 9ac340cf6..df493c64c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt @@ -86,9 +86,7 @@ private fun LongFormHeader( remember { accountViewModel.settings.showImages.value } if (automaticallyShowUrlPreview) { - println("ImagePreview: $title $image") image?.let { - println("ImagePreview: Drawing $title $image") AsyncImage( model = it, contentDescription = @@ -100,7 +98,6 @@ private fun LongFormHeader( modifier = Modifier.fillMaxWidth(), ) } ?: run { - println("ImagePreview: DefaultHeader $title $image") DefaultImageHeader(note, accountViewModel) } } From c1756b75a76894bac297515246b315e78d6f032e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 08:42:14 -0400 Subject: [PATCH 09/15] Fixes double mention to Community headers when seeing a reply to a community post. --- .../main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4dd648350..f4a351ef7 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 @@ -684,7 +684,7 @@ fun RenderRepost( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - note.replyTo?.lastOrNull()?.let { + note.replyTo?.lastOrNull { it.event !is CommunityDefinitionEvent }?.let { NoteCompose( it, modifier = Modifier, From 64909bfb3287f8e1f6dd05d3748389db5e5d243e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 08:50:37 -0400 Subject: [PATCH 10/15] Fixes Chat preview images when no image has been set. --- .../vitorpamplona/amethyst/model/Channel.kt | 2 +- .../amethyst/ui/note/ChannelCardCompose.kt | 55 +++++++------------ .../ui/note/elements/DefaultImageHeader.kt | 19 +++---- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index 8a5e53afb..4cb65397a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -131,7 +131,7 @@ abstract class Channel(val idHex: String) { } open fun profilePicture(): String? { - return creator?.profilePicture() + return creator?.info?.banner } open fun updateChannelInfo( 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 222a748fa..708884a0f 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 @@ -70,6 +70,7 @@ import com.vitorpamplona.amethyst.model.ParticipantListBuilder import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout +import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader @@ -307,29 +308,29 @@ fun RenderClassifiedsThumb( ), ) - RenderClassifiedsThumb(card, baseNote.author) + InnerRenderClassifiedsThumb(card, baseNote) } @Preview @Composable fun RenderClassifiedsThumbPreview() { Surface(Modifier.size(200.dp)) { - RenderClassifiedsThumb( + InnerRenderClassifiedsThumb( card = ClassifiedsThumb( image = null, title = "Like New", price = Price("800000", "SATS", null), ), - author = null, + note = Note("hex"), ) } } @Composable -fun RenderClassifiedsThumb( +fun InnerRenderClassifiedsThumb( card: ClassifiedsThumb, - author: User?, + note: Note, ) { Box( Modifier.fillMaxWidth().aspectRatio(1f), @@ -342,8 +343,7 @@ fun RenderClassifiedsThumb( contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize(), ) - } - ?: run { author?.let { DisplayAuthorBanner(it) } } + } ?: run { DisplayAuthorBanner(note) } Row( Modifier.fillMaxWidth().background(Color.Black.copy(0.6f)).padding(Size5dp), @@ -451,8 +451,7 @@ fun RenderLiveActivityThumb( contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize().clip(QuoteBorder), ) - } - ?: run { baseNote.author?.let { DisplayAuthorBanner(it) } } + } ?: run { DisplayAuthorBanner(baseNote) } Box(Modifier.padding(10.dp)) { Crossfade(targetState = card.status, label = "RenderLiveActivityThumb") { @@ -560,8 +559,7 @@ fun RenderCommunitiesThumb( modifier = Modifier.fillMaxSize().clip(QuoteBorder), ) } - } - ?: run { baseNote.author?.let { DisplayAuthorBanner(it) } } + } ?: run { DisplayAuthorBanner(baseNote) } }, onTitleRow = { Text( @@ -781,16 +779,13 @@ fun RenderChannelThumb( LeftPictureLayout( onImage = { cover?.let { - Box(contentAlignment = BottomStart) { - AsyncImage( - model = it, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize().clip(QuoteBorder), - ) - } - } - ?: run { baseNote.author?.let { DisplayAuthorBanner(it) } } + AsyncImage( + model = it, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize().clip(QuoteBorder), + ) + } ?: run { DisplayAuthorBanner(baseNote) } }, onTitleRow = { Text( @@ -857,18 +852,10 @@ fun Gallery( } @Composable -fun DisplayAuthorBanner(author: User) { - val picture by - author - .live() - .metadata - .map { it.user.info?.banner?.ifBlank { null } ?: it.user.info?.picture?.ifBlank { null } } - .observeAsState() +fun DisplayAuthorBanner(note: Note) { + val authorState by note.live().authorChanges.observeAsState(note.author) - AsyncImage( - model = picture, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize().clip(QuoteBorder), - ) + authorState?.let { author -> + BannerImage(author, Modifier.fillMaxSize().clip(QuoteBorder)) + } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt index 488cf5861..e021842b5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note.elements import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.runtime.Composable @@ -42,7 +41,6 @@ import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.authorNotePictureForImageHeader -import com.vitorpamplona.amethyst.ui.theme.imageHeaderBannerSize @Composable fun DefaultImageHeader( @@ -63,7 +61,10 @@ fun DefaultImageHeader( } @Composable -private fun BoxScope.BannerImage(author: User) { +fun BannerImage( + author: User, + imageModifier: Modifier = Modifier.fillMaxWidth().heightIn(max = 200.dp), +) { val currentInfo by author.live().userMetadataInfo.observeAsState() currentInfo?.banner?.let { AsyncImage( @@ -73,18 +74,16 @@ private fun BoxScope.BannerImage(author: User) { R.string.preview_card_image_for, it, ), - contentScale = ContentScale.FillWidth, - modifier = - Modifier - .fillMaxWidth() - .heightIn(max = 200.dp), + contentScale = ContentScale.Crop, + modifier = imageModifier, + placeholder = painterResource(R.drawable.profile_banner), ) } ?: run { Image( painter = painterResource(R.drawable.profile_banner), contentDescription = stringResource(R.string.profile_banner), - contentScale = ContentScale.FillWidth, - modifier = imageHeaderBannerSize, + contentScale = ContentScale.Crop, + modifier = imageModifier, ) } } From 67202c32d41f9c95d184c72c18f3214bc6cda4ac Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 08:51:23 -0400 Subject: [PATCH 11/15] Migrates channel notes to LargeCache --- .../vitorpamplona/amethyst/model/Channel.kt | 21 ++++++++++--------- .../amethyst/model/LocalCache.kt | 4 ++-- .../com/vitorpamplona/amethyst/model/Note.kt | 3 ++- .../amethyst/model/ParticipantListBuilder.kt | 2 +- .../amethyst/ui/dal/ChannelFeedFilter.kt | 9 ++++---- .../ui/dal/ChatroomListKnownFeedFilter.kt | 11 ++++------ .../amethyst/ui/dal/DiscoverLiveFeedFilter.kt | 5 ++--- .../amethyst/commons/data/LargeCache.kt | 11 ++++++++++ 8 files changed, 38 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index 4cb65397a..18865dbb4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -22,9 +22,11 @@ package com.vitorpamplona.amethyst.model import androidx.compose.runtime.Stable import androidx.lifecycle.LiveData +import com.vitorpamplona.amethyst.commons.data.LargeCache import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.BundledUpdate +import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.note.toShortenHex import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.Hex @@ -33,7 +35,6 @@ import com.vitorpamplona.quartz.encoders.toNote import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.LiveActivitiesEvent import kotlinx.coroutines.Dispatchers -import java.util.concurrent.ConcurrentHashMap @Stable class PublicChatChannel(idHex: String) : Channel(idHex) { @@ -110,7 +111,7 @@ abstract class Channel(val idHex: String) { var updatedMetadataAt: Long = 0 - val notes = ConcurrentHashMap() + val notes = LargeCache() open fun id() = Hex.decode(idHex) @@ -145,7 +146,7 @@ abstract class Channel(val idHex: String) { } fun addNote(note: Note) { - notes[note.idHex] = note + notes.put(note.idHex, note) } fun removeNote(note: Note) { @@ -163,18 +164,18 @@ abstract class Channel(val idHex: String) { fun pruneOldAndHiddenMessages(account: Account): Set { val important = - notes.values - .filter { it.author?.let { it1 -> account.isHidden(it1) } == false } - .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - .reversed() - .take(1000) + notes.filter { key, it -> + it.author?.let { author -> account.isHidden(author) } == false + } + .sortedWith(DefaultFeedOrder) + .take(500) .toSet() - val toBeRemoved = notes.values.filter { it !in important }.toSet() + val toBeRemoved = notes.filter { key, it -> it !in important } toBeRemoved.forEach { notes.remove(it.idHex) } - return toBeRemoved + return toBeRemoved.toSet() } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index acd2709d1..eb4f270c3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -1780,9 +1780,9 @@ object LocalCache { removeFromCache(childrenToBeRemoved) - if (toBeRemoved.size > 100 || it.value.notes.size > 100) { + if (toBeRemoved.size > 100 || it.value.notes.size() > 100) { println( - "PRUNE: ${toBeRemoved.size} messages removed from ${it.value.toBestDisplayName()}. ${it.value.notes.size} kept", + "PRUNE: ${toBeRemoved.size} messages removed from ${it.value.toBestDisplayName()}. ${it.value.notes.size()} kept", ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 7f8e2e1cf..173df25de 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -171,7 +171,8 @@ open class Note(val idHex: String) { event is LiveActivitiesEvent ) { (event as? ChannelMessageEvent)?.channel() - ?: (event as? ChannelMetadataEvent)?.channel() ?: (event as? ChannelCreateEvent)?.id + ?: (event as? ChannelMetadataEvent)?.channel() + ?: (event as? ChannelCreateEvent)?.id ?: (event as? LiveActivitiesChatMessageEvent)?.activity()?.toTag() ?: (event as? LiveActivitiesEvent)?.address()?.toTag() } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt index db99be861..bd1ead6a3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/ParticipantListBuilder.kt @@ -96,7 +96,7 @@ class ParticipantListBuilder { it.replyTo?.forEach { addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet) } } - LocalCache.getChannelIfExists(baseNote.idHex)?.notes?.values?.forEach { + LocalCache.getChannelIfExists(baseNote.idHex)?.notes?.forEach { key, it -> addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt index a8a6ec236..87e113353 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChannelFeedFilter.kt @@ -31,10 +31,11 @@ class ChannelFeedFilter(val channel: Channel, val account: Account) : AdditiveFe // returns the last Note of each user. override fun feed(): List { - return channel.notes.values - .filter { account.isAcceptable(it) } - .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - .reversed() + return sort( + channel.notes.filterIntoSet { key, it -> + account.isAcceptable(it) + }, + ) } override fun applyFilter(collection: Set): Set { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt index b78716deb..2a1e6b20d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ChatroomListKnownFeedFilter.kt @@ -56,15 +56,12 @@ class ChatroomListKnownFeedFilter(val account: Account) : AdditiveFeedFilter - it.notes.values - .filter { account.isAcceptable(it) && it.event != null } - .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - .lastOrNull() + it.notes.filter { key, it -> account.isAcceptable(it) && it.event != null } + .sortedWith(DefaultFeedOrder) + .firstOrNull() } - return (privateMessages + publicChannels) - .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - .reversed() + return (privateMessages + publicChannels).sortedWith(DefaultFeedOrder) } override fun updateListWith( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt index 6fc737bb8..30aa19176 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/DiscoverLiveFeedFilter.kt @@ -48,9 +48,8 @@ open class DiscoverLiveFeedFilter( } override fun feed(): List { - val allChannelNotes = - LocalCache.channels.values.mapNotNull { LocalCache.getNoteIfExists(it.idHex) } - val allMessageNotes = LocalCache.channels.values.map { it.notes.values }.flatten() + val allChannelNotes = LocalCache.channels.values.mapNotNull { LocalCache.getNoteIfExists(it.idHex) } + val allMessageNotes = LocalCache.channels.values.map { it.notes.filter { key, it -> it.event is LiveActivitiesEvent } }.flatten() val notes = innerApplyFilter(allChannelNotes + allMessageNotes) diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/data/LargeCache.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/data/LargeCache.kt index a82f35aba..444cd76e0 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/data/LargeCache.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/data/LargeCache.kt @@ -32,6 +32,17 @@ class LargeCache { fun size() = cache.size + fun isEmpty() = cache.isEmpty() + + fun containsKey(key: K) = cache.containsKey(key) + + fun put( + key: K, + value: V, + ) { + cache.put(key, value) + } + fun getOrCreate( key: K, builder: (key: K) -> V, From c00319812a9d0d4903788ce0fb2ec00fa4ef65ef Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 09:25:26 -0400 Subject: [PATCH 12/15] Reverts to make sure the logged in user's post do not appear in notifications. --- .../vitorpamplona/amethyst/ui/dal/NotificationFeedFilter.kt | 3 +++ 1 file changed, 3 insertions(+) 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 6770a48ed..c33dcc3a7 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 @@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.events.GiftWrapEvent import com.vitorpamplona.quartz.events.GitIssueEvent import com.vitorpamplona.quartz.events.GitPatchEvent import com.vitorpamplona.quartz.events.HighlightEvent +import com.vitorpamplona.quartz.events.LnZapEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent import com.vitorpamplona.quartz.events.MuteListEvent import com.vitorpamplona.quartz.events.PeopleListEvent @@ -87,6 +88,7 @@ class NotificationFeedFilter(val account: Account) : AdditiveFeedFilter() filterParams: FilterByListParams, ): Boolean { val loggedInUserHex = account.userProfile().pubkeyHex + val loggedInUser = account.userProfile() return it.event !is ChannelCreateEvent && it.event !is ChannelMetadataEvent && @@ -94,6 +96,7 @@ class NotificationFeedFilter(val account: Account) : AdditiveFeedFilter() it.event !is BadgeDefinitionEvent && it.event !is BadgeProfilesEvent && it.event !is GiftWrapEvent && + (it.event is LnZapEvent || it.author !== loggedInUser) && (filterParams.isGlobal || filterParams.followLists?.users?.contains(it.author?.pubkeyHex) == true) && it.event?.isTaggedUser(loggedInUserHex) ?: false && (filterParams.isHiddenList || it.author == null || !account.isHidden(it.author!!.pubkeyHex)) && From 3086d3957d9348038856a8e4b8ae181aee535184 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 09:27:57 -0400 Subject: [PATCH 13/15] Moves from habla to njump --- .../com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index a60b15af4..d0209765b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -117,7 +117,7 @@ val externalLinkForNote = { note: Note -> } else if (note.event is AudioTrackEvent) { "https://zapstr.live/?track=${note.address()?.toNAddr()}" } else { - "https://habla.news/a/${note.address()?.toNAddr()}" + "https://njump.me/${note.address()?.toNAddr()}" } } else { if (note.event is FileHeaderEvent) { From 8f5820f46dd6b2015283aeb8fb02567fdc153f77 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 16:54:50 -0400 Subject: [PATCH 14/15] Fixes the reply finder for the reply row on compose --- .../com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt index 503944e38..33d1fa0f9 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/BaseTextNoteEvent.kt @@ -72,7 +72,7 @@ open class BaseTextNoteEvent( } fun replyingTo(): HexKey? { - val oldStylePositional = tags.lastOrNull { it.size > 1 && it[0] == "e" }?.get(1) + val oldStylePositional = tags.lastOrNull { it.size > 1 && it.size <= 3 && it[0] == "e" }?.get(1) val newStyleReply = tags.lastOrNull { it.size > 3 && it[0] == "e" && it[3] == "reply" }?.get(1) val newStyleRoot = tags.lastOrNull { it.size > 3 && it[0] == "e" && it[3] == "root" }?.get(1) @@ -80,7 +80,7 @@ open class BaseTextNoteEvent( } fun replyingToAddress(): ATag? { - val oldStylePositional = tags.lastOrNull { it.size > 1 && it[0] == "a" }?.let { ATag.parseAtag(it[1], it[2]) } + val oldStylePositional = tags.lastOrNull { it.size > 1 && it.size <= 3 && it[0] == "a" }?.let { ATag.parseAtag(it[1], it[2]) } val newStyleReply = tags.lastOrNull { it.size > 3 && it[0] == "a" && it[3] == "reply" }?.let { ATag.parseAtag(it[1], it[2]) } val newStyleRoot = tags.lastOrNull { it.size > 3 && it[0] == "a" && it[3] == "root" }?.let { ATag.parseAtag(it[1], it[2]) } @@ -88,7 +88,7 @@ open class BaseTextNoteEvent( } fun replyingToAddressOrEvent(): String? { - val oldStylePositional = tags.lastOrNull { it.size > 1 && (it[0] == "e" || it[0] == "a") }?.get(1) + val oldStylePositional = tags.lastOrNull { it.size > 1 && it.size <= 3 && (it[0] == "e" || it[0] == "a") }?.get(1) val newStyleReply = tags.lastOrNull { it.size > 3 && (it[0] == "e" || it[0] == "a") && it[3] == "reply" }?.get(1) val newStyleRoot = tags.lastOrNull { it.size > 3 && (it[0] == "e" || it[0] == "a") && it[3] == "root" }?.get(1) From 6f0e4f1f19f0cb7b705706a01a41118be4475380 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 21 Mar 2024 16:55:11 -0400 Subject: [PATCH 15/15] Makes hidden cards full width on the discovery feed --- .../vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt | 2 ++ 1 file changed, 2 insertions(+) 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 f016723ae..7a3685f4d 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 @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row 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.foundation.layout.size @@ -108,6 +109,7 @@ fun ChatroomMessageCompose( WatchBlockAndReport( note = baseNote, showHiddenWarning = innerQuote, + modifier = Modifier.fillMaxWidth(), accountViewModel = accountViewModel, nav = nav, ) { canPreview ->