mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-28 21:03:14 +02:00
Replaces the Live bar in the top of the feed for Notification dots in the LiveStream bottom button.
This commit is contained in:
@@ -10,7 +10,7 @@ import okhttp3.Request
|
|||||||
data class OnlineCheckResult(val timeInMs: Long, val online: Boolean)
|
data class OnlineCheckResult(val timeInMs: Long, val online: Boolean)
|
||||||
|
|
||||||
object OnlineChecker {
|
object OnlineChecker {
|
||||||
val checkOnlineCache = LruCache<String, OnlineCheckResult>(10)
|
val checkOnlineCache = LruCache<String, OnlineCheckResult>(100)
|
||||||
val fiveMinutes = 1000 * 60 * 5
|
val fiveMinutes = 1000 * 60 * 5
|
||||||
|
|
||||||
fun isOnline(url: String?): Boolean {
|
fun isOnline(url: String?): Boolean {
|
||||||
|
@@ -9,7 +9,7 @@ import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.ST
|
|||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE
|
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_PLANNED
|
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_PLANNED
|
||||||
|
|
||||||
class DiscoverFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
open class DiscoverFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
||||||
override fun feedKey(): String {
|
override fun feedKey(): String {
|
||||||
return account.userProfile().pubkeyHex + "-" + account.defaultDiscoveryFollowList
|
return account.userProfile().pubkeyHex + "-" + account.defaultDiscoveryFollowList
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ class DiscoverFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
|||||||
return innerApplyFilter(collection)
|
return innerApplyFilter(collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
|
protected open fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
|
||||||
val now = System.currentTimeMillis() / 1000
|
val now = System.currentTimeMillis() / 1000
|
||||||
val isGlobal = account.defaultDiscoveryFollowList == GLOBAL_FOLLOWS
|
val isGlobal = account.defaultDiscoveryFollowList == GLOBAL_FOLLOWS
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ class DiscoverFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
|||||||
val activities = collection
|
val activities = collection
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.event is LiveActivitiesEvent }
|
.filter { it.event is LiveActivitiesEvent }
|
||||||
.filter { isGlobal || it.author?.pubkeyHex in followingKeySet }
|
.filter { isGlobal || it.author?.pubkeyHex in followingKeySet || it.event?.isTaggedHashes(followingTagSet) == true }
|
||||||
.filter { account.isAcceptable(it) }
|
.filter { it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true }
|
||||||
.filter { (it.createdAt() ?: 0) <= now }
|
.filter { (it.createdAt() ?: 0) <= now }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
|
@@ -0,0 +1,20 @@
|
|||||||
|
package com.vitorpamplona.amethyst.ui.dal
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
|
import com.vitorpamplona.amethyst.service.model.*
|
||||||
|
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE
|
||||||
|
|
||||||
|
class DiscoverLiveNowFeedFilter(account: Account) : DiscoverFeedFilter(account) {
|
||||||
|
override fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
|
||||||
|
val allItems = super.innerApplyFilter(collection)
|
||||||
|
|
||||||
|
val onlineOnly = allItems.filter {
|
||||||
|
val noteEvent = it.event as? LiveActivitiesEvent
|
||||||
|
noteEvent?.status() == STATUS_LIVE && OnlineChecker.isOnline(noteEvent.streaming())
|
||||||
|
}
|
||||||
|
|
||||||
|
return onlineOnly.toSet()
|
||||||
|
}
|
||||||
|
}
|
@@ -1,58 +0,0 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.dal
|
|
||||||
|
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
|
||||||
import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS
|
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
|
||||||
import com.vitorpamplona.amethyst.service.OnlineChecker
|
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
class HomeLiveActivitiesFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
|
||||||
override fun feedKey(): String {
|
|
||||||
val followingKeySet = account.selectedUsersFollowList(account.defaultHomeFollowList)?.size ?: 0
|
|
||||||
val followingTagSet = account.selectedTagsFollowList(account.defaultHomeFollowList)?.size ?: 0
|
|
||||||
|
|
||||||
return account.userProfile().pubkeyHex + "-" + account.defaultHomeFollowList + "-" + followingKeySet + "-" + followingTagSet
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
|
||||||
val longFormNotes = innerApplyFilter(LocalCache.addressables.values)
|
|
||||||
|
|
||||||
return sort(longFormNotes)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
|
||||||
return innerApplyFilter(collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
|
|
||||||
checkNotInMainThread()
|
|
||||||
|
|
||||||
val isGlobal = account.defaultHomeFollowList == GLOBAL_FOLLOWS
|
|
||||||
|
|
||||||
val followingKeySet = account.selectedUsersFollowList(account.defaultHomeFollowList) ?: emptySet()
|
|
||||||
val followingTagSet = account.selectedTagsFollowList(account.defaultHomeFollowList) ?: emptySet()
|
|
||||||
|
|
||||||
val twoHrs = (Date().time / 1000) - 60 * 60 * 2 // hrs
|
|
||||||
|
|
||||||
return collection
|
|
||||||
.asSequence()
|
|
||||||
.filter { it ->
|
|
||||||
val noteEvent = it.event
|
|
||||||
(noteEvent is LiveActivitiesEvent && noteEvent.createdAt > twoHrs && noteEvent.status() == STATUS_LIVE && OnlineChecker.isOnline(noteEvent.streaming())) &&
|
|
||||||
(isGlobal || it.author?.pubkeyHex in followingKeySet || noteEvent.isTaggedHashes(followingTagSet)) &&
|
|
||||||
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
|
||||||
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true
|
|
||||||
}
|
|
||||||
.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun limit() = 2
|
|
||||||
|
|
||||||
override fun sort(collection: Set<Note>): List<Note> {
|
|
||||||
return collection.sortedWith(compareBy({ it.createdAt() }, { it.idHex })).reversed()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -13,7 +13,6 @@ import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedLiveActivitiesViewModel
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
|
||||||
@@ -40,7 +39,6 @@ import kotlinx.coroutines.launch
|
|||||||
fun AppNavigation(
|
fun AppNavigation(
|
||||||
homeFeedViewModel: NostrHomeFeedViewModel,
|
homeFeedViewModel: NostrHomeFeedViewModel,
|
||||||
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
||||||
liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel,
|
|
||||||
knownFeedViewModel: NostrChatroomListKnownFeedViewModel,
|
knownFeedViewModel: NostrChatroomListKnownFeedViewModel,
|
||||||
newFeedViewModel: NostrChatroomListNewFeedViewModel,
|
newFeedViewModel: NostrChatroomListNewFeedViewModel,
|
||||||
videoFeedViewModel: NostrVideoFeedViewModel,
|
videoFeedViewModel: NostrVideoFeedViewModel,
|
||||||
@@ -70,7 +68,6 @@ fun AppNavigation(
|
|||||||
HomeScreen(
|
HomeScreen(
|
||||||
homeFeedViewModel = homeFeedViewModel,
|
homeFeedViewModel = homeFeedViewModel,
|
||||||
repliesFeedViewModel = repliesFeedViewModel,
|
repliesFeedViewModel = repliesFeedViewModel,
|
||||||
liveActivitiesViewModel = liveActivitiesViewModel,
|
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
nip47 = nip47
|
nip47 = nip47
|
||||||
|
@@ -17,6 +17,7 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
|||||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||||
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.ChatroomListKnownFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.ChatroomListKnownFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.DiscoverLiveNowFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
@@ -59,7 +60,8 @@ sealed class Route(
|
|||||||
|
|
||||||
object Discover : Route(
|
object Discover : Route(
|
||||||
route = "Discover",
|
route = "Discover",
|
||||||
icon = R.drawable.ic_sensors
|
icon = R.drawable.ic_sensors,
|
||||||
|
hasNewItems = { accountViewModel, newNotes -> DiscoverLatestItem.hasNewItems(accountViewModel, newNotes) }
|
||||||
)
|
)
|
||||||
|
|
||||||
object Notification : Route(
|
object Notification : Route(
|
||||||
@@ -186,6 +188,21 @@ object HomeLatestItem : LatestItem() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object DiscoverLatestItem : LatestItem() {
|
||||||
|
fun hasNewItems(
|
||||||
|
account: Account,
|
||||||
|
newNotes: Set<Note>
|
||||||
|
): Boolean {
|
||||||
|
checkNotInMainThread()
|
||||||
|
|
||||||
|
val lastTime = account.loadLastRead(Route.Discover.base)
|
||||||
|
|
||||||
|
val newestItem = updateNewestItem(newNotes, account, DiscoverLiveNowFeedFilter(account))
|
||||||
|
|
||||||
|
return (newestItem?.createdAt() ?: 0) > lastTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object NotificationLatestItem : LatestItem() {
|
object NotificationLatestItem : LatestItem() {
|
||||||
fun hasNewItems(
|
fun hasNewItems(
|
||||||
account: Account,
|
account: Account,
|
||||||
|
@@ -25,7 +25,6 @@ import com.vitorpamplona.amethyst.ui.dal.DiscoverFeedFilter
|
|||||||
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.FeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.HashtagFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.HashtagFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.HomeLiveActivitiesFeedFilter
|
|
||||||
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.ThreadFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.ThreadFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.UserProfileAppRecommendationsFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileAppRecommendationsFeedFilter
|
||||||
@@ -130,15 +129,6 @@ class NostrChatroomListNewFeedViewModel(val account: Account) : FeedViewModel(Ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Stable
|
|
||||||
class NostrHomeFeedLiveActivitiesViewModel(val account: Account) : FeedViewModel(HomeLiveActivitiesFeedFilter(account)) {
|
|
||||||
class Factory(val account: Account) : ViewModelProvider.Factory {
|
|
||||||
override fun <NostrHomeFeedLiveActivitiesViewModel : ViewModel> create(modelClass: Class<NostrHomeFeedLiveActivitiesViewModel>): NostrHomeFeedLiveActivitiesViewModel {
|
|
||||||
return NostrHomeFeedLiveActivitiesViewModel(account) as NostrHomeFeedLiveActivitiesViewModel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class NostrHomeFeedViewModel(val account: Account) : FeedViewModel(HomeNewThreadFeedFilter(account)) {
|
class NostrHomeFeedViewModel(val account: Account) : FeedViewModel(HomeNewThreadFeedFilter(account)) {
|
||||||
class Factory(val account: Account) : ViewModelProvider.Factory {
|
class Factory(val account: Account) : ViewModelProvider.Factory {
|
||||||
|
@@ -25,6 +25,7 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.service.NostrDiscoveryDataSource
|
import com.vitorpamplona.amethyst.service.NostrDiscoveryDataSource
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.note.ChannelCardCompose
|
import com.vitorpamplona.amethyst.ui.note.ChannelCardCompose
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedEmpty
|
import com.vitorpamplona.amethyst.ui.screen.FeedEmpty
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedError
|
import com.vitorpamplona.amethyst.ui.screen.FeedError
|
||||||
@@ -70,7 +71,7 @@ fun DiscoverScreen(
|
|||||||
) {
|
) {
|
||||||
RefresheableView(discoveryFeedViewModel, true) {
|
RefresheableView(discoveryFeedViewModel, true) {
|
||||||
SaveableFeedState(discoveryFeedViewModel, scrollStateKey = ScrollStateKeys.DISCOVER_SCREEN) { listState ->
|
SaveableFeedState(discoveryFeedViewModel, scrollStateKey = ScrollStateKeys.DISCOVER_SCREEN) { listState ->
|
||||||
RenderDiscoverFeed(discoveryFeedViewModel, accountViewModel, listState, nav)
|
RenderDiscoverFeed(discoveryFeedViewModel, Route.Discover.base, accountViewModel, listState, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +81,7 @@ fun DiscoverScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun RenderDiscoverFeed(
|
private fun RenderDiscoverFeed(
|
||||||
viewModel: FeedViewModel,
|
viewModel: FeedViewModel,
|
||||||
|
routeForLastRead: String?,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
@@ -106,6 +108,7 @@ private fun RenderDiscoverFeed(
|
|||||||
is FeedState.Loaded -> {
|
is FeedState.Loaded -> {
|
||||||
DiscoverFeedLoaded(
|
DiscoverFeedLoaded(
|
||||||
state,
|
state,
|
||||||
|
routeForLastRead,
|
||||||
listState,
|
listState,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
nav
|
nav
|
||||||
@@ -133,6 +136,7 @@ fun WatchAccountForDiscoveryScreen(discoveryViewModel: NostrDiscoverFeedViewMode
|
|||||||
@Composable
|
@Composable
|
||||||
private fun DiscoverFeedLoaded(
|
private fun DiscoverFeedLoaded(
|
||||||
state: FeedState.Loaded,
|
state: FeedState.Loaded,
|
||||||
|
routeForLastRead: String?,
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
@@ -150,7 +154,8 @@ private fun DiscoverFeedLoaded(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChannelCardCompose(
|
ChannelCardCompose(
|
||||||
item,
|
baseNote = item,
|
||||||
|
routeForLastRead = routeForLastRead,
|
||||||
modifier = defaultModifier,
|
modifier = defaultModifier,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav
|
nav = nav
|
||||||
|
@@ -1,15 +1,10 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.PagerState
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
@@ -20,7 +15,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -33,17 +27,12 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.map
|
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
|
||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
import com.vitorpamplona.amethyst.service.OnlineChecker
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedState
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedLiveActivitiesViewModel
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.PagerStateKeys
|
import com.vitorpamplona.amethyst.ui.screen.PagerStateKeys
|
||||||
@@ -60,7 +49,6 @@ import kotlinx.coroutines.launch
|
|||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
homeFeedViewModel: NostrHomeFeedViewModel,
|
homeFeedViewModel: NostrHomeFeedViewModel,
|
||||||
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
||||||
liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel,
|
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
nip47: String? = null
|
nip47: String? = null
|
||||||
@@ -69,7 +57,7 @@ fun HomeScreen(
|
|||||||
|
|
||||||
val pagerState = rememberForeverPagerState(key = PagerStateKeys.HOME_SCREEN)
|
val pagerState = rememberForeverPagerState(key = PagerStateKeys.HOME_SCREEN)
|
||||||
|
|
||||||
WatchAccountForHomeScreen(homeFeedViewModel, repliesFeedViewModel, liveActivitiesViewModel, accountViewModel)
|
WatchAccountForHomeScreen(homeFeedViewModel, repliesFeedViewModel, accountViewModel)
|
||||||
|
|
||||||
if (wantsToAddNip47 != null) {
|
if (wantsToAddNip47 != null) {
|
||||||
UpdateZapAmountDialog({ wantsToAddNip47 = null }, wantsToAddNip47, accountViewModel)
|
UpdateZapAmountDialog({ wantsToAddNip47 = null }, wantsToAddNip47, accountViewModel)
|
||||||
@@ -77,8 +65,6 @@ fun HomeScreen(
|
|||||||
|
|
||||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||||
DisposableEffect(accountViewModel) {
|
DisposableEffect(accountViewModel) {
|
||||||
liveActivitiesViewModel.invalidateData(true)
|
|
||||||
|
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
if (event == Lifecycle.Event.ON_RESUME) {
|
if (event == Lifecycle.Event.ON_RESUME) {
|
||||||
NostrHomeDataSource.invalidateFilters()
|
NostrHomeDataSource.invalidateFilters()
|
||||||
@@ -104,7 +90,7 @@ fun HomeScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(vertical = 0.dp)
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
) {
|
) {
|
||||||
HomePages(pagerState, tabs, liveActivitiesViewModel, accountViewModel, nav)
|
HomePages(pagerState, tabs, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +100,6 @@ fun HomeScreen(
|
|||||||
private fun HomePages(
|
private fun HomePages(
|
||||||
pagerState: PagerState,
|
pagerState: PagerState,
|
||||||
tabs: ImmutableList<TabItem>,
|
tabs: ImmutableList<TabItem>,
|
||||||
liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel,
|
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -137,12 +122,6 @@ private fun HomePages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveActivities(
|
|
||||||
liveActivitiesViewModel = liveActivitiesViewModel,
|
|
||||||
accountViewModel = accountViewModel,
|
|
||||||
nav = nav
|
|
||||||
)
|
|
||||||
|
|
||||||
HorizontalPager(pageCount = 2, state = pagerState) { page ->
|
HorizontalPager(pageCount = 2, state = pagerState) { page ->
|
||||||
RefresheableFeedView(
|
RefresheableFeedView(
|
||||||
viewModel = tabs[page].viewModel,
|
viewModel = tabs[page].viewModel,
|
||||||
@@ -154,73 +133,6 @@ private fun HomePages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun LiveActivities(
|
|
||||||
liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel,
|
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
nav: (String) -> Unit
|
|
||||||
) {
|
|
||||||
val feedState by liveActivitiesViewModel.feedContent.collectAsState()
|
|
||||||
|
|
||||||
Crossfade(
|
|
||||||
targetState = feedState,
|
|
||||||
animationSpec = tween(durationMillis = 100)
|
|
||||||
) { state ->
|
|
||||||
when (state) {
|
|
||||||
is FeedState.Loaded -> {
|
|
||||||
FeedLoaded(
|
|
||||||
state,
|
|
||||||
accountViewModel,
|
|
||||||
nav
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun FeedLoaded(
|
|
||||||
state: FeedState.Loaded,
|
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
nav: (String) -> Unit
|
|
||||||
) {
|
|
||||||
val listState = rememberLazyListState()
|
|
||||||
|
|
||||||
LazyColumn(
|
|
||||||
contentPadding = PaddingValues(),
|
|
||||||
state = listState
|
|
||||||
) {
|
|
||||||
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
|
||||||
CheckIfLiveActivityIsOnline(item) {
|
|
||||||
ChannelHeader(
|
|
||||||
channelHex = remember { item.idHex },
|
|
||||||
showVideo = false,
|
|
||||||
showBottomDiviser = true,
|
|
||||||
modifier = remember {
|
|
||||||
Modifier.padding(start = 10.dp, end = 10.dp, top = 5.dp, bottom = 5.dp)
|
|
||||||
},
|
|
||||||
accountViewModel = accountViewModel,
|
|
||||||
nav = nav
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CheckIfLiveActivityIsOnline(note: Note, whenOnline: @Composable () -> Unit) {
|
|
||||||
val url by note.live().metadata.map {
|
|
||||||
(note.event as? LiveActivitiesEvent)?.streaming()
|
|
||||||
}.observeAsState()
|
|
||||||
|
|
||||||
url?.let {
|
|
||||||
CheckIfUrlIsOnline(it, whenOnline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CheckIfUrlIsOnline(url: String, whenOnline: @Composable () -> Unit) {
|
fun CheckIfUrlIsOnline(url: String, whenOnline: @Composable () -> Unit) {
|
||||||
var online by remember { mutableStateOf(false) }
|
var online by remember { mutableStateOf(false) }
|
||||||
@@ -242,7 +154,6 @@ fun CheckIfUrlIsOnline(url: String, whenOnline: @Composable () -> Unit) {
|
|||||||
fun WatchAccountForHomeScreen(
|
fun WatchAccountForHomeScreen(
|
||||||
homeFeedViewModel: NostrHomeFeedViewModel,
|
homeFeedViewModel: NostrHomeFeedViewModel,
|
||||||
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
||||||
liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel,
|
|
||||||
accountViewModel: AccountViewModel
|
accountViewModel: AccountViewModel
|
||||||
) {
|
) {
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
@@ -253,7 +164,6 @@ fun WatchAccountForHomeScreen(
|
|||||||
NostrHomeDataSource.invalidateFilters()
|
NostrHomeDataSource.invalidateFilters()
|
||||||
homeFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
homeFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
||||||
repliesFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
repliesFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
||||||
liveActivitiesViewModel.checkKeysInvalidateDataAndSendToTop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedLiveActivitiesViewModel
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
|
||||||
@@ -89,11 +88,6 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
|
|||||||
factory = NostrHomeRepliesFeedViewModel.Factory(accountViewModel.account)
|
factory = NostrHomeRepliesFeedViewModel.Factory(accountViewModel.account)
|
||||||
)
|
)
|
||||||
|
|
||||||
val liveActivitiesViewModel: NostrHomeFeedLiveActivitiesViewModel = viewModel(
|
|
||||||
key = accountViewModel.userProfile().pubkeyHex + "NostrHomeLiveActivitiesFeedViewModel",
|
|
||||||
factory = NostrHomeFeedLiveActivitiesViewModel.Factory(accountViewModel.account)
|
|
||||||
)
|
|
||||||
|
|
||||||
val videoFeedViewModel: NostrVideoFeedViewModel = viewModel(
|
val videoFeedViewModel: NostrVideoFeedViewModel = viewModel(
|
||||||
key = accountViewModel.userProfile().pubkeyHex + "NostrVideoFeedViewModel",
|
key = accountViewModel.userProfile().pubkeyHex + "NostrVideoFeedViewModel",
|
||||||
factory = NostrVideoFeedViewModel.Factory(accountViewModel.account)
|
factory = NostrVideoFeedViewModel.Factory(accountViewModel.account)
|
||||||
@@ -187,18 +181,17 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
|
|||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(bottom = it.calculateBottomPadding())) {
|
Column(modifier = Modifier.padding(bottom = it.calculateBottomPadding())) {
|
||||||
AppNavigation(
|
AppNavigation(
|
||||||
homeFeedViewModel,
|
homeFeedViewModel = homeFeedViewModel,
|
||||||
repliesFeedViewModel,
|
repliesFeedViewModel = repliesFeedViewModel,
|
||||||
liveActivitiesViewModel,
|
knownFeedViewModel = knownFeedViewModel,
|
||||||
knownFeedViewModel,
|
newFeedViewModel = newFeedViewModel,
|
||||||
newFeedViewModel,
|
videoFeedViewModel = videoFeedViewModel,
|
||||||
videoFeedViewModel,
|
discoveryFeedViewModel = discoveryFeedViewModel,
|
||||||
discoveryFeedViewModel,
|
notifFeedViewModel = notifFeedViewModel,
|
||||||
notifFeedViewModel,
|
userReactionsStatsModel = userReactionsStatsModel,
|
||||||
userReactionsStatsModel,
|
navController = navController,
|
||||||
navController,
|
accountViewModel = accountViewModel,
|
||||||
accountViewModel,
|
nextPage = startingPage
|
||||||
startingPage
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user