mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-06-28 16:30:54 +02:00
Improves the design of the discovery cards for Live Activity and Chats.
This commit is contained in:
parent
77eb066362
commit
abef3d13f2
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user