diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt index ec79f5a4ee..e5db4bcd67 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt @@ -25,7 +25,9 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.experimental.trustedAssertions.list.TrustProviderListEvent +import com.vitorpamplona.quartz.experimental.trustedAssertions.list.tags.ProviderTypes import com.vitorpamplona.quartz.experimental.trustedAssertions.list.tags.ServiceProviderTag +import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope @@ -36,6 +38,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest @@ -76,6 +79,38 @@ class TrustProviderListState( emptySet(), ) + @OptIn(ExperimentalCoroutinesApi::class) + val liveUserRankProvider: StateFlow = + liveTrustProviderList.map { + it.firstOrNull { it.service == ProviderTypes.rank } + }.onStart { + emit( + liveTrustProviderList.value.firstOrNull { + it.service == ProviderTypes.rank + } + ) + }.flowOn(Dispatchers.IO) + .stateIn( + scope, + SharingStarted.Eagerly, + null, + ) + + @OptIn(ExperimentalCoroutinesApi::class) + val liveUserFollowerCount: StateFlow = + liveTrustProviderList.map { tagList -> + tagList.firstOrNull { it.service == ProviderTypes.followerCount } + }.onStart { + emit( + liveTrustProviderList.value.firstOrNull { it.service == ProviderTypes.followerCount } + ) + }.flowOn(Dispatchers.IO) + .stateIn( + scope, + SharingStarted.Eagerly, + null, + ) + init { settings.backupTrustProviderList?.let { event -> Log.d("AccountRegisterObservers", "Loading saved ephemeral chat list") diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceProviderTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceProviderTag.kt index f83bdec73a..b177660bef 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceProviderTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceProviderTag.kt @@ -61,28 +61,3 @@ data class ServiceProviderTag( fun assemble(id: ServiceProviderTag) = arrayOf(id.service, id.pubkey, id.relayUrl) } } - -data class ServiceType( - val kind: Int, - val type: String, -) { - fun toValue() = assemble(kind, type) - - companion object { - fun assemble( - kind: Int, - type: String, - ) = "$kind:$type" - - fun parse(serviceType: String): ServiceType? { - val (kindStr, type) = serviceType.split(":", limit = 2) - val kind = kindStr.toIntOrNull() ?: return null - return ServiceType(kind, type) - } - - fun isOfKind( - serviceType: String, - kind: String, - ) = serviceType.startsWith(kind) && serviceType[kind.length] == ':' - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceType.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceType.kt new file mode 100644 index 0000000000..2fe121b536 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/trustedAssertions/list/tags/ServiceType.kt @@ -0,0 +1,67 @@ +/** + * 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.quartz.experimental.trustedAssertions.list.tags + +data class ServiceType( + val kind: Int, + val type: String, +) { + fun toValue() = assemble(kind, type) + + companion object { + fun assemble( + kind: Int, + type: String, + ) = "$kind:$type" + + fun parse(serviceType: String): ServiceType? { + val (kindStr, type) = serviceType.split(":", limit = 2) + val kind = kindStr.toIntOrNull() ?: return null + return ServiceType(kind, type) + } + + fun isOfKind( + serviceType: String, + kind: String, + ) = serviceType.startsWith(kind) && serviceType[kind.length] == ':' + } +} + +object ProviderTypes { + val rank = ServiceType(30382, "rank") + val followerCount = ServiceType(30382, "followers") + + val firstPost = ServiceType(30382, "first_created_at") + val postCount = ServiceType(30382, "post_cnt") + val replyCount = ServiceType(30382, "reply_cnt") + val reactionsCount = ServiceType(30382, "reactions_cnt") + val zapReceivedAmount = ServiceType(30382, "zap_amt_recd") + val zapSentAmount = ServiceType(30382, "zap_amt_sent") + val zapReceivedCount = ServiceType(30382, "zap_cnt_recd") + val zapSentCount = ServiceType(30382, "zap_cnt_sent") + val averageZapAmountReceivedPerDay = ServiceType(30382, "zap_avg_amt_day_recd") + val averageZapAmountSentPerDay = ServiceType(30382, "zap_avg_amt_day_sent") + val reportsReceivedCount = ServiceType(30382, "reports_cnt_recd") + val reportsSentCount = ServiceType(30382, "reports_cnt_sent") + val topics = ServiceType(30382, "t") + val activeFrom = ServiceType(30382, "active_hours_start") + val activeTo = ServiceType(30382, "active_hours_end") +}