mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2024-09-29 16:30:49 +00:00
Breaks down Compose components in the Discovery tab.
This commit is contained in:
parent
188ef3762d
commit
cec204b7ae
@ -19,6 +19,7 @@ import androidx.compose.material3.Divider
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@ -30,7 +31,6 @@ 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
|
||||||
import androidx.compose.ui.Alignment.Companion.BottomStart
|
import androidx.compose.ui.Alignment.Companion.BottomStart
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
|
||||||
import androidx.compose.ui.Alignment.Companion.TopEnd
|
import androidx.compose.ui.Alignment.Companion.TopEnd
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@ -50,7 +50,6 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
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.service.OnlineChecker
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||||
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
|
||||||
@ -75,6 +74,7 @@ import com.vitorpamplona.quartz.events.LiveActivitiesEvent
|
|||||||
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_ENDED
|
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_ENDED
|
||||||
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_LIVE
|
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_LIVE
|
||||||
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_PLANNED
|
import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_PLANNED
|
||||||
|
import com.vitorpamplona.quartz.events.Participant
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
@ -372,6 +372,18 @@ private fun RenderNoteRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class LiveActivityCard(
|
||||||
|
val name: String,
|
||||||
|
val cover: String?,
|
||||||
|
val media: String?,
|
||||||
|
val subject: String?,
|
||||||
|
val content: String?,
|
||||||
|
val participants: ImmutableList<Participant>,
|
||||||
|
val status: String?,
|
||||||
|
val starts: Long?
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RenderLiveActivityThumb(
|
fun RenderLiveActivityThumb(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
@ -380,38 +392,279 @@ fun RenderLiveActivityThumb(
|
|||||||
) {
|
) {
|
||||||
val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return
|
val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return
|
||||||
|
|
||||||
val eventUpdates by baseNote.live().metadata.observeAsState()
|
val card by baseNote.live().metadata.map {
|
||||||
|
val noteEvent = it.note.event as? LiveActivitiesEvent
|
||||||
|
|
||||||
val media = remember(eventUpdates) { noteEvent.streaming() }
|
LiveActivityCard(
|
||||||
val cover by remember(eventUpdates) {
|
name = noteEvent?.dTag() ?: "",
|
||||||
derivedStateOf {
|
cover = noteEvent?.image()?.ifBlank { null },
|
||||||
noteEvent.image()?.ifBlank { null }
|
media = noteEvent?.streaming(),
|
||||||
}
|
subject = noteEvent?.title()?.ifBlank { null },
|
||||||
}
|
content = noteEvent?.summary(),
|
||||||
val subject = remember(eventUpdates) { noteEvent.title()?.ifBlank { null } }
|
participants = noteEvent?.participants()?.toImmutableList() ?: persistentListOf(),
|
||||||
val content = remember(eventUpdates) { noteEvent.summary() }
|
status = noteEvent?.status(),
|
||||||
val participants = remember(eventUpdates) { noteEvent.participants() }
|
starts = noteEvent?.starts()
|
||||||
val status = remember(eventUpdates) { noteEvent.status() }
|
)
|
||||||
val starts = remember(eventUpdates) { noteEvent.starts() }
|
}.distinctUntilChanged().observeAsState(
|
||||||
|
LiveActivityCard(
|
||||||
|
name = noteEvent.dTag(),
|
||||||
|
cover = noteEvent.image()?.ifBlank { null },
|
||||||
|
media = noteEvent.streaming(),
|
||||||
|
subject = noteEvent.title()?.ifBlank { null },
|
||||||
|
content = noteEvent.summary(),
|
||||||
|
participants = noteEvent.participants().toImmutableList(),
|
||||||
|
status = noteEvent.status(),
|
||||||
|
starts = noteEvent.starts()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
var isOnline by remember { mutableStateOf(false) }
|
var isOnline by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(key1 = media) {
|
LaunchedEffect(key1 = card.media) {
|
||||||
launch(Dispatchers.IO) {
|
accountViewModel.checkIsOnline(card.media) { newIsOnline ->
|
||||||
val newIsOnline = OnlineChecker.isOnline(media)
|
|
||||||
if (isOnline != newIsOnline) {
|
if (isOnline != newIsOnline) {
|
||||||
isOnline = newIsOnline
|
isOnline = newIsOnline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = TopEnd,
|
||||||
|
modifier = Modifier
|
||||||
|
.aspectRatio(ratio = 16f / 9f)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
card.cover?.let {
|
||||||
|
AsyncImage(
|
||||||
|
model = it,
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clip(QuoteBorder)
|
||||||
|
)
|
||||||
|
} ?: run {
|
||||||
|
baseNote.author?.let {
|
||||||
|
DisplayAuthorBanner(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(Modifier.padding(10.dp)) {
|
||||||
|
Crossfade(targetState = card.status) {
|
||||||
|
when (it) {
|
||||||
|
STATUS_LIVE -> {
|
||||||
|
if (card.media.isNullOrBlank()) {
|
||||||
|
LiveFlag()
|
||||||
|
} else if (isOnline) {
|
||||||
|
LiveFlag()
|
||||||
|
} else {
|
||||||
|
OfflineFlag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATUS_ENDED -> {
|
||||||
|
EndedFlag()
|
||||||
|
}
|
||||||
|
STATUS_PLANNED -> {
|
||||||
|
ScheduledFlag(card.starts)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
EndedFlag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadParticipants(card.participants, baseNote, accountViewModel) { participantUsers ->
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.align(BottomStart)
|
||||||
|
) {
|
||||||
|
if (participantUsers.isNotEmpty()) {
|
||||||
|
Gallery(participantUsers, accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = DoubleVertSpacer)
|
||||||
|
|
||||||
|
ChannelHeader(
|
||||||
|
channelHex = remember { 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)
|
||||||
|
},
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class CommunityCard(
|
||||||
|
val name: String,
|
||||||
|
val description: String?,
|
||||||
|
val cover: String?,
|
||||||
|
val moderators: ImmutableList<Participant>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
|
val noteEvent = baseNote.event as? CommunityDefinitionEvent ?: return
|
||||||
|
|
||||||
|
val card by baseNote.live().metadata.map {
|
||||||
|
val noteEvent = it.note.event as? CommunityDefinitionEvent
|
||||||
|
|
||||||
|
CommunityCard(
|
||||||
|
name = noteEvent?.dTag() ?: "",
|
||||||
|
description = noteEvent?.description(),
|
||||||
|
cover = noteEvent?.image()?.ifBlank { null },
|
||||||
|
moderators = noteEvent?.moderators()?.toImmutableList() ?: persistentListOf()
|
||||||
|
)
|
||||||
|
}.distinctUntilChanged().observeAsState(
|
||||||
|
CommunityCard(
|
||||||
|
name = noteEvent.dTag(),
|
||||||
|
description = noteEvent.description(),
|
||||||
|
cover = noteEvent.image()?.ifBlank { null },
|
||||||
|
moderators = noteEvent.moderators().toImmutableList()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(Modifier.fillMaxWidth()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(0.3f)
|
||||||
|
.aspectRatio(ratio = 1f)
|
||||||
|
) {
|
||||||
|
card.cover?.let {
|
||||||
|
Box(contentAlignment = BottomStart) {
|
||||||
|
AsyncImage(
|
||||||
|
model = it,
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clip(QuoteBorder)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
baseNote.author?.let {
|
||||||
|
DisplayAuthorBanner(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
card.description?.let {
|
||||||
|
Spacer(modifier = StdVertSpacer)
|
||||||
|
Row() {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
color = MaterialTheme.colorScheme.placeholderText,
|
||||||
|
maxLines = 3,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadModerators(card.moderators, baseNote, accountViewModel) { participantUsers ->
|
||||||
|
if (participantUsers.isNotEmpty()) {
|
||||||
|
Spacer(modifier = StdVertSpacer)
|
||||||
|
Row(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Gallery(participantUsers, accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoadModerators(
|
||||||
|
moderators: ImmutableList<Participant>,
|
||||||
|
baseNote: Note,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
content: @Composable (ImmutableList<User>) -> Unit
|
||||||
|
) {
|
||||||
var participantUsers by remember {
|
var participantUsers by remember {
|
||||||
mutableStateOf<ImmutableList<User>>(
|
mutableStateOf<ImmutableList<User>>(
|
||||||
persistentListOf()
|
persistentListOf()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(key1 = eventUpdates) {
|
LaunchedEffect(key1 = moderators) {
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
val hosts = moderators.mapNotNull { part ->
|
||||||
|
if (part.key != baseNote.author?.pubkeyHex) {
|
||||||
|
LocalCache.checkGetOrCreateUser(part.key)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val followingKeySet = accountViewModel.account.selectedUsersFollowList(accountViewModel.account.defaultDiscoveryFollowList)
|
||||||
|
val allParticipants = ParticipantListBuilder().followsThatParticipateOn(baseNote, followingKeySet).minus(hosts)
|
||||||
|
|
||||||
|
val newParticipantUsers = if (followingKeySet == null) {
|
||||||
|
val allFollows = accountViewModel.account.selectedUsersFollowList(KIND3_FOLLOWS)
|
||||||
|
val followingParticipants = ParticipantListBuilder().followsThatParticipateOn(baseNote, allFollows).minus(hosts)
|
||||||
|
|
||||||
|
(hosts + followingParticipants + (allParticipants - followingParticipants)).toImmutableList()
|
||||||
|
} else {
|
||||||
|
(hosts + allParticipants).toImmutableList()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!equalImmutableLists(newParticipantUsers, participantUsers)) {
|
||||||
|
participantUsers = newParticipantUsers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content(participantUsers)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LoadParticipants(
|
||||||
|
participants: ImmutableList<Participant>,
|
||||||
|
baseNote: Note,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
inner: @Composable (ImmutableList<User>) -> Unit
|
||||||
|
) {
|
||||||
|
var participantUsers by remember {
|
||||||
|
mutableStateOf<ImmutableList<User>>(
|
||||||
|
persistentListOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = participants) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
val hosts = participants.mapNotNull { part ->
|
val hosts = participants.mapNotNull { part ->
|
||||||
if (part.key != baseNote.author?.pubkeyHex) {
|
if (part.key != baseNote.author?.pubkeyHex) {
|
||||||
@ -445,198 +698,7 @@ fun RenderLiveActivityThumb(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
inner(participantUsers)
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
contentAlignment = TopEnd,
|
|
||||||
modifier = Modifier
|
|
||||||
.aspectRatio(ratio = 16f / 9f)
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
cover?.let {
|
|
||||||
AsyncImage(
|
|
||||||
model = it,
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.clip(QuoteBorder)
|
|
||||||
)
|
|
||||||
} ?: run {
|
|
||||||
baseNote.author?.let {
|
|
||||||
DisplayAuthorBanner(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(Modifier.padding(10.dp)) {
|
|
||||||
Crossfade(targetState = status) {
|
|
||||||
when (it) {
|
|
||||||
STATUS_LIVE -> {
|
|
||||||
if (media.isNullOrBlank()) {
|
|
||||||
LiveFlag()
|
|
||||||
} else if (isOnline) {
|
|
||||||
LiveFlag()
|
|
||||||
} else {
|
|
||||||
OfflineFlag()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
STATUS_ENDED -> {
|
|
||||||
EndedFlag()
|
|
||||||
}
|
|
||||||
STATUS_PLANNED -> {
|
|
||||||
ScheduledFlag(starts)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
EndedFlag()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.padding(10.dp)
|
|
||||||
.align(BottomStart)
|
|
||||||
) {
|
|
||||||
if (participantUsers.isNotEmpty()) {
|
|
||||||
Gallery(participantUsers, accountViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = DoubleVertSpacer)
|
|
||||||
|
|
||||||
ChannelHeader(
|
|
||||||
channelHex = remember { 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)
|
|
||||||
},
|
|
||||||
accountViewModel = accountViewModel,
|
|
||||||
nav = nav
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
|
||||||
val noteEvent = baseNote.event as? CommunityDefinitionEvent ?: return
|
|
||||||
|
|
||||||
val eventUpdates by baseNote.live().metadata.observeAsState()
|
|
||||||
|
|
||||||
val name = remember(eventUpdates) { noteEvent.dTag() }
|
|
||||||
val description = remember(eventUpdates) { noteEvent.description() }
|
|
||||||
val cover by remember(eventUpdates) {
|
|
||||||
derivedStateOf {
|
|
||||||
noteEvent.image()?.ifBlank { null }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val moderators = remember(eventUpdates) { noteEvent.moderators() }
|
|
||||||
|
|
||||||
var participantUsers by remember {
|
|
||||||
mutableStateOf<ImmutableList<User>>(
|
|
||||||
persistentListOf()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(key1 = eventUpdates) {
|
|
||||||
launch(Dispatchers.IO) {
|
|
||||||
val hosts = moderators.mapNotNull { part ->
|
|
||||||
if (part.key != baseNote.author?.pubkeyHex) {
|
|
||||||
LocalCache.checkGetOrCreateUser(part.key)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val followingKeySet = accountViewModel.account.selectedUsersFollowList(accountViewModel.account.defaultDiscoveryFollowList)
|
|
||||||
val allParticipants = ParticipantListBuilder().followsThatParticipateOn(baseNote, followingKeySet).minus(hosts)
|
|
||||||
|
|
||||||
val newParticipantUsers = if (followingKeySet == null) {
|
|
||||||
val allFollows = accountViewModel.account.selectedUsersFollowList(KIND3_FOLLOWS)
|
|
||||||
val followingParticipants = ParticipantListBuilder().followsThatParticipateOn(baseNote, allFollows).minus(hosts)
|
|
||||||
|
|
||||||
(hosts + followingParticipants + (allParticipants - followingParticipants)).toImmutableList()
|
|
||||||
} else {
|
|
||||||
(hosts + allParticipants).toImmutableList()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!equalImmutableLists(newParticipantUsers, participantUsers)) {
|
|
||||||
participantUsers = newParticipantUsers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(Modifier.fillMaxWidth()) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth(0.3f)
|
|
||||||
.aspectRatio(ratio = 1f)
|
|
||||||
) {
|
|
||||||
cover?.let {
|
|
||||||
Box(contentAlignment = BottomStart) {
|
|
||||||
AsyncImage(
|
|
||||||
model = it,
|
|
||||||
contentDescription = null,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.clip(QuoteBorder)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
baseNote.author?.let {
|
|
||||||
DisplayAuthorBanner(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = DoubleHorzSpacer)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
description?.let {
|
|
||||||
Spacer(modifier = StdVertSpacer)
|
|
||||||
Row() {
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
color = MaterialTheme.colorScheme.placeholderText,
|
|
||||||
maxLines = 3,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
fontSize = 14.sp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participantUsers.isNotEmpty()) {
|
|
||||||
Spacer(modifier = StdVertSpacer)
|
|
||||||
Row(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
Gallery(participantUsers, accountViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
Loading…
Reference in New Issue
Block a user