feat(subscriptions): make screen subscriptions lifecycle-aware

Migrates 32 call sites from KeyDataSourceSubscription to
LifecycleAwareKeyDataSourceSubscription so feed/screen REQs are
paused when the app goes to background and resumed on foreground,
saving relay bandwidth while the always-on notification service
keeps the socket open.

Adds a MutableComposeSubscriptionManager overload to
LifecycleAwareKeyDataSourceSubscription so the search bars (which
bind to a flow-driven query) can also opt in.

Skips AccountFilterAssemblerSubscription (always-on account state)
and NWCFinderFilterAssemblerSubscription (in-flight zap payments
that must complete in the background).

https://claude.ai/code/session_01RUmRxmzUAcVXezF9PEETGz
This commit is contained in:
Claude
2026-05-04 18:16:15 +00:00
parent 846b25dcd4
commit 98c0438526
33 changed files with 134 additions and 65 deletions
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.model.Channel
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun ChannelFinderFilterAssemblerSubscription(
ChannelFinderQueryState(channel)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -46,5 +46,5 @@ fun EventFinderFilterAssemblerSubscription(
EventFinderQueryState(note, account)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user
import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -52,5 +52,5 @@ fun UserFinderFilterAssemblerSubscription(
UserFinderQueryState(user, forAccount)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -21,7 +21,7 @@
package com.vitorpamplona.amethyst.service.relayClient.searchCommand
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchBarViewModel
@@ -36,5 +36,5 @@ fun TextSearchDataSourceSubscription(
searchBarViewModel: SearchBarViewModel,
dataSource: SearchFilterAssembler,
) {
KeyDataSourceSubscription(searchBarViewModel.searchDataSourceState, dataSource)
LifecycleAwareKeyDataSourceSubscription(searchBarViewModel.searchDataSourceState, dataSource)
}
@@ -21,7 +21,7 @@
package com.vitorpamplona.amethyst.service.relayClient.searchCommand
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -36,5 +36,5 @@ fun UserSearchDataSourceSubscription(
userSuggestions: UserSuggestionState,
dataSource: SearchFilterAssembler,
) {
KeyDataSourceSubscription(userSuggestions.searchDataSourceState, dataSource)
LifecycleAwareKeyDataSourceSubscription(userSuggestions.searchDataSourceState, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun ArticlesFilterAssemblerSubscription(
ArticlesQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun BadgesFilterAssemblerSubscription(
BadgesQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -32,5 +32,5 @@ fun ProfileBadgesFilterAssemblerSubscription(accountViewModel: AccountViewModel)
ProfileBadgesQueryState(accountViewModel.account)
}
KeyDataSourceSubscription(state, accountViewModel.dataSources().profileBadges)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().profileBadges)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
@@ -39,5 +39,5 @@ fun ChatroomFilterAssemblerSubscription(
ChatroomQueryState(room, accountViewModel.account)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -27,7 +27,7 @@ import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.commons.model.Channel
import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -43,7 +43,7 @@ fun ChannelFilterAssemblerSubscription(
ChannelQueryState(channel, accountViewModel.account)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
// Live streams need the 30311 event to populate `channel.info` before we can read its
// `goal` tag and add the goal+zap subscriptions. Re-invalidate when metadata changes so
@@ -25,7 +25,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessViewModelNew
@@ -78,14 +78,14 @@ fun ChessSubscription(
}
// Register subscription with Amethyst's subscription system
KeyDataSourceSubscription(state, chessAssembler)
LifecycleAwareKeyDataSourceSubscription(state, chessAssembler)
// Trigger ViewModel refresh when subscription state changes
// This fetches challenges from LocalCache after events arrive
DisposableEffect(state) {
chessViewModel.forceRefresh()
onDispose {
// Subscription cleanup handled by KeyDataSourceSubscription
// Subscription cleanup handled by LifecycleAwareKeyDataSourceSubscription
}
}
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.AddressableNote
@Composable
@@ -37,5 +37,5 @@ fun CommunityFilterAssemblerSubscription(
CommunityQueryState(channel)
}
KeyDataSourceSubscription(state, filterAssembler)
LifecycleAwareKeyDataSourceSubscription(state, filterAssembler)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.datasourc
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun CommunitiesListFilterAssemblerSubscription(
CommunitiesListQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.datasour
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun BrowseEmojiSetsFilterAssemblerSubscription(
BrowseEmojiSetsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasourc
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -38,5 +38,5 @@ fun FollowPackFeedFilterAssemblerSubscription(
FollowPackFeedQueryState(pack, accountViewModel.account)
}
KeyDataSourceSubscription(state, accountViewModel.dataSources().followPacks)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().followPacks)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.datasourc
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun FollowPacksFilterAssemblerSubscription(
FollowPacksQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.datasource
import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -40,5 +40,5 @@ fun GeoHashFilterAssemblerSubscription(
GeohashQueryState(tag.geohash, accountViewModel.account.followOutboxesOrProxy.flow.value)
}
KeyDataSourceSubscription(state, accountViewModel.dataSources().geohashes)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().geohashes)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -38,5 +38,5 @@ fun HashtagFilterAssemblerSubscription(
HashtagQueryState(tag.hashtag, accountViewModel.account.followOutboxesOrProxy.flow.value)
}
KeyDataSourceSubscription(state, accountViewModel.dataSources().hashtags)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().hashtags)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun LiveStreamsFilterAssemblerSubscription(
LiveStreamsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun LongsFilterAssemblerSubscription(
LongsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.PerUniqueIdEoseManager
@@ -156,5 +156,5 @@ fun NestRoomFilterAssemblerSubscription(
remember(note, account.pubKey) {
NestRoomQueryState(note, account)
}
KeyDataSourceSubscription(state, filterAssembler)
LifecycleAwareKeyDataSourceSubscription(state, filterAssembler)
}
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.PerUniqueIdEoseManager
@@ -137,5 +137,5 @@ fun NestRoomLivenessProbeSubscription(
remember(note, account.pubKey) {
NestRoomLivenessQueryState(note, account)
}
KeyDataSourceSubscription(state, filterAssembler)
LifecycleAwareKeyDataSourceSubscription(state, filterAssembler)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun NestsFilterAssemblerSubscription(
NestsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun PicturesFilterAssemblerSubscription(
PicturesQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun PollsFilterAssemblerSubscription(
PollsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.products.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun ProductsFilterAssemblerSubscription(
ProductsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.User
@Composable
@@ -37,5 +37,5 @@ fun UserProfileFilterAssemblerSubscription(
UserProfileQueryState(user)
}
KeyDataSourceSubscription(state, assembler)
LifecycleAwareKeyDataSourceSubscription(state, assembler)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun PublicChatsFilterAssemblerSubscription(
PublicChatsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
@@ -38,5 +38,5 @@ fun RelayFeedFilterAssemblerSubscription(
RelayFeedQueryState(normalizedUrl)
} ?: return
KeyDataSourceSubscription(state, accountViewModel.dataSources().relayFeed)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().relayFeed)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -36,5 +36,5 @@ fun RelayInfoNip66FilterAssemblerSubscription(
RelayInfoNip66QueryState(relayUrl, accountViewModel.account.followOutboxesOrProxy.flow.value)
}
KeyDataSourceSubscription(state, accountViewModel.dataSources().relayInfoNip66)
LifecycleAwareKeyDataSourceSubscription(state, accountViewModel.dataSources().relayInfoNip66)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.datasource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
@@ -44,5 +44,5 @@ fun ShortsFilterAssemblerSubscription(
ShortsQueryState(accountViewModel.account, accountViewModel.feedStates, accountViewModel.viewModelScope)
}
KeyDataSourceSubscription(state, dataSource)
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
}
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -50,5 +50,5 @@ fun ThreadFilterAssemblerSubscription(
ThreadQueryState(eventId, account)
}
KeyDataSourceSubscription(state, filterAssembler)
LifecycleAwareKeyDataSourceSubscription(state, filterAssembler)
}
@@ -27,6 +27,8 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.MutableComposeSubscriptionManager
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.MutableQueryState
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -119,3 +121,70 @@ fun <T> LifecycleAwareKeyDataSourceSubscription(
}
}
}
@Composable
fun <T : MutableQueryState> LifecycleAwareKeyDataSourceSubscription(
state: T,
dataSource: MutableComposeSubscriptionManager<T>,
) {
val lifecycleOwner = LocalLifecycleOwner.current
val scope = rememberCoroutineScope()
DisposableEffect(state, lifecycleOwner) {
var isSubscribed = false
var pendingUnsubscribe: Job? = null
fun subscribeNow() {
pendingUnsubscribe?.cancel()
pendingUnsubscribe = null
if (!isSubscribed) {
dataSource.subscribe(state)
isSubscribed = true
}
}
fun scheduleUnsubscribe() {
if (!isSubscribed || pendingUnsubscribe != null) return
pendingUnsubscribe =
scope.launch {
delay(UNSUBSCRIBE_GRACE_MILLIS)
if (isSubscribed) {
dataSource.unsubscribe(state)
isSubscribed = false
}
pendingUnsubscribe = null
}
}
val observer =
LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_START -> {
subscribeNow()
}
Lifecycle.Event.ON_STOP -> {
scheduleUnsubscribe()
}
else -> {}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
if (lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
subscribeNow()
}
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
pendingUnsubscribe?.cancel()
pendingUnsubscribe = null
if (isSubscribed) {
dataSource.unsubscribe(state)
isSubscribed = false
}
}
}
}