diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 2d71b7079..ca0b2cb5e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt @@ -24,9 +24,8 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import com.vitorpamplona.amethyst.commons.MediaUrlImage @@ -46,19 +45,16 @@ fun LoadUrlPreview( if (!automaticallyShowUrlPreview) { ClickableUrl(urlText, url) } else { - var urlPreviewState by - remember(url) { - mutableStateOf( - UrlCachedPreviewer.cache.get(url) ?: UrlPreviewState.Loading, - ) + val urlPreviewState by + produceState( + initialValue = UrlCachedPreviewer.cache.get(url) ?: UrlPreviewState.Loading, + key1 = url, + ) { + if (value == UrlPreviewState.Loading) { + accountViewModel.urlPreview(url) { value = it } + } } - // Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are - // created). - if (urlPreviewState == UrlPreviewState.Loading) { - LaunchedEffect(url) { accountViewModel.urlPreview(url) { urlPreviewState = it } } - } - Crossfade( targetState = urlPreviewState, animationSpec = tween(durationMillis = 100), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 9c525fc3c..db6a35bc8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -28,6 +28,7 @@ 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.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent @@ -102,6 +103,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadedBechLink import com.vitorpamplona.amethyst.ui.theme.Font17SP import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle +import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.ui.theme.markdownStyle import com.vitorpamplona.amethyst.ui.uriToRoute @@ -344,6 +346,16 @@ private fun RenderRegular( } } } + + // UrlPreviews and Images have a 5dp spacing down. This also adds the space to Text. + val lastElement = state.paragraphs.lastOrNull()?.words?.lastOrNull() + if (lastElement !is ImageSegment && + lastElement !is LinkSegment && + lastElement !is InvoiceSegment && + lastElement !is CashuSegment + ) { + Spacer(modifier = StdVertSpacer) + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 794a20752..25de08d53 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -150,7 +150,7 @@ fun ReactionsRow( ) { val wantsToSeeReactions = remember(baseNote) { mutableStateOf(false) } - Spacer(modifier = HalfDoubleVertSpacer) + // Spacer(modifier = HalfDoubleVertSpacer) InnerReactionRow(baseNote, showReactionDetail, wantsToSeeReactions, accountViewModel, nav) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt index 71c661083..2d946e5a1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt @@ -20,11 +20,19 @@ */ package com.vitorpamplona.amethyst.ui.note +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.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.Icon @@ -37,14 +45,17 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember 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.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonBoxModifer -import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconButtonModifier -import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonIconModifier +import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText @OptIn(ExperimentalLayoutApi::class) @@ -58,16 +69,18 @@ fun RelayBadges( val relayList by baseNote.live().relayInfo.observeAsState(baseNote.relays) - Spacer(DoubleVertSpacer) + Spacer(StdVertSpacer) // FlowRow Seems to be a lot faster than LazyVerticalGrid - FlowRow { - if (expanded) { - relayList?.forEach { RenderRelay(it, accountViewModel, nav) } - } else { - relayList?.getOrNull(0)?.let { RenderRelay(it, accountViewModel, nav) } - relayList?.getOrNull(1)?.let { RenderRelay(it, accountViewModel, nav) } - relayList?.getOrNull(2)?.let { RenderRelay(it, accountViewModel, nav) } + Box(modifier = Modifier.fillMaxWidth().padding(start = 2.dp, end = 1.dp)) { + FlowRow(modifier = Modifier.fillMaxWidth()) { + if (expanded) { + relayList?.forEach { RenderRelay(it, accountViewModel, nav) } + } else { + relayList?.getOrNull(0)?.let { RenderRelay(it, accountViewModel, nav) } + relayList?.getOrNull(1)?.let { RenderRelay(it, accountViewModel, nav) } + relayList?.getOrNull(2)?.let { RenderRelay(it, accountViewModel, nav) } + } } } @@ -76,6 +89,62 @@ fun RelayBadges( } } +@OptIn(ExperimentalLayoutApi::class) +@Preview +@Composable +fun RelayIconLayoutPreview() { + Column(modifier = Modifier.width(55.dp)) { + Spacer(StdVertSpacer) + + // FlowRow Seems to be a lot faster than LazyVerticalGrid + Box(modifier = Modifier.fillMaxWidth().padding(start = 2.dp, end = 1.dp)) { + FlowRow { + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box( + Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black), + ) + } + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box(Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black)) + } + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box(Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black)) + } + + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box(Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black)) + } + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box(Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black)) + } + Box( + modifier = Modifier.size(17.dp), + contentAlignment = Alignment.Center, + ) { + Box(Modifier.size(13.dp).clip(shape = CircleShape).background(Color.Black)) + } + } + } + + ShowMoreRelaysButton { } + } +} + @Composable private fun ShowMoreRelaysButton(onClick: () -> Unit) { Row( @@ -84,13 +153,11 @@ private fun ShowMoreRelaysButton(onClick: () -> Unit) { verticalAlignment = Alignment.Top, ) { IconButton( - modifier = ShowMoreRelaysButtonIconButtonModifier, onClick = onClick, ) { Icon( imageVector = Icons.Default.ExpandMore, contentDescription = stringResource(id = R.string.expand_relay_list), - modifier = ShowMoreRelaysButtonIconModifier, tint = MaterialTheme.colorScheme.placeholderText, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index cac24a089..ee5ecfcde 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight @@ -47,7 +46,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role -import androidx.compose.ui.unit.dp import androidx.lifecycle.map import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note @@ -59,7 +57,7 @@ import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter import com.vitorpamplona.amethyst.ui.theme.Size15Modifier -import com.vitorpamplona.amethyst.ui.theme.Size15dp +import com.vitorpamplona.amethyst.ui.theme.Size17dp import com.vitorpamplona.amethyst.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.relayIconModifier @@ -164,13 +162,12 @@ fun RenderRelay( val context = LocalContext.current val interactionSource = remember { MutableInteractionSource() } - val ripple = rememberRipple(bounded = false, radius = Size15dp) + val ripple = rememberRipple(bounded = false, radius = Size17dp) val clickableModifier = remember(relay) { Modifier - .padding(1.dp) - .size(Size15dp) + .size(Size17dp) .clickable( role = Role.Button, interactionSource = interactionSource, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt index e42c2fe6c..10ff2a720 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.gestures.ScrollableState import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight @@ -232,7 +231,7 @@ private fun RenderDiscoverFeed( viewModel: FeedViewModel, routeForLastRead: String?, forceEventKind: Int?, - listState: ScrollableState, + listState: LazyGridState, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { @@ -251,25 +250,54 @@ private fun RenderDiscoverFeed( FeedError(state.errorMessage) { viewModel.invalidateData() } } is FeedState.Loaded -> { - if (listState is LazyGridState) { - DiscoverFeedColumnsLoaded( - state, - routeForLastRead, - listState, - forceEventKind, - accountViewModel, - nav, - ) - } else if (listState is LazyListState) { - DiscoverFeedLoaded( - state, - routeForLastRead, - listState, - forceEventKind, - accountViewModel, - nav, - ) - } + DiscoverFeedColumnsLoaded( + state, + routeForLastRead, + listState, + forceEventKind, + accountViewModel, + nav, + ) + } + is FeedState.Loading -> { + LoadingFeed() + } + } + } +} + +@Composable +private fun RenderDiscoverFeed( + viewModel: FeedViewModel, + routeForLastRead: String?, + forceEventKind: Int?, + listState: LazyListState, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val feedState by viewModel.feedContent.collectAsStateWithLifecycle() + + Crossfade( + targetState = feedState, + animationSpec = tween(durationMillis = 100), + label = "RenderDiscoverFeed", + ) { state -> + when (state) { + is FeedState.Empty -> { + FeedEmpty { viewModel.invalidateData() } + } + is FeedState.FeedError -> { + FeedError(state.errorMessage) { viewModel.invalidateData() } + } + is FeedState.Loaded -> { + DiscoverFeedLoaded( + state, + routeForLastRead, + listState, + forceEventKind, + accountViewModel, + nav, + ) } is FeedState.Loading -> { LoadingFeed() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index 0d10f938d..29b1300ed 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -146,9 +146,9 @@ val Height4dpModifier = Modifier.height(4.dp) val AccountPictureModifier = Modifier.size(55.dp).clip(shape = CircleShape) val HeaderPictureModifier = Modifier.size(34.dp).clip(shape = CircleShape) -val ShowMoreRelaysButtonIconButtonModifier = Modifier.size(24.dp) -val ShowMoreRelaysButtonIconModifier = Modifier.size(15.dp) -val ShowMoreRelaysButtonBoxModifer = Modifier.fillMaxWidth().height(25.dp) +val ShowMoreRelaysButtonIconButtonModifier = Modifier.size(15.dp) +val ShowMoreRelaysButtonIconModifier = Modifier.size(20.dp) +val ShowMoreRelaysButtonBoxModifer = Modifier.fillMaxWidth().height(17.dp) val ChatBubbleMaxSizeModifier = Modifier.fillMaxWidth(0.85f) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 2fcdc92b9..4bfebcc01 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -167,14 +167,14 @@ val LightReplyBorderModifier = val DarkInnerPostBorderModifier = Modifier - .padding(top = 5.dp) + .padding(vertical = 5.dp) .fillMaxWidth() .clip(shape = QuoteBorder) .border(1.dp, DarkSubtleBorder, QuoteBorder) val LightInnerPostBorderModifier = Modifier - .padding(top = 5.dp) + .padding(vertical = 5.dp) .fillMaxWidth() .clip(shape = QuoteBorder) .border(1.dp, LightSubtleBorder, QuoteBorder)