mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-27 00:16:31 +02:00
Activates reactions and zaps to the channel and community headers.
This commit is contained in:
@@ -27,6 +27,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.BottomStart
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Alignment.Companion.TopEnd
|
||||
@@ -347,7 +348,6 @@ private fun RenderNoteRow(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return
|
||||
@@ -570,7 +570,7 @@ fun RenderCommunitiesThumb(baseNote: Note, accountViewModel: AccountViewModel, n
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Row() {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = name,
|
||||
fontWeight = FontWeight.Bold,
|
||||
@@ -684,7 +684,7 @@ fun RenderChannelThumb(baseNote: Note, channel: Channel, accountViewModel: Accou
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().fillMaxHeight()
|
||||
) {
|
||||
Row() {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = name,
|
||||
fontWeight = FontWeight.Bold,
|
||||
|
@@ -478,20 +478,144 @@ fun CommunityHeader(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
var expanded = remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
scope.launch {
|
||||
nav("Community/${baseNote.idHex}")
|
||||
}
|
||||
modifier = modifier.clickable {
|
||||
expanded.value = !expanded.value
|
||||
}
|
||||
) {
|
||||
val channelState by baseNote.live().metadata.observeAsState()
|
||||
val noteEvent = remember(channelState) { channelState?.note?.event as? CommunityDefinitionEvent } ?: return
|
||||
ShortCommunityHeader(baseNote, expanded, accountViewModel, nav)
|
||||
|
||||
if (expanded.value) {
|
||||
LongCommunityHeader(baseNote, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
if (showBottomDiviser) {
|
||||
Divider(
|
||||
thickness = 0.25.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LongCommunityHeader(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by baseNote.live().metadata.observeAsState()
|
||||
val noteEvent = remember(noteState) { noteState?.note?.event as? CommunityDefinitionEvent } ?: return
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 10.dp)
|
||||
) {
|
||||
val summary = remember(noteState) {
|
||||
noteEvent.description()?.ifBlank { null }
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 10.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = summary ?: "This group does not have a description or rules. Talk to the owner to add one"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Spacer(DoubleHorzSpacer)
|
||||
LongCommunityActionOptions(baseNote, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val rules = remember(noteState) {
|
||||
noteEvent.rules()?.ifBlank { null }
|
||||
}
|
||||
|
||||
rules?.let {
|
||||
Spacer(DoubleVertSpacer)
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 10.dp)
|
||||
) {
|
||||
Text(
|
||||
text = it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(DoubleVertSpacer)
|
||||
|
||||
Row(Modifier.fillMaxWidth().padding(start = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.owner),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.width(75.dp)
|
||||
)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
NoteAuthorPicture(baseNote, nav, accountViewModel, Size25dp)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
||||
TimeAgo(baseNote)
|
||||
MoreOptionsButton(baseNote, accountViewModel)
|
||||
}
|
||||
|
||||
var participantUsers by remember(baseNote) {
|
||||
mutableStateOf<ImmutableList<Pair<Participant, User>>>(
|
||||
persistentListOf()
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = noteState) {
|
||||
launch(Dispatchers.IO) {
|
||||
val noteEvent = (noteState?.note?.event as? CommunityDefinitionEvent)
|
||||
val newParticipantUsers = noteEvent?.moderators()?.mapNotNull { part ->
|
||||
LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) }
|
||||
}?.toImmutableList()
|
||||
|
||||
if (newParticipantUsers != null && !equalImmutableLists(newParticipantUsers, participantUsers)) {
|
||||
participantUsers = newParticipantUsers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
participantUsers.forEach {
|
||||
Row(
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(start = 10.dp, top = 10.dp)
|
||||
.clickable {
|
||||
nav("User/${it.second.pubkeyHex}")
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
it.first.role?.let { it1 ->
|
||||
Text(
|
||||
text = it1.capitalize(Locale.ROOT),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.width(75.dp)
|
||||
)
|
||||
}
|
||||
Spacer(DoubleHorzSpacer)
|
||||
ClickableUserPicture(it.second, Size25dp, accountViewModel)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
UsernameDisplay(it.second, remember { Modifier.weight(1f) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShortCommunityHeader(baseNote: Note, expanded: MutableState<Boolean>, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
val noteState by baseNote.live().metadata.observeAsState()
|
||||
val noteEvent = remember(noteState) { noteState?.note?.event as? CommunityDefinitionEvent } ?: return
|
||||
|
||||
Column(modifier = modifier) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
noteEvent.image()?.let {
|
||||
RobohashAsyncImageProxy(
|
||||
@@ -510,23 +634,24 @@ fun CommunityHeader(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.height(Size35dp)
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = remember(channelState) { noteEvent.dTag() },
|
||||
text = remember(noteState) { noteEvent.dTag() },
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
||||
val summary = remember(channelState) {
|
||||
val summary = remember(noteState) {
|
||||
noteEvent.description()?.ifBlank { null }
|
||||
}
|
||||
|
||||
if (summary != null) {
|
||||
if (summary != null && !expanded.value) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = summary,
|
||||
@@ -545,21 +670,37 @@ fun CommunityHeader(
|
||||
.padding(start = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CommunityActionOptions(baseNote, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showBottomDiviser) {
|
||||
Divider(
|
||||
thickness = 0.25.dp
|
||||
)
|
||||
ShortCommunityActionOptions(baseNote, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CommunityActionOptions(
|
||||
private fun ShortCommunityActionOptions(
|
||||
note: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val isFollowing by remember(accountState) {
|
||||
derivedStateOf {
|
||||
accountState?.account?.followingCommunities?.contains(note.idHex) ?: false
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
LikeReaction(baseNote = note, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
ZapReaction(baseNote = note, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
|
||||
|
||||
if (!isFollowing) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
JoinCommunityButton(accountViewModel, note, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LongCommunityActionOptions(
|
||||
note: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
@@ -573,8 +714,6 @@ private fun CommunityActionOptions(
|
||||
|
||||
if (isFollowing) {
|
||||
LeaveCommunityButton(accountViewModel, note, nav)
|
||||
} else {
|
||||
JoinCommunityButton(accountViewModel, note, nav)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,7 @@ import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
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
|
||||
@@ -75,6 +76,8 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
@@ -82,35 +85,50 @@ import com.vitorpamplona.amethyst.model.LiveActivitiesChannel
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE
|
||||
import com.vitorpamplona.amethyst.service.model.Participant
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.ServersAvailable
|
||||
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||
import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
|
||||
import com.vitorpamplona.amethyst.ui.components.ZoomableUrlVideo
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.ChatroomMessageCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.LikeReaction
|
||||
import com.vitorpamplona.amethyst.ui.note.MoreOptionsButton
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.TimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapReaction
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAgo
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
|
||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.SmallBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.Locale
|
||||
|
||||
@Composable
|
||||
fun ChannelScreen(
|
||||
@@ -556,47 +574,73 @@ fun ChannelHeader(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
scope.launch {
|
||||
nav("Channel/${baseChannel.idHex}")
|
||||
Column(Modifier.fillMaxWidth()) {
|
||||
if (showVideo && baseChannel is LiveActivitiesChannel) {
|
||||
ShowVideoStreaming(baseChannel)
|
||||
}
|
||||
|
||||
var expanded = remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = modifier.clickable {
|
||||
expanded.value = !expanded.value
|
||||
}
|
||||
) {
|
||||
val channelState by baseChannel.live.observeAsState()
|
||||
val channel = remember(channelState) { channelState?.channel } ?: return
|
||||
ShortChannelHeader(baseChannel, expanded, accountViewModel, nav, showFlag)
|
||||
|
||||
if (showVideo) {
|
||||
val streamingUrl by remember(channelState) {
|
||||
derivedStateOf {
|
||||
val activity = channel as? LiveActivitiesChannel
|
||||
val description = activity?.info?.title()
|
||||
val url = activity?.info?.streaming()
|
||||
if (url != null) {
|
||||
ZoomableUrlVideo(url, description = description)
|
||||
} else {
|
||||
null
|
||||
if (expanded.value) {
|
||||
LongChannelHeader(baseChannel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
if (showBottomDiviser) {
|
||||
Divider(
|
||||
thickness = 0.25.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ShowVideoStreaming(
|
||||
baseChannel: LiveActivitiesChannel
|
||||
) {
|
||||
val streamingUrl by baseChannel.live.map {
|
||||
val activity = it.channel as? LiveActivitiesChannel
|
||||
activity?.info?.streaming()
|
||||
}.distinctUntilChanged().observeAsState(baseChannel.info?.streaming())
|
||||
|
||||
streamingUrl?.let {
|
||||
CheckIfUrlIsOnline(it.url) {
|
||||
CheckIfUrlIsOnline(it) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = remember { Modifier.heightIn(max = 300.dp) }
|
||||
) {
|
||||
val zoomableUrlVideo = remember(it) {
|
||||
ZoomableUrlVideo(url = it)
|
||||
}
|
||||
|
||||
ZoomableContentView(
|
||||
content = it
|
||||
content = zoomableUrlVideo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(modifier = modifier) {
|
||||
|
||||
@Composable
|
||||
private fun ShortChannelHeader(
|
||||
baseChannel: Channel,
|
||||
expanded: MutableState<Boolean>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
showFlag: Boolean
|
||||
) {
|
||||
val channelState = baseChannel.live.observeAsState()
|
||||
val channel = remember(channelState) {
|
||||
channelState.value?.channel
|
||||
} ?: return
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (channel is LiveActivitiesChannel) {
|
||||
channel.creator?.let {
|
||||
@@ -614,7 +658,8 @@ fun ChannelHeader(
|
||||
model = it,
|
||||
contentDescription = stringResource(R.string.profile_image),
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.padding(start = 10.dp)
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.width(Size35dp)
|
||||
.height(Size35dp)
|
||||
.clip(shape = CircleShape)
|
||||
@@ -625,6 +670,7 @@ fun ChannelHeader(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.height(35.dp)
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
@@ -641,7 +687,7 @@ fun ChannelHeader(
|
||||
channel.summary()?.ifBlank { null }
|
||||
}
|
||||
|
||||
if (summary != null) {
|
||||
if (summary != null && !expanded.value) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = summary,
|
||||
@@ -661,7 +707,7 @@ fun ChannelHeader(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (channel is PublicChatChannel) {
|
||||
ChannelActionOptions(channel, accountViewModel, nav)
|
||||
ShortChannelActionOptions(channel, accountViewModel, nav)
|
||||
}
|
||||
if (channel is LiveActivitiesChannel) {
|
||||
LiveChannelActionOptions(channel, showFlag, accountViewModel, nav)
|
||||
@@ -670,22 +716,150 @@ fun ChannelHeader(
|
||||
}
|
||||
}
|
||||
|
||||
if (showBottomDiviser) {
|
||||
Divider(
|
||||
thickness = 0.25.dp
|
||||
@Composable
|
||||
private fun LongChannelHeader(
|
||||
baseChannel: Channel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val channelState = baseChannel.live.observeAsState()
|
||||
val channel = remember(channelState) {
|
||||
channelState.value?.channel
|
||||
} ?: return
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 10.dp)
|
||||
) {
|
||||
val summary = remember(channelState) {
|
||||
channel.summary()?.ifBlank { null }
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 10.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = summary ?: "This group does not have a description or rules. Talk to the owner to add one"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column() {
|
||||
if (channel is PublicChatChannel) {
|
||||
Row() {
|
||||
Spacer(DoubleHorzSpacer)
|
||||
LongChannelActionOptions(channel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(DoubleVertSpacer)
|
||||
|
||||
Row(Modifier.fillMaxWidth().padding(start = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
LoadNote(baseNoteHex = channel.idHex) {
|
||||
it?.let {
|
||||
Text(
|
||||
text = stringResource(id = R.string.owner),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.width(55.dp)
|
||||
)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
NoteAuthorPicture(it, nav, accountViewModel, Size25dp)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
NoteUsernameDisplay(it, remember { Modifier.weight(1f) })
|
||||
TimeAgo(it)
|
||||
MoreOptionsButton(it, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var participantUsers by remember(baseChannel) {
|
||||
mutableStateOf<ImmutableList<Pair<Participant, User>>>(
|
||||
persistentListOf()
|
||||
)
|
||||
}
|
||||
|
||||
if (channel is LiveActivitiesChannel) {
|
||||
LaunchedEffect(key1 = channelState) {
|
||||
launch(Dispatchers.IO) {
|
||||
val newParticipantUsers = channel.info?.participants()?.mapNotNull { part ->
|
||||
LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) }
|
||||
}?.toImmutableList()
|
||||
|
||||
if (newParticipantUsers != null && !equalImmutableLists(newParticipantUsers, participantUsers)) {
|
||||
participantUsers = newParticipantUsers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
participantUsers.forEach {
|
||||
Row(
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(start = 10.dp, top = 10.dp)
|
||||
.clickable {
|
||||
nav("User/${it.second.pubkeyHex}")
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
it.first.role?.let { it1 ->
|
||||
Text(
|
||||
text = it1.capitalize(Locale.ROOT),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.width(55.dp)
|
||||
)
|
||||
}
|
||||
Spacer(DoubleHorzSpacer)
|
||||
ClickableUserPicture(it.second, Size25dp, accountViewModel)
|
||||
Spacer(DoubleHorzSpacer)
|
||||
UsernameDisplay(it.second, remember { Modifier.weight(1f) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChannelActionOptions(
|
||||
private fun ShortChannelActionOptions(
|
||||
channel: PublicChatChannel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
NoteCopyButton(channel)
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val isFollowing by remember(accountState) {
|
||||
derivedStateOf {
|
||||
accountState?.account?.followingChannels?.contains(channel.idHex) ?: false
|
||||
}
|
||||
}
|
||||
|
||||
LoadNote(baseNoteHex = channel.idHex) {
|
||||
it?.let {
|
||||
var popupExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
LikeReaction(baseNote = it, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
ZapReaction(baseNote = it, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFollowing) {
|
||||
JoinChatButton(accountViewModel, channel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LongChannelActionOptions(
|
||||
channel: PublicChatChannel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit
|
||||
) {
|
||||
val isMe by remember(accountViewModel) {
|
||||
derivedStateOf {
|
||||
channel.creator == accountViewModel.account.userProfile()
|
||||
@@ -705,8 +879,6 @@ private fun ChannelActionOptions(
|
||||
|
||||
if (isFollowing) {
|
||||
LeaveChatButton(accountViewModel, channel, nav)
|
||||
} else {
|
||||
JoinChatButton(accountViewModel, channel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,7 +1063,6 @@ fun LeaveChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: (
|
||||
modifier = Modifier.padding(horizontal = 3.dp),
|
||||
onClick = {
|
||||
accountViewModel.account.leaveChannel(channel.idHex)
|
||||
nav(Route.Message.route)
|
||||
},
|
||||
shape = ButtonBorder,
|
||||
colors = ButtonDefaults
|
||||
|
Reference in New Issue
Block a user