Improves the design of the discovery cards for Live Activity and Chats.

This commit is contained in:
Vitor Pamplona 2023-12-27 17:00:41 -05:00
parent 77eb066362
commit abef3d13f2
4 changed files with 196 additions and 80 deletions

View File

@ -0,0 +1,139 @@
package com.vitorpamplona.amethyst.ui.layouts
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.note.LikeIcon
import com.vitorpamplona.amethyst.ui.note.TextCount
import com.vitorpamplona.amethyst.ui.note.ZappedIcon
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.ui.theme.Size16Modifier
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.ThemeComparison
import com.vitorpamplona.amethyst.ui.theme.placeholderText
@Composable
@Preview
fun LeftPictureLayoutPreview() {
ThemeComparison(
onDark = { LeftPictureLayoutPreviewCard() },
onLight = { LeftPictureLayoutPreviewCard() }
)
}
@Composable
fun LeftPictureLayoutPreviewCard() {
LeftPictureLayout(
onImage = {
Image(
painter = painterResource(R.drawable.github),
contentDescription = stringResource(id = R.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxSize()
.clip(QuoteBorder)
)
},
onTitleRow = {
Text(
text = "This is my title",
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
Spacer(modifier = StdHorzSpacer)
LikeIcon(
iconSizeModifier = Size16Modifier,
grayTint = MaterialTheme.colorScheme.onSurface
)
TextCount(12, MaterialTheme.colorScheme.onSurface)
Spacer(modifier = StdHorzSpacer)
ZappedIcon(Size20Modifier)
TextCount(120, MaterialTheme.colorScheme.onSurface)
},
onDescription = {
Text(
"This is 3-line description, This is 3-line description, This is 3-line description, This is 3-line description",
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp
)
},
onBottomRow = {
Text("This is my Moderator List")
}
)
}
@Composable
fun LeftPictureLayout(
onImage: @Composable () -> Unit,
onTitleRow: @Composable RowScope.() -> Unit,
onDescription: @Composable () -> Unit,
onBottomRow: @Composable RowScope.() -> Unit
) {
Row(Modifier.aspectRatio(ratio = 4f)) {
Column(
modifier = Modifier
.fillMaxWidth(0.25f)
.aspectRatio(ratio = 1f)
) {
onImage()
}
Spacer(modifier = DoubleHorzSpacer)
Column(
modifier = Modifier
.fillMaxWidth(),
verticalArrangement = Arrangement.SpaceBetween
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
onTitleRow()
}
Row(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
onDescription()
}
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
onBottomRow()
}
}
}
}

View File

@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -32,7 +31,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.BottomStart import androidx.compose.ui.Alignment.Companion.BottomStart
import androidx.compose.ui.Alignment.Companion.TopEnd import androidx.compose.ui.Alignment.Companion.TopEnd
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -54,6 +52,7 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.ParticipantListBuilder import com.vitorpamplona.amethyst.model.ParticipantListBuilder
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
@ -64,7 +63,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.OfflineFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ScheduledFlag import com.vitorpamplona.amethyst.ui.screen.loggedIn.ScheduledFlag
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
import com.vitorpamplona.amethyst.ui.theme.DividerThickness 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.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.HalfPadding import com.vitorpamplona.amethyst.ui.theme.HalfPadding
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
@ -689,12 +687,8 @@ fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, n
) )
) )
Row(Modifier.fillMaxWidth()) { LeftPictureLayout(
Column( onImage = {
modifier = Modifier
.fillMaxWidth(0.3f)
.aspectRatio(ratio = 1f)
) {
card.cover?.let { card.cover?.let {
Box(contentAlignment = BottomStart) { Box(contentAlignment = BottomStart) {
AsyncImage( AsyncImage(
@ -711,29 +705,22 @@ fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, n
DisplayAuthorBanner(it) DisplayAuthorBanner(it)
} }
} }
} },
onTitleRow = {
Spacer(modifier = DoubleHorzSpacer) Text(
text = card.name,
Column( fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth(), maxLines = 1,
verticalArrangement = Arrangement.SpaceBetween overflow = TextOverflow.Ellipsis,
) { modifier = Modifier.weight(1f)
Row(verticalAlignment = Alignment.CenterVertically) { )
Text(
text = card.name,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
Spacer(modifier = StdHorzSpacer)
LikeReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav = nav)
}
Spacer(modifier = StdHorzSpacer)
LikeReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav = nav)
},
onDescription = {
card.description?.let { card.description?.let {
Spacer(modifier = StdVertSpacer) Spacer(modifier = StdVertSpacer)
Row() { Row() {
@ -746,17 +733,16 @@ fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, n
) )
} }
} }
},
onBottomRow = {
Spacer(modifier = StdVertSpacer)
LoadModerators(card.moderators, baseNote, accountViewModel) { participantUsers -> LoadModerators(card.moderators, baseNote, accountViewModel) { participantUsers ->
if (participantUsers.isNotEmpty()) { if (participantUsers.isNotEmpty()) {
Spacer(modifier = StdVertSpacer) Gallery(participantUsers, accountViewModel)
Row(modifier = Modifier.fillMaxWidth()) {
Gallery(participantUsers, accountViewModel)
}
} }
} }
} }
} )
} }
@Composable @Composable
@ -901,12 +887,8 @@ fun RenderChannelThumb(baseNote: Note, channel: Channel, accountViewModel: Accou
} }
} }
Row(Modifier.fillMaxWidth()) { LeftPictureLayout(
Column( onImage = {
modifier = Modifier
.fillMaxWidth(0.3f)
.aspectRatio(ratio = 1f)
) {
cover?.let { cover?.let {
Box(contentAlignment = BottomStart) { Box(contentAlignment = BottomStart) {
AsyncImage( AsyncImage(
@ -923,43 +905,33 @@ fun RenderChannelThumb(baseNote: Note, channel: Channel, accountViewModel: Accou
DisplayAuthorBanner(it) DisplayAuthorBanner(it)
} }
} }
} },
onTitleRow = {
Spacer(modifier = DoubleHorzSpacer) Text(
text = name,
Column( fontWeight = FontWeight.Bold,
modifier = Modifier maxLines = 1,
.fillMaxWidth() overflow = TextOverflow.Ellipsis,
.fillMaxHeight() modifier = Modifier.weight(1f)
) { )
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = name,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
Spacer(modifier = StdHorzSpacer)
LikeReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav = nav)
}
Spacer(modifier = StdHorzSpacer)
LikeReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote = baseNote, grayTint = MaterialTheme.colorScheme.onSurface, accountViewModel = accountViewModel, nav = nav)
},
onDescription = {
description?.let { description?.let {
Spacer(modifier = StdVertSpacer) Text(
Row() { text = it,
Text( color = MaterialTheme.colorScheme.placeholderText,
text = it, maxLines = 3,
color = MaterialTheme.colorScheme.placeholderText, overflow = TextOverflow.Ellipsis,
maxLines = 3, fontSize = 14.sp
overflow = TextOverflow.Ellipsis, )
fontSize = 14.sp
)
}
} }
},
onBottomRow = {
if (participantUsers.isNotEmpty()) { if (participantUsers.isNotEmpty()) {
Spacer(modifier = StdVertSpacer) Spacer(modifier = StdVertSpacer)
Row() { Row() {
@ -967,7 +939,7 @@ fun RenderChannelThumb(baseNote: Note, channel: Channel, accountViewModel: Accou
} }
} }
} }
} )
} }
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class)
@ -980,7 +952,7 @@ fun Gallery(users: ImmutableList<User>, accountViewModel: AccountViewModel) {
if (users.size > 6) { if (users.size > 6) {
Text( Text(
text = remember(users) { " + " + (showCount(users.size - 6)).toString() }, text = remember(users) { " + " + (showCount(users.size - 6)) },
fontSize = 13.sp, fontSize = 13.sp,
color = MaterialTheme.colorScheme.onSurface color = MaterialTheme.colorScheme.onSurface
) )

View File

@ -594,7 +594,7 @@ val slideAnimation: ContentTransform =
) )
@Composable @Composable
private fun TextCount(count: Int, textColor: Color) { fun TextCount(count: Int, textColor: Color) {
Text( Text(
text = showCount(count), text = showCount(count),
fontSize = Font14SP, fontSize = Font14SP,

View File

@ -29,8 +29,13 @@ class LiveActivitiesEvent(
fun participants() = tags.filter { it.size > 1 && it[0] == "p" }.map { Participant(it[1], it.getOrNull(3)) } fun participants() = tags.filter { it.size > 1 && it[0] == "p" }.map { Participant(it[1], it.getOrNull(3)) }
fun hasHost() = tags.any { it.size > 3 && it[0] == "p" && it[3].equals("Host", true) }
fun host() = tags.firstOrNull { it.size > 3 && it[0] == "p" && it[3].equals("Host", true) }?.get(1) fun host() = tags.firstOrNull { it.size > 3 && it[0] == "p" && it[3].equals("Host", true) }?.get(1)
fun hosts() = tags.filter { it.size > 3 && it[0] == "p" && it[3].equals("Host", true) }.map { it[1] }
fun checkStatus(eventStatus: String?): String? { fun checkStatus(eventStatus: String?): String? {
return if (eventStatus == STATUS_LIVE && createdAt < TimeUtils.eightHoursAgo()) { return if (eventStatus == STATUS_LIVE && createdAt < TimeUtils.eightHoursAgo()) {
STATUS_ENDED STATUS_ENDED