Improves the Discovery block UI

This commit is contained in:
Vitor Pamplona 2024-12-02 17:17:31 -05:00
parent 95774ddca5
commit ae13725db5
5 changed files with 82 additions and 69 deletions

View File

@ -109,10 +109,11 @@ fun LeftPictureLayout(
onTitleRow: @Composable RowScope.() -> Unit,
onDescription: @Composable () -> Unit,
onBottomRow: @Composable RowScope.() -> Unit,
imageFraction: Float = 0.25f,
) {
Row(Modifier.aspectRatio(ratio = 4f)) {
Row(Modifier.aspectRatio(ratio = 1 / imageFraction)) {
Column(
modifier = Modifier.fillMaxWidth(0.25f).aspectRatio(ratio = 1f),
modifier = Modifier.fillMaxWidth(imageFraction).aspectRatio(ratio = 1f),
) {
onImage()
}

View File

@ -42,7 +42,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
@ -66,6 +65,8 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.map
import coil3.compose.AsyncImage
import coil3.compose.AsyncImagePainter
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Channel
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
@ -86,18 +87,21 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.ui.theme.RowColSpacing
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.RowColSpacing5dp
import com.vitorpamplona.amethyst.ui.theme.Size25dp
import com.vitorpamplona.amethyst.ui.theme.Size5dp
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.bitcoinColor
import com.vitorpamplona.amethyst.ui.theme.grayText
import com.vitorpamplona.amethyst.ui.theme.nip05
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent
@ -515,7 +519,7 @@ fun RenderLiveActivityThumb(
.align(BottomStart),
) {
if (participantUsers.isNotEmpty()) {
Gallery(participantUsers, accountViewModel)
Gallery(participantUsers, Modifier, accountViewModel)
}
}
}
@ -629,24 +633,20 @@ fun RenderCommunitiesThumb(
)
},
onDescription = {
card.description?.let {
Spacer(modifier = StdVertSpacer)
Row {
Text(
text = it,
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
)
}
}
Text(
text = card.description ?: stringRes(R.string.community_about_topic, card.name),
color = MaterialTheme.colorScheme.grayText,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
lineHeight = 18.sp,
modifier = HalfTopPadding,
)
},
onBottomRow = {
Spacer(modifier = StdVertSpacer)
LoadModerators(card.moderators, baseNote, accountViewModel) { participantUsers ->
if (participantUsers.isNotEmpty()) {
Gallery(participantUsers, accountViewModel)
Gallery(participantUsers, HalfTopPadding, accountViewModel)
}
}
},
@ -778,6 +778,7 @@ fun RenderContentDVMThumb(
val card = observeAppDefinition(appDefinitionNote = baseNote)
LeftPictureLayout(
imageFraction = 0.20f,
onImage = {
card.cover?.let {
Box(contentAlignment = BottomStart) {
@ -810,11 +811,10 @@ fun RenderContentDVMThumb(
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f),
)
Spacer(modifier = StdVertSpacer)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = RowColSpacing,
horizontalArrangement = RowColSpacing5dp,
) {
LikeReaction(
baseNote = baseNote,
@ -833,16 +833,15 @@ fun RenderContentDVMThumb(
},
onDescription = {
card.description?.let {
Spacer(modifier = StdVertSpacer)
Row {
Text(
text = it,
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
)
}
Text(
text = it,
color = MaterialTheme.colorScheme.grayText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
lineHeight = 16.sp,
modifier = HalfTopPadding,
)
}
},
onBottomRow = {
@ -856,13 +855,12 @@ fun RenderContentDVMThumb(
color = MaterialTheme.colorScheme.primaryContainer
amount = "Flexible"
} else if (card.amount == "") {
color = MaterialTheme.colorScheme.secondaryContainer
color = MaterialTheme.colorScheme.grayText
amount = "Unknown"
} else {
color = MaterialTheme.colorScheme.primary
amount = card.amount + " Sats"
}
Spacer(modifier = StdVertSpacer)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Absolute.Right,
@ -874,7 +872,6 @@ fun RenderContentDVMThumb(
maxLines = 3,
modifier =
Modifier
.padding(start = 4.dp)
.weight(1f, fill = false)
.border(Dp(.1f), color, shape = RoundedCornerShape(20)),
fontSize = 12.sp,
@ -938,10 +935,10 @@ fun RenderChannelThumb(
val channelUpdates by channel.live.observeAsState()
val name = remember(channelUpdates) { channelUpdates?.channel?.toBestDisplayName() ?: "" }
val description = remember(channelUpdates) { channelUpdates?.channel?.summary() }
val cover by
val description = remember(channelUpdates) { channelUpdates?.channel?.summary()?.ifBlank { null } }
var cover by
remember(channelUpdates) {
derivedStateOf { channelUpdates?.channel?.profilePicture()?.ifBlank { null } }
mutableStateOf(channelUpdates?.channel?.profilePicture()?.ifBlank { null })
}
var participantUsers by
@ -989,6 +986,11 @@ fun RenderChannelThumb(
Modifier
.fillMaxSize()
.clip(QuoteBorder),
onState = {
if (it is AsyncImagePainter.State.Error) {
cover = null
}
},
)
} ?: run { DisplayAuthorBanner(baseNote) }
},
@ -1021,20 +1023,19 @@ fun RenderChannelThumb(
)
},
onDescription = {
description?.let {
Text(
text = it,
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
)
}
Text(
text = description ?: stringRes(R.string.chat_about_topic, name),
color = MaterialTheme.colorScheme.grayText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
lineHeight = 18.sp,
modifier = HalfTopPadding,
)
},
onBottomRow = {
if (participantUsers.isNotEmpty()) {
Spacer(modifier = StdVertSpacer)
Gallery(participantUsers, accountViewModel)
Gallery(participantUsers, HalfTopPadding, accountViewModel)
}
},
)
@ -1044,17 +1045,18 @@ fun RenderChannelThumb(
@Composable
fun Gallery(
users: ImmutableList<User>,
modifier: Modifier,
accountViewModel: AccountViewModel,
) {
FlowRow(verticalArrangement = Arrangement.Center) {
users.take(6).forEach { ClickableUserPicture(it, Size35dp, accountViewModel) }
FlowRow(modifier, verticalArrangement = Arrangement.Center) {
users.take(6).forEach { ClickableUserPicture(it, Size25dp, accountViewModel) }
if (users.size > 6) {
Text(
text = " + " + showCount(users.size - 6),
fontSize = 13.sp,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.align(CenterVertically),
modifier = Modifier.padding(start = 3.dp).align(CenterVertically),
)
}
}

View File

@ -198,7 +198,6 @@ fun DiscoverScreen(
}
@Composable
@OptIn(ExperimentalFoundationApi::class)
private fun DiscoverPages(
pagerState: PagerState,
tabs: ImmutableList<TabItem>,

View File

@ -95,6 +95,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.Size75dp
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.AppMetadata
import com.vitorpamplona.quartz.events.NIP90ContentDiscoveryResponseEvent
import com.vitorpamplona.quartz.events.NIP90StatusEvent
import com.vitorpamplona.quartz.events.PayInvoiceErrorResponse
@ -627,6 +628,28 @@ fun FeedEmptyWithStatus(
}
}
fun convertAppMetadataToCard(metadata: AppMetadata?): DVMCard {
if (metadata == null) {
return DVMCard(
name = "",
description = "",
cover = null,
amount = "",
personalized = false,
)
}
return with(metadata) {
DVMCard(
name = this.name ?: "",
description = this.about ?: "",
cover = this.profilePicture()?.ifBlank { null },
amount = this.amount ?: "",
personalized = this.personalized ?: false,
)
}
}
@Composable
fun observeAppDefinition(appDefinitionNote: Note): DVMCard {
val noteEvent =
@ -643,24 +666,10 @@ fun observeAppDefinition(appDefinitionNote: Note): DVMCard {
.live()
.metadata
.map {
val noteEvent = it.note.event as? AppDefinitionEvent
DVMCard(
name = noteEvent?.appMetaData()?.name ?: "",
description = noteEvent?.appMetaData()?.about ?: "",
cover = noteEvent?.appMetaData()?.profilePicture()?.ifBlank { null },
amount = noteEvent?.appMetaData()?.amount ?: "",
personalized = noteEvent?.appMetaData()?.personalized ?: false,
)
convertAppMetadataToCard((it.note.event as? AppDefinitionEvent)?.appMetaData())
}.distinctUntilChanged()
.observeAsState(
DVMCard(
name = noteEvent.appMetaData()?.name ?: "",
description = noteEvent.appMetaData()?.about ?: "",
cover = noteEvent.appMetaData()?.profilePicture()?.ifBlank { null },
amount = noteEvent.appMetaData()?.amount ?: "",
personalized = noteEvent.appMetaData()?.personalized ?: false,
),
convertAppMetadataToCard(noteEvent.appMetaData()),
)
return card

View File

@ -210,6 +210,8 @@
<string name="translations_translated_from">translated from</string>
<string name="translations_to">to</string>
<string name="translations_show_in_lang_first">Show in %1$s first</string>
<string name="chat_about_topic">Public chat about %1$s</string>
<string name="community_about_topic">Public community about %1$s</string>
<string name="translations_always_translate_to_lang">Always translate to %1$s</string>
<string name="translations_never_translate_from_lang">Never translate from %1$s</string>
<string name="nip_05">Nostr Address</string>