Merge branch 'main' into l10n_crowdin_translations
This commit is contained in:
@@ -168,9 +168,10 @@ import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
@@ -843,7 +844,12 @@ object LocalCache : ILocalCache, ICacheProvider {
|
||||
event.taggedAddresses().map { getOrCreateAddressableNote(it) }
|
||||
}
|
||||
|
||||
is BadgeProfilesEvent -> {
|
||||
is AcceptedBadgeSetEvent -> {
|
||||
event.badgeAwardEvents().mapNotNull { checkGetOrCreateNote(it) } +
|
||||
event.badgeAwardDefinitions().map { getOrCreateAddressableNote(it) }
|
||||
}
|
||||
|
||||
is ProfileBadgesEvent -> {
|
||||
event.badgeAwardEvents().mapNotNull { checkGetOrCreateNote(it) } +
|
||||
event.badgeAwardDefinitions().map { getOrCreateAddressableNote(it) }
|
||||
}
|
||||
@@ -2539,6 +2545,7 @@ object LocalCache : ILocalCache, ICacheProvider {
|
||||
): Boolean =
|
||||
try {
|
||||
when (event) {
|
||||
is AcceptedBadgeSetEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is AdvertisedRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is AppDefinitionEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is AppRecommendationEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
@@ -2551,7 +2558,6 @@ object LocalCache : ILocalCache, ICacheProvider {
|
||||
is AudioTrackEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is BadgeAwardEvent -> consumeRegularEvent(event, relay, wasVerified)
|
||||
is BadgeDefinitionEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is BadgeProfilesEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is BlockedRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is BlossomServersEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is BroadcastRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
@@ -2635,6 +2641,7 @@ object LocalCache : ILocalCache, ICacheProvider {
|
||||
is PictureEvent -> consumeRegularEvent(event, relay, wasVerified)
|
||||
is PrivateDmEvent -> consumeRegularEvent(event, relay, wasVerified)
|
||||
is PrivateOutboxRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is ProfileBadgesEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is ProxyRelayListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is PinListEvent -> consumeBaseReplaceable(event, relay, wasVerified)
|
||||
is PublicMessageEvent -> consumeRegularEvent(event, relay, wasVerified)
|
||||
|
||||
+4
-2
@@ -30,14 +30,16 @@ import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEve
|
||||
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
|
||||
val FollowAndMutesFromKeyKinds =
|
||||
listOf(
|
||||
PeopleListEvent.KIND,
|
||||
FollowListEvent.KIND,
|
||||
MuteListEvent.KIND,
|
||||
BadgeProfilesEvent.KIND,
|
||||
AcceptedBadgeSetEvent.KIND,
|
||||
ProfileBadgesEvent.KIND,
|
||||
EmojiPackSelectionEvent.KIND,
|
||||
EphemeralChatListEvent.KIND,
|
||||
ChannelListEvent.KIND,
|
||||
|
||||
+4
-2
@@ -26,7 +26,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||
|
||||
val UserProfileMetadataKinds =
|
||||
@@ -34,7 +35,8 @@ val UserProfileMetadataKinds =
|
||||
MetadataEvent.KIND,
|
||||
AdvertisedRelayListEvent.KIND,
|
||||
ContactListEvent.KIND,
|
||||
BadgeProfilesEvent.KIND,
|
||||
AcceptedBadgeSetEvent.KIND,
|
||||
ProfileBadgesEvent.KIND,
|
||||
)
|
||||
|
||||
fun filterUserProfileMetadata(
|
||||
|
||||
+41
-14
@@ -32,13 +32,14 @@ import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMapNotNull
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
@@ -49,11 +50,18 @@ import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.BadgePictureModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
@Composable
|
||||
fun DisplayBadges(
|
||||
@@ -61,25 +69,44 @@ fun DisplayBadges(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
LoadAddressableNote(
|
||||
BadgeProfilesEvent.createAddress(baseUser.pubkeyHex),
|
||||
accountViewModel,
|
||||
) { note ->
|
||||
if (note != null) {
|
||||
WatchAndRenderBadgeList(note, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
val oldDesign = AcceptedBadgeSetEvent.createAddress(baseUser.pubkeyHex)
|
||||
val newDesign = ProfileBadgesEvent.createAddress(baseUser.pubkeyHex)
|
||||
|
||||
val oldNote = accountViewModel.getOrCreateAddressableNote(oldDesign)
|
||||
val newNote = accountViewModel.getOrCreateAddressableNote(newDesign)
|
||||
|
||||
WatchAndRenderBadgeList(oldNote, newNote, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchAndRenderBadgeList(
|
||||
note: AddressableNote,
|
||||
oldNote: AddressableNote,
|
||||
newNote: AddressableNote,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val badgeList by observeNoteEventAndMapNotNull(note, accountViewModel) { event: BadgeProfilesEvent ->
|
||||
event.badgeAwardEvents().toImmutableList()
|
||||
}
|
||||
// Subscribe in the relay for changes in this note.
|
||||
EventFinderFilterAssemblerSubscription(oldNote, accountViewModel)
|
||||
EventFinderFilterAssemblerSubscription(newNote, accountViewModel)
|
||||
|
||||
// Subscribe in the LocalCache for changes that arrive in the device
|
||||
val flow =
|
||||
remember(oldNote, newNote) {
|
||||
combine(
|
||||
oldNote.flow().metadata.stateFlow,
|
||||
newNote.flow().metadata.stateFlow,
|
||||
) { oldNote, newNote ->
|
||||
val oldProfileBadgeEvent = oldNote.note.event as? AcceptedBadgeSetEvent
|
||||
val newProfileBadgeEvent = newNote.note.event as? ProfileBadgesEvent
|
||||
|
||||
newProfileBadgeEvent?.badgeAwardEvents()?.toImmutableList()
|
||||
?: oldProfileBadgeEvent?.badgeAwardEvents()?.toImmutableList()
|
||||
}.distinctUntilChanged()
|
||||
.flowOn(Dispatchers.IO)
|
||||
}
|
||||
|
||||
// Subscribe in the LocalCache for changes that arrive in the device
|
||||
val badgeList by flow.collectAsStateWithLifecycle(persistentListOf())
|
||||
|
||||
badgeList?.let { list -> RenderBadgeList(list, accountViewModel, nav) }
|
||||
}
|
||||
|
||||
+4
-2
@@ -233,9 +233,10 @@ import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent
|
||||
@@ -552,6 +553,7 @@ fun RelayInformationBody(
|
||||
@Suppress("DEPRECATION")
|
||||
fun kindDisplayName(kind: Int): Int =
|
||||
when (kind) {
|
||||
AcceptedBadgeSetEvent.KIND -> R.string.kind_accepted_badge_set
|
||||
AdvertisedRelayListEvent.KIND -> R.string.kind_outbox_relays
|
||||
AppDefinitionEvent.KIND -> R.string.kind_apps
|
||||
AppRecommendationEvent.KIND -> R.string.kind_app_recommendations
|
||||
@@ -564,7 +566,6 @@ fun kindDisplayName(kind: Int): Int =
|
||||
AttestorProficiencyEvent.KIND -> R.string.attestor_proficiency
|
||||
BadgeAwardEvent.KIND -> R.string.kind_badge_awards
|
||||
BadgeDefinitionEvent.KIND -> R.string.kind_badge_definitions
|
||||
BadgeProfilesEvent.KIND -> R.string.kind_profile_badges
|
||||
BlockedRelayListEvent.KIND -> R.string.kind_blocked_relays
|
||||
BlossomServersEvent.KIND -> R.string.kind_blossom_servers
|
||||
BlossomAuthorizationEvent.KIND -> R.string.kind_blossom_auth
|
||||
@@ -651,6 +652,7 @@ fun kindDisplayName(kind: Int): Int =
|
||||
OtsEvent.KIND -> R.string.kind_ots
|
||||
PaymentTargetsEvent.KIND -> R.string.kind_pay_to
|
||||
PeopleListEvent.KIND -> R.string.kind_people_lists
|
||||
ProfileBadgesEvent.KIND -> R.string.kind_profile_badges
|
||||
PictureEvent.KIND -> R.string.kind_pictures
|
||||
PinListEvent.KIND -> R.string.kind_pins
|
||||
ZapPollEvent.KIND -> R.string.kind_zap_poll
|
||||
|
||||
@@ -1744,6 +1744,7 @@
|
||||
<string name="kind_audio_track">Audio Track</string>
|
||||
<string name="kind_badge_awards">Badge Awards</string>
|
||||
<string name="kind_badge_definitions">Badge Definitions</string>
|
||||
<string name="kind_accepted_badge_set">Accepted Badge Set</string>
|
||||
<string name="kind_profile_badges">Profile Badges</string>
|
||||
<string name="kind_blocked_relays">Blocked Relays</string>
|
||||
<string name="kind_blossom_servers">Blossom Servers</string>
|
||||
|
||||
+4
-4
@@ -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.quartz.nip58Badges.profiles
|
||||
package com.vitorpamplona.quartz.nip58Badges.accepted
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
@@ -34,11 +34,11 @@ import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.tags.AcceptedBadge
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class BadgeProfilesEvent(
|
||||
class AcceptedBadgeSetEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
@@ -79,7 +79,7 @@ class BadgeProfilesEvent(
|
||||
fun build(
|
||||
acceptedBadges: List<AcceptedBadge> = emptyList(),
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<BadgeProfilesEvent>.() -> Unit = {},
|
||||
initializer: TagArrayBuilder<AcceptedBadgeSetEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, "", createdAt) {
|
||||
dTag(STANDARD_D_TAG)
|
||||
alt(ALT_DESCRIPTION)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.nip58Badges.accepted
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
|
||||
fun TagArrayBuilder<AcceptedBadgeSetEvent>.acceptedBadges(badges: List<AcceptedBadge>) = addAll(AcceptedBadge.assemble(badges))
|
||||
+2
-2
@@ -18,12 +18,12 @@
|
||||
* 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.nip58Badges.profiles
|
||||
package com.vitorpamplona.quartz.nip58Badges.accepted
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.tags.AcceptedBadge
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
|
||||
fun TagArray.acceptedBadges() = AcceptedBadge.parseAll(this)
|
||||
|
||||
+1
-1
@@ -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.quartz.nip58Badges.profiles.tags
|
||||
package com.vitorpamplona.quartz.nip58Badges.accepted.tags
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.nip58Badges.profile
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class ProfileBadgesEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
override fun eventHints() = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds() = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints() = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds() = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
fun acceptedBadges() = tags.acceptedBadges()
|
||||
|
||||
fun badgeAwardEvents() = tags.badgeAwardEvents()
|
||||
|
||||
fun badgeAwardDefinitions() = tags.badgeAwardDefinitions()
|
||||
|
||||
companion object {
|
||||
const val KIND = 10008
|
||||
const val ALT_DESCRIPTION = "List of accepted badges by the author"
|
||||
|
||||
fun createAddress(pubKey: HexKey): Address = Address(KIND, pubKey, "")
|
||||
|
||||
fun createAddressTag(pubKey: HexKey): ATag = ATag(KIND, pubKey, "", null)
|
||||
|
||||
fun build(
|
||||
acceptedBadges: List<AcceptedBadge> = emptyList(),
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<ProfileBadgesEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, "", createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
if (acceptedBadges.isNotEmpty()) {
|
||||
acceptedBadges(acceptedBadges)
|
||||
}
|
||||
initializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -18,9 +18,9 @@
|
||||
* 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.nip58Badges.profiles
|
||||
package com.vitorpamplona.quartz.nip58Badges.profile
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.tags.AcceptedBadge
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
|
||||
fun TagArrayBuilder<BadgeProfilesEvent>.acceptedBadges(badges: List<AcceptedBadge>) = addAll(AcceptedBadge.assemble(badges))
|
||||
fun TagArrayBuilder<ProfileBadgesEvent>.acceptedBadges(badges: List<AcceptedBadge>) = addAll(AcceptedBadge.assemble(badges))
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.nip58Badges.profile
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.tags.AcceptedBadge
|
||||
|
||||
fun TagArray.acceptedBadges() = AcceptedBadge.parseAll(this)
|
||||
|
||||
fun TagArray.badgeAwardEvents() = taggedEvents()
|
||||
|
||||
fun TagArray.badgeAwardDefinitions() = taggedAddresses()
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.nip58Badges.profile.tags
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
|
||||
/**
|
||||
* Represents a paired `a` (badge definition) and `e` (badge award) tag
|
||||
* as specified in NIP-58 Profile Badges.
|
||||
*
|
||||
* Clients SHOULD ignore unpaired `a` or `e` tags.
|
||||
*/
|
||||
@Stable
|
||||
class AcceptedBadge(
|
||||
val badgeDefinition: ATag,
|
||||
val badgeAward: ETag,
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* Parses ordered consecutive pairs of `a` and `e` tags from a tag array.
|
||||
* Tags must appear as sequential pairs: `a`, `e`, `a`, `e`, ...
|
||||
* Unpaired tags are ignored per the spec.
|
||||
*/
|
||||
fun parseAll(tags: TagArray): List<AcceptedBadge> {
|
||||
val result = mutableListOf<AcceptedBadge>()
|
||||
var i = 0
|
||||
while (i < tags.size - 1) {
|
||||
val aTag = ATag.parse(tags[i])
|
||||
if (aTag != null) {
|
||||
val eTag = ETag.parse(tags[i + 1])
|
||||
if (eTag != null) {
|
||||
result.add(AcceptedBadge(aTag, eTag))
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun assemble(badges: List<AcceptedBadge>): List<Array<String>> =
|
||||
badges.flatMap { badge ->
|
||||
listOf(
|
||||
badge.badgeDefinition.toATagArray(),
|
||||
badge.badgeAward.toTagArray(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,9 +140,10 @@ import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profiles.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent
|
||||
@@ -268,6 +269,7 @@ class EventFactory {
|
||||
sig: HexKey,
|
||||
): T =
|
||||
when (kind) {
|
||||
AcceptedBadgeSetEvent.KIND -> AcceptedBadgeSetEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
AdvertisedRelayListEvent.KIND -> AdvertisedRelayListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
AppDefinitionEvent.KIND -> AppDefinitionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
AppRecommendationEvent.KIND -> AppRecommendationEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
@@ -281,7 +283,6 @@ class EventFactory {
|
||||
AudioTrackEvent.KIND -> AudioTrackEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BadgeAwardEvent.KIND -> BadgeAwardEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BadgeDefinitionEvent.KIND -> BadgeDefinitionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BadgeProfilesEvent.KIND -> BadgeProfilesEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BidEvent.KIND -> BidEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BidConfirmationEvent.KIND -> BidConfirmationEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
BlockedRelayListEvent.KIND -> BlockedRelayListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
@@ -439,6 +440,7 @@ class EventFactory {
|
||||
P2POrderEvent.KIND -> P2POrderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
PictureEvent.KIND -> PictureEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
PinListEvent.KIND -> PinListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
ProfileBadgesEvent.KIND -> ProfileBadgesEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
ZapPollEvent.KIND -> ZapPollEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
PollEvent.KIND -> PollEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
PollResponseEvent.KIND -> PollResponseEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
||||
Reference in New Issue
Block a user