mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-25 20:47:49 +02:00
Activates live streams to the top feed bubble
This commit is contained in:
@@ -1588,7 +1588,7 @@ object LocalCache : ILocalCache {
|
||||
val isVerified =
|
||||
if (event.createdAt > oldChannel.updatedMetadataAt) {
|
||||
if (wasVerified || justVerify(event)) {
|
||||
oldChannel.updateChannelInfo(author, event)
|
||||
oldChannel.updateChannelInfo(author, event, note)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@@ -40,7 +40,10 @@ class PublicChatChannel(
|
||||
) : Channel() {
|
||||
var creator: User? = null
|
||||
var event: ChannelCreateEvent? = null
|
||||
var eventNote: Note? = null
|
||||
|
||||
// Important to keep this long-term reference because LocalCache uses WeakReferences.
|
||||
var creationEventNote: Note? = null
|
||||
var updateEventNote: Note? = null
|
||||
|
||||
var info = ChannelDataNorm(null, null, null, null)
|
||||
var infoTags = EmptyTagList
|
||||
@@ -71,7 +74,7 @@ class PublicChatChannel(
|
||||
|
||||
this.infoTags = event.tags.toImmutableListOfLists()
|
||||
this.updatedMetadataAt = event.createdAt
|
||||
this.eventNote = eventNote
|
||||
this.creationEventNote = eventNote
|
||||
|
||||
updateChannelInfo()
|
||||
}
|
||||
@@ -79,12 +82,14 @@ class PublicChatChannel(
|
||||
fun updateChannelInfo(
|
||||
creator: User,
|
||||
event: ChannelMetadataEvent,
|
||||
eventNote: Note? = null,
|
||||
) {
|
||||
this.creator = creator
|
||||
this.info = event.channelInfo()
|
||||
|
||||
this.infoTags = event.tags.toImmutableListOfLists()
|
||||
this.updatedMetadataAt = event.createdAt
|
||||
this.updateEventNote = eventNote
|
||||
|
||||
super.updateChannelInfo()
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@ class LiveActivitiesChannel(
|
||||
) : Channel() {
|
||||
var creator: User? = null
|
||||
var info: LiveActivitiesEvent? = null
|
||||
|
||||
// Important to keep this long-term reference because LocalCache uses WeakReferences.
|
||||
var infoNote: Note? = null
|
||||
|
||||
fun address() = address
|
||||
|
@@ -67,8 +67,8 @@ fun RenderVideoPlayer(
|
||||
// if we alrady know the size of the frame, this forces the player to stay in the size
|
||||
layoutParams =
|
||||
FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
)
|
||||
|
||||
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
|
||||
|
@@ -24,8 +24,8 @@ import android.util.Log
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.emphChat.EphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.ui.dal.AdditiveComplexFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
@@ -41,7 +41,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Stable
|
||||
class ChannelFeedContentState(
|
||||
val localFilter: AdditiveComplexFeedFilter<EphemeralChatChannel, Note>,
|
||||
val localFilter: AdditiveComplexFeedFilter<Channel, Note>,
|
||||
val viewModelScope: CoroutineScope,
|
||||
) : InvalidatableContent {
|
||||
private val _feedContent = MutableStateFlow<ChannelFeedState>(ChannelFeedState.Loading)
|
||||
@@ -92,15 +92,15 @@ class ChannelFeedContentState(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFeed(notes: ImmutableList<EphemeralChatChannel>) {
|
||||
private fun updateFeed(notes: ImmutableList<Channel>) {
|
||||
val currentState = _feedContent.value
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.tryEmit(ChannelFeedState.Empty)
|
||||
} else if (currentState is ChannelFeedState.Loaded) {
|
||||
currentState.feed.tryEmit(LoadedFeedState<EphemeralChatChannel>(notes, localFilter.showHiddenKey()))
|
||||
currentState.feed.tryEmit(LoadedFeedState<Channel>(notes, localFilter.showHiddenKey()))
|
||||
} else {
|
||||
_feedContent.tryEmit(
|
||||
ChannelFeedState.Loaded(MutableStateFlow(LoadedFeedState<EphemeralChatChannel>(notes, localFilter.showHiddenKey()))),
|
||||
ChannelFeedState.Loaded(MutableStateFlow(LoadedFeedState<Channel>(notes, localFilter.showHiddenKey()))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@
|
||||
package com.vitorpamplona.amethyst.ui.feeds
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.amethyst.model.emphChat.EphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Stable
|
||||
@@ -29,7 +29,7 @@ sealed class ChannelFeedState {
|
||||
object Loading : ChannelFeedState()
|
||||
|
||||
class Loaded(
|
||||
val feed: MutableStateFlow<LoadedFeedState<EphemeralChatChannel>>,
|
||||
val feed: MutableStateFlow<LoadedFeedState<Channel>>,
|
||||
) : ChannelFeedState()
|
||||
|
||||
object Empty : ChannelFeedState()
|
||||
|
@@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.LiveActivitiesChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
|
@@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -113,12 +112,10 @@ fun LiveActivityChannelView(
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
Column(
|
||||
modifier =
|
||||
remember {
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(vertical = 0.dp)
|
||||
.weight(1f, true)
|
||||
},
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(vertical = 0.dp)
|
||||
.weight(1f, true),
|
||||
) {
|
||||
ShowVideoStreaming(channel, accountViewModel)
|
||||
RefreshingChatroomFeedView(
|
||||
|
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
@@ -51,7 +50,7 @@ fun LiveActivityChannelScreen(
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
Column(Modifier.padding(it).statusBarsPadding()) {
|
||||
Column(Modifier.padding(it)) {
|
||||
LiveActivityChannelView(channelId, draft, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChanne
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ShowVideoStreaming
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdPadding
|
||||
|
||||
@Composable
|
||||
@@ -70,7 +71,11 @@ fun LiveActivitiesChannelHeader(
|
||||
)
|
||||
|
||||
if (expanded.value) {
|
||||
LongLiveActivityChannelHeader(baseChannel, accountViewModel = accountViewModel, nav = nav)
|
||||
LongLiveActivityChannelHeader(
|
||||
baseChannel,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@@ -25,8 +25,6 @@ import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChanne
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarExtensibleWithBackButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.LongLiveActivityChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ShortLiveActivityChannelHeader
|
||||
|
||||
@Composable
|
||||
fun LiveActivityTopBar(
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.ui.note.LikeReaction
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapReaction
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.theme.RowColSpacing
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size34dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
@@ -60,10 +60,10 @@ import com.vitorpamplona.amethyst.ui.note.Gallery
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.EndedFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.LiveActivitiesChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.OfflineFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
|
@@ -57,6 +57,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.AROUND_ME
|
||||
import com.vitorpamplona.amethyst.model.emphChat.EphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
||||
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||
import com.vitorpamplona.amethyst.service.OnlineChecker.isOnline
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
@@ -81,6 +83,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.NewGeoPostButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.live.RenderEphemeralBubble
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.live.RenderLiveActivityBubble
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
@@ -345,8 +348,11 @@ fun DisplayLiveBubbles(
|
||||
val feed by liveFeed.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyRow(HorzPadding, horizontalArrangement = spacedBy(Size5dp)) {
|
||||
itemsIndexed(feed.list, key = { _, item -> item.roomId.toKey() }) { _, item ->
|
||||
RenderEphemeralBubble(item, accountViewModel, nav)
|
||||
itemsIndexed(feed.list, key = { _, item -> item.hashCode() }) { _, item ->
|
||||
when (item) {
|
||||
is EphemeralChatChannel -> RenderEphemeralBubble(item, accountViewModel, nav)
|
||||
is LiveActivitiesChannel -> RenderLiveActivityBubble(item, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,9 +21,11 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.emphChat.EphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
||||
import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.author.AuthorsByOutboxTopNavFilter
|
||||
@@ -35,11 +37,13 @@ import com.vitorpamplona.amethyst.ui.dal.AdditiveComplexFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
class HomeLiveFilter(
|
||||
val account: Account,
|
||||
) : AdditiveComplexFeedFilter<EphemeralChatChannel, Note>() {
|
||||
) : AdditiveComplexFeedFilter<Channel, Note>() {
|
||||
override fun feedKey(): String = account.userProfile().pubkeyHex
|
||||
|
||||
override fun showHiddenKey(): Boolean = false
|
||||
@@ -52,14 +56,17 @@ class HomeLiveFilter(
|
||||
|
||||
fun limitTime() = TimeUtils.fifteenMinutesAgo()
|
||||
|
||||
override fun feed(): List<EphemeralChatChannel> {
|
||||
override fun feed(): List<Channel> {
|
||||
val filterParams = buildFilterParams(account)
|
||||
val fiveMinsAgo = limitTime()
|
||||
val fifteenMinsAgo = limitTime()
|
||||
|
||||
val list =
|
||||
LocalCache.ephemeralChannels.filter { id, channel ->
|
||||
shouldIncludeChannel(channel, filterParams, fiveMinsAgo)
|
||||
}
|
||||
shouldIncludeChannel(channel, filterParams, fifteenMinsAgo)
|
||||
} +
|
||||
LocalCache.liveChatChannels.filter { id, channel ->
|
||||
shouldIncludeChannel(channel, filterParams, fifteenMinsAgo)
|
||||
}
|
||||
|
||||
return sort(list.toSet())
|
||||
}
|
||||
@@ -71,18 +78,42 @@ class HomeLiveFilter(
|
||||
): Boolean =
|
||||
channel.notes
|
||||
.filter { key, value ->
|
||||
acceptableEvent(value, filterParams, timeLimit)
|
||||
acceptableChatEvent(value, filterParams, timeLimit)
|
||||
}.isNotEmpty()
|
||||
|
||||
fun shouldIncludeChannel(
|
||||
channel: LiveActivitiesChannel,
|
||||
filterParams: FilterByListParams,
|
||||
timeLimit: Long,
|
||||
): Boolean {
|
||||
val liveChannel =
|
||||
channel.info?.let {
|
||||
it.createdAt > timeLimit &&
|
||||
it.status() == StatusTag.STATUS.LIVE &&
|
||||
filterParams.match(it, channel.relays().toList())
|
||||
}
|
||||
|
||||
if (liveChannel == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
return channel.notes
|
||||
.filter { key, value ->
|
||||
acceptableChatEvent(value, filterParams, timeLimit)
|
||||
}.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun updateListWith(
|
||||
oldList: List<EphemeralChatChannel>,
|
||||
oldList: List<Channel>,
|
||||
newItems: Set<Note>,
|
||||
): List<EphemeralChatChannel> {
|
||||
val fiveMinsAgo = limitTime()
|
||||
): List<Channel> {
|
||||
val fifteenMinsAgo = limitTime()
|
||||
|
||||
val revisedOldList =
|
||||
oldList.filter { channel ->
|
||||
(channel.lastNote?.createdAt() ?: 0) > fiveMinsAgo
|
||||
val channelTime = (channel as? LiveActivitiesChannel)?.info?.createdAt
|
||||
(channelTime == null || channelTime > fifteenMinsAgo) ||
|
||||
(channel.lastNote?.createdAt() ?: 0) > fifteenMinsAgo
|
||||
}
|
||||
|
||||
val newItemsToBeAdded = applyFilter(newItems)
|
||||
@@ -94,7 +125,12 @@ class HomeLiveFilter(
|
||||
if (room != null) {
|
||||
LocalCache.getEphemeralChatChannelIfExists(room)
|
||||
} else {
|
||||
null
|
||||
val liveStream = (it.event as? LiveActivitiesChatMessageEvent)?.activityAddress()
|
||||
if (liveStream != null) {
|
||||
LocalCache.getLiveActivityChannelIfExists(liveStream)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,23 +145,23 @@ class HomeLiveFilter(
|
||||
val filterParams = buildFilterParams(account)
|
||||
|
||||
return collection.filterTo(HashSet()) {
|
||||
acceptableEvent(it, filterParams, limitTime())
|
||||
acceptableChatEvent(it, filterParams, limitTime())
|
||||
}
|
||||
}
|
||||
|
||||
private fun acceptableEvent(
|
||||
private fun acceptableChatEvent(
|
||||
note: Note,
|
||||
filterParams: FilterByListParams,
|
||||
timeLimit: Long,
|
||||
): Boolean {
|
||||
val createdAt = note.createdAt() ?: return false
|
||||
val noteEvent = note.event
|
||||
return (noteEvent is EphemeralChatEvent) &&
|
||||
return (noteEvent is EphemeralChatEvent || noteEvent is LiveActivitiesChatMessageEvent) &&
|
||||
createdAt > timeLimit &&
|
||||
filterParams.match(noteEvent, note.relays)
|
||||
}
|
||||
|
||||
fun sort(collection: Set<EphemeralChatChannel>): List<EphemeralChatChannel> {
|
||||
fun sort(collection: Set<Channel>): List<Channel> {
|
||||
val topFilter = account.liveHomeFollowLists.value
|
||||
val topFilterAuthors =
|
||||
when (topFilter) {
|
||||
@@ -145,15 +181,14 @@ class HomeLiveFilter(
|
||||
collection.associateWith { followsThatParticipateOn(it, followingKeySet) }
|
||||
|
||||
return collection.sortedWith(
|
||||
compareByDescending<EphemeralChatChannel> { followCounts[it] }
|
||||
.thenByDescending<EphemeralChatChannel> { it.lastNote?.createdAt() ?: 0 }
|
||||
.thenBy { it.roomId.id }
|
||||
.thenBy { it.roomId.relayUrl },
|
||||
compareByDescending<Channel> { followCounts[it] }
|
||||
.thenByDescending<Channel> { it.lastNote?.createdAt() ?: 0 }
|
||||
.thenBy { it.hashCode() },
|
||||
)
|
||||
}
|
||||
|
||||
fun followsThatParticipateOn(
|
||||
channel: EphemeralChatChannel,
|
||||
channel: Channel,
|
||||
followingSet: Set<HexKey>?,
|
||||
): Int {
|
||||
var count = 0
|
||||
|
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.live
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelNoteAuthors
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.Gallery
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
|
||||
@Composable
|
||||
fun RenderLiveActivityBubble(
|
||||
channel: LiveActivitiesChannel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
FilledTonalButton(
|
||||
contentPadding = PaddingValues(start = 8.dp, end = 10.dp, bottom = 0.dp, top = 0.dp),
|
||||
onClick = {
|
||||
nav.nav { routeFor(channel) }
|
||||
},
|
||||
) {
|
||||
RenderUsers(channel, accountViewModel, nav)
|
||||
Spacer(StdHorzSpacer)
|
||||
Text(
|
||||
channel.toBestDisplayName(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderUsers(
|
||||
channel: LiveActivitiesChannel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val authors by observeChannelNoteAuthors(channel, accountViewModel)
|
||||
|
||||
Gallery(authors, Modifier, accountViewModel, nav, 3)
|
||||
}
|
Reference in New Issue
Block a user