Solving some more stability issues

This commit is contained in:
Vitor Pamplona
2026-02-25 16:53:50 -05:00
parent 105dfa21fb
commit 591c32ceb3
32 changed files with 77 additions and 3 deletions
@@ -20,10 +20,12 @@
*/
package com.vitorpamplona.amethyst.model
import androidx.compose.runtime.Stable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@Stable
class UiSettingsFlow(
val theme: MutableStateFlow<ThemeType> = MutableStateFlow(ThemeType.SYSTEM),
val preferredLanguage: MutableStateFlow<String?> = MutableStateFlow(null),
@@ -20,10 +20,12 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
@Stable
class NotifyRequestsCache {
val transientPaymentRequestDismissals: MutableStateFlow<Set<NotifyRequest>> = MutableStateFlow(emptySet())
val transientPaymentRequests: MutableStateFlow<Set<NotifyRequest>> = MutableStateFlow(emptySet())
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
@@ -38,6 +39,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.auth.IAuthStatus
import kotlinx.coroutines.CoroutineScope
// This allows multiple screen to be listening to logged-in accounts.
@Stable
class AccountQueryState(
val account: Account,
val feedContentStates: AccountFeedContentStates,
@@ -47,6 +49,7 @@ class AccountQueryState(
/**
* This assembler loads everything eech account needs.
*/
@Stable
class AccountFilterAssembler(
client: INostrClient,
cache: LocalCache,
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.model.Channel
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.mixChatsLive.ChannelMetadataAndLiveActivityWatcherSubAssembler
@@ -27,10 +28,12 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.nip28Pu
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class ChannelFinderQueryState(
val channel: Channel,
)
@Stable
class ChannelFinderFilterAssemblyGroup(
client: INostrClient,
) : ComposeSubscriptionManager<ChannelFinderQueryState>() {
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
@@ -28,11 +29,13 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.watchers.
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class EventFinderQueryState(
val note: Note,
val account: Account,
)
@Stable
class EventFinderFilterAssembler(
client: INostrClient,
) : ComposeSubscriptionManager<EventFinderQueryState>() {
@@ -20,12 +20,14 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class NWCPaymentQueryState(
val fromServiceHex: HexKey,
val toUserHex: HexKey,
@@ -33,6 +35,7 @@ class NWCPaymentQueryState(
val relay: NormalizedRelayUrl,
)
@Stable
class NWCPaymentFilterAssembler(
client: INostrClient,
) : ComposeSubscriptionManager<NWCPaymentQueryState>() {
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
@@ -32,11 +33,13 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class UserFinderQueryState(
val user: User,
val account: Account,
)
@Stable
class UserFinderFilterAssembler(
client: INostrClient,
cache: LocalCache,
@@ -40,6 +40,7 @@ class SearchQueryState(
override fun flow(): Flow<String> = searchQuery
}
@Stable
class SearchFilterAssembler(
client: INostrClient,
scope: CoroutineScope,
@@ -21,7 +21,9 @@
package com.vitorpamplona.amethyst.ui.note.creators.zapraiser
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
@Stable
interface IZapRaiser {
val zapRaiserAmount: MutableState<Long?>
@@ -21,9 +21,11 @@
package com.vitorpamplona.amethyst.ui.note.creators.zapsplits
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.ui.text.input.TextFieldValue
import com.vitorpamplona.amethyst.model.User
@Stable
interface IZapField {
val forwardZapTo: MutableState<SplitBuilder<User>>
val forwardZapToEditting: MutableState<TextFieldValue>
@@ -20,19 +20,25 @@
*/
package com.vitorpamplona.amethyst.ui.screen
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.model.User
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
@Stable
sealed class UserFeedState {
@Stable
object Loading : UserFeedState()
@Stable
class Loaded(
val feed: MutableStateFlow<ImmutableList<User>>,
) : UserFeedState()
@Stable
object Empty : UserFeedState()
@Stable
class FeedError(
val errorMessage: String,
) : UserFeedState()
@@ -20,15 +20,18 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class ChatroomListState(
val account: Account,
)
@Stable
class ChatroomListFilterAssembler(
client: INostrClient,
) : ComposeSubscriptionManager<ChatroomListState>() {
@@ -54,6 +54,7 @@ import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size40dp
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.launch
@Immutable
@@ -66,7 +67,7 @@ class MessagesTabItem(
@Composable
fun MessagesTabHeader(
pagerState: PagerState,
tabs: List<MessagesTabItem>,
tabs: ImmutableList<MessagesTabItem>,
onMarkKnownAsRead: () -> Unit,
onMarkNewAsRead: () -> Unit,
) {
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.Chat
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesPager
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesTabHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesTabItem
import kotlinx.collections.immutable.persistentListOf
@Composable
fun MessagesSinglePane(
@@ -60,7 +61,7 @@ fun MessagesSinglePane(
val tabs by
remember(knownFeedContentState) {
derivedStateOf {
listOf(
persistentListOf(
MessagesTabItem(R.string.known, ScrollStateKeys.MESSAGES_KNOWN, knownFeedContentState),
MessagesTabItem(R.string.new_requests, ScrollStateKeys.MESSAGES_NEW, newFeedContentState),
)
@@ -38,6 +38,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.Chat
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesPager
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesTabHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesTabItem
import kotlinx.collections.immutable.persistentListOf
@Composable
fun ChatroomList(
@@ -56,7 +57,7 @@ fun ChatroomList(
val tabs by
remember(knownFeedContentState) {
derivedStateOf {
listOf(
persistentListOf(
MessagesTabItem(R.string.known, ScrollStateKeys.MESSAGES_KNOWN, knownFeedContentState),
MessagesTabItem(R.string.new_requests, ScrollStateKeys.MESSAGES_NEW, newFeedContentState),
)
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountFeedContentStates
@@ -28,12 +29,15 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import kotlinx.coroutines.CoroutineScope
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class HomeQueryState(
val account: Account,
val feedState: AccountFeedContentStates,
val scope: CoroutineScope,
)
@Stable
class HomeFilterAssembler(
client: INostrClient,
) : ComposeSubscriptionManager<HomeQueryState>() {
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.proxy
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoModel
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@Stable
class ProxyRelayListViewModel : BasicRelaySetupInfoModel() {
override fun getRelayList(): List<NormalizedRelayUrl>? =
account.proxyRelayList.flow.value
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.trusted
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoModel
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@Stable
class TrustedRelayListViewModel : BasicRelaySetupInfoModel() {
override fun getRelayList(): List<NormalizedRelayUrl>? =
account.trustedRelayList.flow.value
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.subassembies.ThreadEventLoaderSubAssembler
@@ -28,11 +29,13 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
// This allows multiple screen to be listening to tags, even the same tag
@Stable
class ThreadQueryState(
val eventId: HexKey,
val account: Account,
)
@Stable
class ThreadFilterAssembler(
client: INostrClient,
) : ComposeSubscriptionManager<ThreadQueryState>() {
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedOff.login
import androidx.compose.runtime.Stable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -29,6 +30,7 @@ import androidx.lifecycle.ViewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
@Stable
class LoginViewModel : ViewModel() {
lateinit var accountStateViewModel: AccountStateViewModel
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.amethyst.ui.tor
import androidx.compose.runtime.Stable
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@Stable
class TorSettingsFlow(
val torType: MutableStateFlow<TorType> = MutableStateFlow(TorType.INTERNAL),
val externalSocksPort: MutableStateFlow<Int> = MutableStateFlow(9050),
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.commons.viewmodels.thread
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -45,6 +46,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
@Stable
abstract class LevelFeedViewModel(
localFilter: FeedFilter<Note>,
cacheProvider: ICacheProvider,
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.quartz.experimental.interactiveStories
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.experimental.interactiveStories.tags.StoryOptionTag
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -27,6 +28,7 @@ import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag
import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag
import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag
@Stable
open class InteractiveStoryBaseEvent(
id: HexKey,
pubKey: HexKey,
@@ -20,6 +20,9 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds
import androidx.compose.runtime.Stable
@Stable
interface ExternalId {
fun toScope(): String
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.location
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class GeohashId(
val geohash: String,
val hint: String? = null,
@@ -20,10 +20,12 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.movies
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
import kotlin.math.min
@Stable
class MovieId(
val isan: String,
val hint: String? = null,
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.papers
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class PaperId(
val doi: String,
val hint: String? = null,
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.podcasts
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class PodcastEpisodeId(
val guid: String,
val hint: String? = null,
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.podcasts
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class PodcastFeedId(
val guid: String,
val hint: String? = null,
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.podcasts
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class PodcastPublisherId(
val guid: String,
val hint: String? = null,
@@ -20,9 +20,11 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.topics
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.ensure
@Stable
class HashtagId(
val topic: String,
val hint: String? = null,
@@ -20,10 +20,12 @@
*/
package com.vitorpamplona.quartz.nip73ExternalIds.urls
import androidx.compose.runtime.Stable
import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId
import com.vitorpamplona.quartz.utils.Rfc3986
import com.vitorpamplona.quartz.utils.ensure
@Stable
class UrlId(
val url: String,
val hint: String? = null,