Final touches on the Attestation cards
This commit is contained in:
@@ -784,11 +784,11 @@ private fun RenderNoteRow(
|
||||
}
|
||||
|
||||
is AttestorRecommendationEvent -> {
|
||||
RenderAttestorRecommendation(baseNote, backgroundColor, accountViewModel, nav)
|
||||
RenderAttestorRecommendation(baseNote, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is AttestorProficiencyEvent -> {
|
||||
RenderAttestorProficiency(baseNote, backgroundColor, accountViewModel, nav)
|
||||
RenderAttestorProficiency(baseNote, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is AudioTrackEvent -> {
|
||||
|
||||
@@ -46,6 +46,8 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -53,13 +55,28 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.KindChip
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.AttestationStatus
|
||||
@@ -71,16 +88,75 @@ import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RenderAttestationPreview() {
|
||||
val event =
|
||||
AttestationEvent(
|
||||
id = "f8e05e4fa964d9dfbeb339ae0450d0b3424aaf8f6083d95f38c780335c3dbd56",
|
||||
pubKey = "c4f5e7a75a8ce3683d529cff06368439c529e5243c6b125ba68789198856cac7",
|
||||
createdAt = 1773941524,
|
||||
content = "This is Frank's new npub.",
|
||||
sig = "61dde5dc5738bfa637aa04451eec63d45f649902a0772abbaf55711aad5b7ce376bc7712c937f9ffc504655c4fd7e39f78139dc3f1a90953d150b43f3e2428fb",
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("d", "af5aa898:fe108febb997:1773941524"),
|
||||
arrayOf("e", "fe108febb99796c4091775e00aa1fc3ffc489ad22fdf1f8c559b2472815c09c7"),
|
||||
arrayOf("s", "verified"),
|
||||
arrayOf("v", "valid"),
|
||||
arrayOf("client", "attestr.xyz"),
|
||||
),
|
||||
)
|
||||
|
||||
LocalCache.justConsume(event, null, true)
|
||||
val note = LocalCache.getOrCreateNote(event.id)
|
||||
|
||||
ThemeComparisonColumn(
|
||||
toPreview = {
|
||||
RenderAttestation(
|
||||
baseNote = note,
|
||||
quotesLeft = 3,
|
||||
backgroundColor = remember { mutableStateOf(Color.Transparent) },
|
||||
accountViewModel = mockAccountViewModel(),
|
||||
nav = EmptyNav(),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderAttestation(
|
||||
note: Note,
|
||||
baseNote: Note,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noteEvent = note.event as? AttestationEvent ?: return
|
||||
val noteState by baseNote
|
||||
.flow()
|
||||
.metadata.stateFlow
|
||||
.collectAsStateWithLifecycle()
|
||||
val noteEvent = noteState.note.event as? AttestationEvent ?: return
|
||||
|
||||
RenderAttestation(
|
||||
baseNote,
|
||||
noteEvent,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderAttestation(
|
||||
note: Note,
|
||||
noteEvent: AttestationEvent,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val validity = remember(noteEvent) { noteEvent.validity() }
|
||||
val status = remember(noteEvent) { noteEvent.status() }
|
||||
val validFrom = remember(noteEvent) { noteEvent.validFrom() }
|
||||
@@ -91,6 +167,10 @@ fun RenderAttestation(
|
||||
val statusIcon = remember(status, validity) { attestationIcon(status, validity) }
|
||||
val statusLabel = attestationStatusLabel(status, validity)
|
||||
|
||||
val aboutAddress = remember(noteEvent) { noteEvent.assertionAddress() }
|
||||
val aboutEvent = remember(noteEvent) { noteEvent.assertionEventId() }
|
||||
val aboutPubkey = remember(noteEvent) { noteEvent.assertionPubkey() }
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
@@ -119,7 +199,7 @@ fun RenderAttestation(
|
||||
}
|
||||
|
||||
if (validFrom != null || validTo != null) {
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
validFrom?.let {
|
||||
Text(
|
||||
@@ -138,24 +218,11 @@ fun RenderAttestation(
|
||||
}
|
||||
}
|
||||
|
||||
content?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (quotesLeft > 0) {
|
||||
note.replyTo?.firstOrNull()?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringRes(R.string.attestation_attests_to),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
if (aboutAddress != null) {
|
||||
LoadAddressableNote(aboutAddress, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
NoteCompose(
|
||||
baseNote = it,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier,
|
||||
@@ -169,6 +236,49 @@ fun RenderAttestation(
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (aboutEvent != null) {
|
||||
LoadNote(aboutEvent, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
NoteCompose(
|
||||
baseNote = it,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier,
|
||||
isQuotedNote = true,
|
||||
unPackReply = ReplyRenderType.NONE,
|
||||
makeItShort = true,
|
||||
quotesLeft = quotesLeft - 1,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (aboutPubkey != null) {
|
||||
LoadUser(aboutPubkey, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
UserCompose(it, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content?.let {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
TranslatableRichTextViewer(
|
||||
content = it,
|
||||
canPreview = true,
|
||||
quotesLeft = quotesLeft,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList },
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -179,9 +289,18 @@ fun RenderAttestationRequest(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noteEvent = note.event as? AttestationRequestEvent ?: return
|
||||
val noteState by note
|
||||
.flow()
|
||||
.metadata.stateFlow
|
||||
.collectAsStateWithLifecycle()
|
||||
val noteEvent = noteState.note.event as? AttestationRequestEvent ?: return
|
||||
|
||||
val content = remember(noteEvent) { noteEvent.content.ifBlank { null } }
|
||||
|
||||
val aboutAddress = remember(noteEvent) { noteEvent.assertionAddress() }
|
||||
val aboutEvent = remember(noteEvent) { noteEvent.assertionEventId() }
|
||||
val aboutPubkey = remember(noteEvent) { noteEvent.assertionPubkey() }
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
@@ -213,18 +332,32 @@ fun RenderAttestationRequest(
|
||||
}
|
||||
|
||||
content?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
TranslatableRichTextViewer(
|
||||
content = it,
|
||||
canPreview = true,
|
||||
quotesLeft = quotesLeft,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList },
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (quotesLeft > 0) {
|
||||
note.replyTo?.firstOrNull()?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
if (aboutAddress != null) {
|
||||
LoadAddressableNote(aboutAddress, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
Text(
|
||||
text = stringRes(R.string.attestation_requests_attestation_to),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
NoteCompose(
|
||||
baseNote = it,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier,
|
||||
@@ -238,19 +371,62 @@ fun RenderAttestationRequest(
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (aboutEvent != null) {
|
||||
LoadNote(aboutEvent, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
Text(
|
||||
text = stringRes(R.string.attestation_requests_attestation_to),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
NoteCompose(
|
||||
baseNote = it,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier,
|
||||
isQuotedNote = true,
|
||||
unPackReply = ReplyRenderType.NONE,
|
||||
makeItShort = true,
|
||||
quotesLeft = quotesLeft - 1,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (aboutPubkey != null) {
|
||||
LoadUser(aboutPubkey, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
Text(
|
||||
text = stringRes(R.string.attestation_requests_attestation_to),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
UserCompose(it, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun RenderAttestorRecommendation(
|
||||
note: Note,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noteEvent = note.event as? AttestorRecommendationEvent ?: return
|
||||
val noteState by note
|
||||
.flow()
|
||||
.metadata.stateFlow
|
||||
.collectAsStateWithLifecycle()
|
||||
val noteEvent = noteState.note.event as? AttestorRecommendationEvent ?: return
|
||||
|
||||
val kinds = remember(noteEvent) { noteEvent.kinds() }
|
||||
val description = remember(noteEvent) { noteEvent.description() }
|
||||
val aboutPubKey = remember(noteEvent) { noteEvent.dTag() }
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
@@ -282,25 +458,45 @@ fun RenderAttestorRecommendation(
|
||||
)
|
||||
}
|
||||
|
||||
LoadUser(aboutPubKey, accountViewModel) {
|
||||
if (it != null) {
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
UserCompose(it, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
|
||||
if (kinds.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text =
|
||||
stringRes(
|
||||
R.string.attestor_recommendation_for_kinds,
|
||||
kinds.joinToString(", "),
|
||||
),
|
||||
text = stringRes(R.string.attestor_recommendation_for_kinds),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
// Kinds
|
||||
kinds.forEach { kind ->
|
||||
KindChip(kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
description?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
Spacer(modifier = DoubleVertSpacer)
|
||||
TranslatableRichTextViewer(
|
||||
content = it,
|
||||
canPreview = true,
|
||||
quotesLeft = quotesLeft,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList },
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -310,11 +506,17 @@ fun RenderAttestorRecommendation(
|
||||
@Composable
|
||||
fun RenderAttestorProficiency(
|
||||
note: Note,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noteEvent = note.event as? AttestorProficiencyEvent ?: return
|
||||
val noteState by note
|
||||
.flow()
|
||||
.metadata.stateFlow
|
||||
.collectAsStateWithLifecycle()
|
||||
val noteEvent = noteState.note.event as? AttestorProficiencyEvent ?: return
|
||||
|
||||
val kinds = remember(noteEvent) { noteEvent.kinds() }
|
||||
val description = remember(noteEvent) { noteEvent.description() }
|
||||
|
||||
@@ -368,10 +570,17 @@ fun RenderAttestorProficiency(
|
||||
|
||||
description?.let {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
TranslatableRichTextViewer(
|
||||
content = it,
|
||||
canPreview = true,
|
||||
quotesLeft = quotesLeft,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList },
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -669,7 +669,7 @@ val zaps = setOf(9734, 9735, 9041, 17375, 23194, 23195)
|
||||
val reports = setOf(ReportEvent.KIND, MuteListEvent.KIND, DeletionEvent.KIND, RequestToVanishEvent.KIND)
|
||||
|
||||
@Composable
|
||||
private fun KindChip(kind: Int) {
|
||||
fun KindChip(kind: Int) {
|
||||
val nameResId = kindDisplayName(kind)
|
||||
val name = if (nameResId != -1) stringResource(nameResId) else "k$kind"
|
||||
val (bg, fg) =
|
||||
|
||||
+2
-2
@@ -633,9 +633,9 @@ private fun FullBleedNoteCompose(
|
||||
} else if (noteEvent is AttestationRequestEvent) {
|
||||
RenderAttestationRequest(baseNote, 3, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is AttestorRecommendationEvent) {
|
||||
RenderAttestorRecommendation(baseNote, backgroundColor, accountViewModel, nav)
|
||||
RenderAttestorRecommendation(baseNote, 3, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is AttestorProficiencyEvent) {
|
||||
RenderAttestorProficiency(baseNote, backgroundColor, accountViewModel, nav)
|
||||
RenderAttestorProficiency(baseNote, 3, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is AdvertisedRelayListEvent) {
|
||||
DisplayNIP65RelayList(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is LnZapEvent) {
|
||||
|
||||
@@ -1907,8 +1907,9 @@
|
||||
<string name="attestation_request">Attestation Request</string>
|
||||
<string name="attestation_request_description">Requesting attestation for an event</string>
|
||||
<string name="attestor_recommendation">Attestor Recommendation</string>
|
||||
<string name="attestor_recommendation_for_kinds">Recommended for kinds: %1$s</string>
|
||||
<string name="attestor_recommendation_for_kinds">Recommended for kinds: </string>
|
||||
<string name="attestor_proficiency">Attestor Proficiency</string>
|
||||
<string name="attestor_proficiency_for_kinds">Proficient in verifying kinds: %1$s</string>
|
||||
<string name="attestation_attests_to">Attests to</string>
|
||||
<string name="attestation_requests_attestation_to">Requests attestation to</string>
|
||||
</resources>
|
||||
|
||||
+97
-3
@@ -23,13 +23,26 @@ package com.vitorpamplona.quartz.experimental.attestations.attestation
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.AttestationStatus
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Validity
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.AttestationRequestEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
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.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
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.utils.TimeUtils
|
||||
import kotlinx.serialization.json.JsonNull.content
|
||||
|
||||
@Immutable
|
||||
class AttestationEvent(
|
||||
@@ -39,7 +52,22 @@ class AttestationEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun eventHints(): List<EventIdHint> = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds(): List<HexKey> = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints(): List<AddressHint> = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds(): List<String> = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun validity() = tags.validity()
|
||||
|
||||
fun status() = tags.status()
|
||||
@@ -50,25 +78,91 @@ class AttestationEvent(
|
||||
|
||||
fun request() = tags.request()
|
||||
|
||||
fun requestId() = tags.requestId()
|
||||
|
||||
fun requestAddress() = tags.requestAddress()
|
||||
|
||||
fun isRevoked() = status() == AttestationStatus.REVOKED
|
||||
|
||||
fun assertionAddrId() = tags.firstNotNullOfOrNull(ATag::parseAddressId)
|
||||
|
||||
fun assertionAddress() = tags.firstNotNullOfOrNull(ATag::parseAddress)
|
||||
|
||||
fun assertionATag() = tags.firstNotNullOfOrNull(ATag::parse)
|
||||
|
||||
fun assertionEventId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun assertionETag() = tags.firstNotNullOfOrNull(ETag::parse)
|
||||
|
||||
fun assertionPubkey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun assertionPTag() = tags.firstNotNullOfOrNull(PTag::parse)
|
||||
|
||||
companion object {
|
||||
const val KIND = 31871
|
||||
const val ALT_DESCRIPTION = "Attestation"
|
||||
|
||||
fun build(
|
||||
fun buildEvent(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<Event>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: String? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
about(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
validTo?.let { validTo(it) }
|
||||
requestAddress?.let { request(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildReplaceable(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseReplaceableEvent>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutReplaceable(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
validTo?.let { validTo(it) }
|
||||
requestAddress?.let { request(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildAddress(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseAddressableEvent>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutAddressable(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
|
||||
+14
-1
@@ -27,7 +27,14 @@ import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Valid
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.ValidToTag
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Validity
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.ValidityTag
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.AttestationRequestEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.validity(validity: Validity) = addUnique(ValidityTag.assemble(validity))
|
||||
|
||||
@@ -37,4 +44,10 @@ fun TagArrayBuilder<AttestationEvent>.validFrom(timestamp: Long) = addUnique(Val
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.validTo(timestamp: Long) = addUnique(ValidToTag.assemble(timestamp))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.request(requestAddress: String) = addUnique(RequestTag.assemble(requestAddress))
|
||||
fun TagArrayBuilder<AttestationEvent>.request(request: EventHintBundle<AttestationRequestEvent>) = addUnique(RequestTag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.aboutAddressable(request: EventHintBundle<BaseAddressableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.aboutReplaceable(request: EventHintBundle<BaseReplaceableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.about(request: EventHintBundle<Event>) = addUnique(ETag.assemble(request.event.id, request.relay, request.event.pubKey))
|
||||
|
||||
+4
@@ -36,3 +36,7 @@ fun TagArray.validFrom() = firstNotNullOfOrNull(ValidFromTag::parse)
|
||||
fun TagArray.validTo() = firstNotNullOfOrNull(ValidToTag::parse)
|
||||
|
||||
fun TagArray.request() = firstNotNullOfOrNull(RequestTag::parse)
|
||||
|
||||
fun TagArray.requestId() = firstNotNullOfOrNull(RequestTag::parseAddressId)
|
||||
|
||||
fun TagArray.requestAddress() = firstNotNullOfOrNull(RequestTag::parseAddress)
|
||||
|
||||
+90
-4
@@ -20,22 +20,108 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.experimental.attestations.attestation.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip72ModCommunities.approval.tags.ApprovedAddressTag
|
||||
import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class RequestTag {
|
||||
class RequestTag(
|
||||
val address: Address,
|
||||
val relayHint: NormalizedRelayUrl? = null,
|
||||
) {
|
||||
fun toTag() = Address.assemble(address.kind, address.pubKeyHex, address.dTag)
|
||||
|
||||
fun toTagArray() = assemble(address, relayHint)
|
||||
|
||||
fun toTagIdOnly() = assemble(address, null)
|
||||
|
||||
companion object {
|
||||
const val TAG_NAME = "request"
|
||||
|
||||
fun isTag(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && !Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)
|
||||
|
||||
fun parse(tag: Array<String>): String? {
|
||||
fun isTagged(
|
||||
tag: Array<String>,
|
||||
addressId: String,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId
|
||||
|
||||
fun isTagged(
|
||||
tag: Array<String>,
|
||||
address: ApprovedAddressTag,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag()
|
||||
|
||||
fun isIn(
|
||||
tag: Array<String>,
|
||||
addressIds: Set<String>,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds
|
||||
|
||||
fun parse(tag: Array<String>): ApprovedAddressTag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
|
||||
val address = Address.parse(tag[1]) ?: return null
|
||||
val relayHint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||
return ApprovedAddressTag(address, relayHint)
|
||||
}
|
||||
|
||||
fun parseValidAddress(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
return Address.parse(tag[1])?.toValue()
|
||||
}
|
||||
|
||||
fun parseAddress(tag: Array<String>): Address? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
val address = Address.parse(tag[1]) ?: return null
|
||||
ensure(address.kind != CommunityDefinitionEvent.KIND) { return null }
|
||||
return address
|
||||
}
|
||||
|
||||
fun parseAddressId(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
fun assemble(requestAddress: String) = arrayOf(TAG_NAME, requestAddress)
|
||||
fun parseAsHint(tag: Array<String>): AddressHint? {
|
||||
ensure(tag.has(2)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
ensure(tag[1].contains(':')) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
ensure(relayHint != null) { return null }
|
||||
|
||||
return AddressHint(tag[1], relayHint)
|
||||
}
|
||||
|
||||
fun assemble(
|
||||
aTagId: HexKey,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url)
|
||||
|
||||
fun assemble(
|
||||
address: Address,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url)
|
||||
|
||||
fun assemble(
|
||||
kind: Int,
|
||||
pubKey: String,
|
||||
dTag: String,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = assemble(Address.assemble(kind, pubKey, dTag), relay)
|
||||
}
|
||||
}
|
||||
|
||||
+81
-2
@@ -21,13 +21,27 @@
|
||||
package com.vitorpamplona.quartz.experimental.attestations.request
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.attestorPubKeys
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.cashuToken
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
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.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
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.utils.TimeUtils
|
||||
import kotlin.let
|
||||
|
||||
@Immutable
|
||||
class AttestationRequestEvent(
|
||||
@@ -37,15 +51,45 @@ class AttestationRequestEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun eventHints(): List<EventIdHint> = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds(): List<HexKey> = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints(): List<AddressHint> = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds(): List<String> = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun cashuToken() = tags.cashuToken()
|
||||
|
||||
fun assertionAddrId() = tags.firstNotNullOfOrNull(ATag::parseAddressId)
|
||||
|
||||
fun assertionAddress() = tags.firstNotNullOfOrNull(ATag::parseAddress)
|
||||
|
||||
fun assertionATag() = tags.firstNotNullOfOrNull(ATag::parse)
|
||||
|
||||
fun assertionEventId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun assertionETag() = tags.firstNotNullOfOrNull(ETag::parse)
|
||||
|
||||
fun assertionPubkey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun assertionPTag() = tags.firstNotNullOfOrNull(PTag::parse)
|
||||
|
||||
companion object {
|
||||
const val KIND = 31872
|
||||
const val ALT_DESCRIPTION = "Attestation Request"
|
||||
|
||||
fun build(
|
||||
fun buildEvent(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<Event>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
@@ -54,6 +98,41 @@ class AttestationRequestEvent(
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
about(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildReplaceable(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseReplaceableEvent>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationRequestEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutReplaceable(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildAddress(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseAddressableEvent>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationRequestEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutAddressable(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
|
||||
+12
@@ -21,10 +21,22 @@
|
||||
package com.vitorpamplona.quartz.experimental.attestations.request
|
||||
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.tags.CashuTokenTag
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.attestorPubKeys(pubKeys: List<HexKey>) = addAll(pubKeys.map { PTag.assemble(it, null) })
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.cashuToken(token: String) = addUnique(CashuTokenTag.assemble(token))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.aboutAddressable(request: EventHintBundle<BaseAddressableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.aboutReplaceable(request: EventHintBundle<BaseReplaceableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.about(request: EventHintBundle<Event>) = addUnique(ETag.assemble(request.event.id, request.relay, request.event.pubKey))
|
||||
|
||||
+7
-1
@@ -24,6 +24,7 @@ import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
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.aTag.aTag
|
||||
@@ -47,7 +48,12 @@ class CalendarRSVPEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
PubKeyHintProvider {
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun status() = tags.firstNotNullOfOrNull(RSVPStatusTag.Companion::parse)
|
||||
|
||||
fun statusValue() = tags.firstNotNullOfOrNull(RSVPStatusTag.Companion::parseValue)
|
||||
|
||||
Reference in New Issue
Block a user