Create nostr events from database data

This commit is contained in:
Kgothatso Ngako
2026-07-19 19:15:42 +02:00
parent ed70df2c11
commit 1b19c6a1be
26 changed files with 771 additions and 23 deletions

View File

@@ -4,9 +4,11 @@ import androidx.room3.Entity
import androidx.room3.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip31Alts.AltTag
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ArtifactEvent
import press.mantra.compose.nostr.nip30303.tags.ArtifactMetadataTag
import press.mantra.compose.nostr.nip30303.tags.DialectIdTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -19,10 +21,10 @@ data class MantraArtifact(
@PrimaryKey
val id: HexKey,
val publicKey: String,
val name: String,
val url: String, // Hash this to get the dTag...
val visibility: String, // public, private, permissioned (public, but only members can contribute)
val dialectId: String,
val copyrightOwner: String, // Put this in artifactContributor
val license: String,
// val artifactApprovalId: String,
@@ -47,12 +49,42 @@ data class MantraArtifact(
pubKey = publicKey,
createdAt = createdAt.epochSeconds,
tags = TagArrayBuilder<ArtifactEvent>()
.addUnique(
ArtifactMetadataTag.assemble(
url = url,
visibility = visibility,
license = license
)
)
.addUnique(
DialectIdTag.assemble(dialectId)
)
.addUnique(
AltTag.assemble(ArtifactEvent.ALT_DESCRIPTION)
)
.build(),
content = "",
content = name,
sig = signature
)
}
companion object {
fun fromArtifactEvent(artifactEvent: ArtifactEvent): MantraArtifact? {
return artifactEvent.artifactMetadata?.let { artifactMetadata ->
artifactEvent.dialectId()?.let { dialectId ->
MantraArtifact(
id = artifactEvent.id,
publicKey = artifactEvent.pubKey,
dialectId = dialectId,
createdAt = Instant.fromEpochSeconds(artifactEvent.createdAt),
url = artifactMetadata.url,
license = artifactMetadata.license,
visibility = artifactMetadata.visibility,
name = artifactEvent.content,
signature = artifactEvent.sig,
)
}
}
}
}
}

View File

@@ -5,10 +5,12 @@ import androidx.room3.ForeignKey
import androidx.room3.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip31Alts.AltTag
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ArtifactVersionEvent
import press.mantra.compose.nostr.nip30303.tags.ArtifactIdTag
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionMetadataTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -57,11 +59,31 @@ data class MantraArtifactVersion(
id = id,
pubKey = publicKey,
createdAt = createdAt.epochSeconds,
tags = TagArrayBuilder<ArtifactVersionEvent>().addUnique(
ArtifactIdTag.assemble(artifactId)
).build(),
content = "",
tags = TagArrayBuilder<ArtifactVersionEvent>()
.addUnique(
ArtifactIdTag.assemble(artifactId)
)
.addUnique(
AltTag.assemble(ArtifactVersionEvent.ALT_DESCRIPTION)
)
.build(),
content = versionLabel,
sig = signature
)
}
companion object {
fun fromArtifactVersionEvent(artifactVersionEvent: ArtifactVersionEvent): MantraArtifactVersion? {
return artifactVersionEvent.artifactId()?.let { artifactId ->
MantraArtifactVersion(
id = artifactVersionEvent.id,
publicKey = artifactVersionEvent.pubKey,
createdAt = Instant.fromEpochSeconds(artifactVersionEvent.createdAt),
artifactId = artifactId,
versionLabel = artifactVersionEvent.content,
signature = artifactVersionEvent.sig
)
}
}
}
}

View File

@@ -10,6 +10,9 @@ import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ArtifactVersionEvent
import press.mantra.compose.nostr.nip30303.ChapterEvent
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.ChapterMetadataTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.WordStatisticsTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -59,11 +62,52 @@ data class MantraChapter(
id = id,
pubKey = publicKey,
createdAt = createdAt.epochSeconds,
tags = TagArrayBuilder<ArtifactVersionEvent>().addUnique(
ArtifactVersionIdTag.assemble(artifactVersionId)
).build(),
tags = TagArrayBuilder<ArtifactVersionEvent>()
.addUnique(
ArtifactVersionIdTag.assemble(artifactVersionId)
)
.addUnique(
ChapterMetadataTag.assemble(
name = name,
originalText = originalText,
)
)
.addUnique(
IndexTag.assemble(
index
)
)
.addUnique(
WordStatisticsTag.assemble(wordCount, characterCount)
)
.build(),
content = "",
sig = signature
)
}
companion object {
fun fromChapterEvent(chapterEvent: ChapterEvent): MantraChapter? {
return chapterEvent.chapterMetadata?.let { chapterMetadata ->
chapterEvent.wordStatisticsTag?.let { wordStatisticsTag ->
chapterEvent.artifactVersionId()?.let { artifactId ->
chapterEvent.index()?.let { index ->
MantraChapter(
id = chapterEvent.id,
publicKey = chapterEvent.pubKey,
createdAt = Instant.fromEpochSeconds(chapterEvent.createdAt),
artifactVersionId = artifactId,
name = chapterMetadata.name,
originalText = chapterMetadata.originalText,
index = index,
wordCount = wordStatisticsTag.wordCount,
characterCount = wordStatisticsTag.characterCount,
signature = chapterEvent.sig
)
}
}
}
}
}
}
}

View File

@@ -9,6 +9,8 @@ import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ChunkEvent
import press.mantra.compose.nostr.nip30303.tags.ChapterIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.WordStatisticsTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -56,11 +58,44 @@ data class MantraChunk(
id = id,
pubKey = publicKey,
createdAt = createdAt.epochSeconds,
tags = TagArrayBuilder<ChunkEvent>().addUnique(
ChapterIdTag.assemble(chapterId)
).build(),
content = "",
tags = TagArrayBuilder<ChunkEvent>()
.addUnique(
ChapterIdTag.assemble(chapterId)
)
.addUnique(
IndexTag.assemble(
index
)
)
.addUnique(
WordStatisticsTag.assemble(wordCount, characterCount)
)
.build(),
content = text,
sig = signature
)
}
companion object {
fun fromChunkEvent(chunkEvent: ChunkEvent): MantraChunk? {
return chunkEvent.wordStatisticsTag?.let { wordStatisticsTag ->
chunkEvent.index()?.let { index ->
chunkEvent.chapterId()?.let { chapterId ->
MantraChunk(
id = chunkEvent.id,
publicKey = chunkEvent.pubKey,
createdAt = Instant.fromEpochSeconds(chunkEvent.createdAt),
index = index,
wordCount = wordStatisticsTag.wordCount,
characterCount = wordStatisticsTag.characterCount,
chapterId = chapterId,
text = chunkEvent.content,
signature = chunkEvent.sig
)
}
}
}
}
}
}

View File

@@ -3,9 +3,13 @@ package press.mantra.compose.database.model
import androidx.room3.Entity
import androidx.room3.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ChunkEvent
import press.mantra.compose.nostr.nip30303.DialectEvent
import press.mantra.compose.nostr.nip30303.tags.ChapterIdTag
import press.mantra.compose.nostr.nip30303.tags.DialectMetadataTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -39,10 +43,38 @@ data class MantraDialect(
id = id,
pubKey = publicKey,
createdAt = createdAt.epochSeconds,
tags = emptyArray(),
content = "",
tags = TagArrayBuilder<ChunkEvent>()
.addUnique(
DialectMetadataTag.assemble(
name = name,
country = country,
language = language
)
)
.build(),
content = language, // TODO: Consider using the isoCode... as content?
sig = signature
)
}
companion object {
fun fromDialectEvent(dialectEvent: DialectEvent): MantraDialect? {
return dialectEvent.name()?.let { name ->
dialectEvent.language()?.let { language ->
dialectEvent.country()?.let { country ->
MantraDialect(
id = dialectEvent.id,
publicKey = dialectEvent.pubKey,
createdAt = Instant.fromEpochSeconds(dialectEvent.createdAt),
name = name,
language = language,
country = country,
signature = dialectEvent.sig
)
}
}
}
}
}
}

View File

@@ -5,6 +5,7 @@ import androidx.room3.ForeignKey
import androidx.room3.PrimaryKey
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.utils.ensure
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.TranslationEvent
@@ -66,8 +67,29 @@ data class MantraTranslation(
TranslationChunkIdTag.assemble(translationChunkId)
)
.build(),
content = "",
content = text,
sig = signature
)
}
companion object {
fun fromTranslationEvent(translationEvent: TranslationEvent): MantraTranslation? {
ensure(translationEvent.translationChunkId() != null) { return null}
ensure(translationEvent.translationArtifactVersionId() != null) { return null}
return translationEvent.translationChunkId()?.let { translationChunkId ->
translationEvent.translationArtifactVersionId()?.let { translationArtifactVersionId ->
MantraTranslation(
id = translationEvent.id,
publicKey = translationEvent.pubKey,
createdAt = Instant.fromEpochSeconds(translationEvent.createdAt),
text = translationEvent.content,
translationChunkId = translationChunkId,
translationArtifactVersionId = translationArtifactVersionId,
signature = translationEvent.sig
)
}
}
}
}
}

View File

@@ -11,6 +11,7 @@ import press.mantra.compose.nostr.nip30303.ArtifactVersionEvent
import press.mantra.compose.nostr.nip30303.TranslationArtifactVersionEvent
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.DialectIdTag
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionMetadataTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -35,6 +36,7 @@ data class MantraTranslationArtifactVersion(
val dialectId: HexKey,
val name: String,
val visibility: String,
val license: String,
/**
* Signature will be an empty string if this is a rumor
@@ -64,10 +66,40 @@ data class MantraTranslationArtifactVersion(
.addUnique(
DialectIdTag.assemble(dialectId)
)
.addUnique(
TranslationArtifactVersionMetadataTag.assemble(
name = name,
visibility = visibility,
license = license
)
)
.build(),
content = "",
sig = signature
)
}
companion object {
fun fromTranslationArtifactVersionEvent(translationArtifactVersionEvent: TranslationArtifactVersionEvent): MantraTranslationArtifactVersion? {
return translationArtifactVersionEvent.artifactVersionId()?.let { artifactVersionId ->
translationArtifactVersionEvent.dialectId()?.let { dialectId ->
translationArtifactVersionEvent.translationArtifactVersionMetadata?.let { translationArtifactVersionMetadata ->
MantraTranslationArtifactVersion(
id = translationArtifactVersionEvent.id,
publicKey = translationArtifactVersionEvent.pubKey,
createdAt = Instant.fromEpochSeconds(translationArtifactVersionEvent.createdAt),
artifactVersionId = artifactVersionId,
dialectId = dialectId,
name = translationArtifactVersionMetadata.name,
visibility = translationArtifactVersionMetadata.visibility,
license = translationArtifactVersionMetadata.license,
signature = translationArtifactVersionEvent.sig
)
}
}
}
}
}
}

View File

@@ -6,8 +6,10 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ChapterEvent
import press.mantra.compose.nostr.nip30303.TranslationChapterEvent
import press.mantra.compose.nostr.nip30303.tags.ChapterIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionIdTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -59,10 +61,33 @@ data class MantraTranslationChapter(
.addUnique(
ChapterIdTag.assemble(chapterId)
)
.addUnique(
IndexTag.assemble(index)
)
.build(),
content = "",
sig = signature
)
}
companion object {
fun fromTranslationChapterEvent(translationChapterEvent: TranslationChapterEvent): MantraTranslationChapter? {
return translationChapterEvent.chapterId()?.let { chapterId ->
translationChapterEvent.translationArtifactVersionId()?.let { translationArtifactVersionId ->
translationChapterEvent.index()?.let { index ->
MantraTranslationChapter(
id = translationChapterEvent.id,
publicKey = translationChapterEvent.pubKey,
createdAt = Instant.fromEpochSeconds(translationChapterEvent.createdAt),
chapterId = chapterId,
translationArtifactVersionId = translationArtifactVersionId,
index = index,
signature = translationChapterEvent.sig
)
}
}
}
}
}
}

View File

@@ -7,8 +7,10 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import press.mantra.compose.database.model.traits.OptionalNostrEventEntity
import press.mantra.compose.database.model.traits.TimestampedEntity
import press.mantra.compose.nostr.nip30303.ChunkEvent
import press.mantra.compose.nostr.nip30303.TranslationChunkEvent
import press.mantra.compose.nostr.nip30303.tags.ChunkIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.TranslationChapterIdTag
import kotlin.time.Clock
import kotlin.time.Instant
@@ -67,11 +69,35 @@ data class MantraTranslationChunk(
TranslationChapterIdTag.assemble(translationChapterId)
)
.addUnique(
ChunkIdTag.assemble(chunkId) // TODO: PublicKeyListTag
ChunkIdTag.assemble(chunkId)
)
.addUnique(
IndexTag.assemble(index)
)
.build(),
content = "",
content = text,
sig = signature
)
}
companion object {
fun fromTranslationChunkEvent(translationChunkEvent: TranslationChunkEvent): MantraTranslationChunk? {
return translationChunkEvent.translationChapterId()?.let { translationChapterId ->
translationChunkEvent.chunkId()?.let { chunkId ->
translationChunkEvent.index()?.let { index ->
MantraTranslationChunk(
id = translationChunkEvent.id,
publicKey = translationChunkEvent.pubKey,
createdAt = Instant.fromEpochSeconds(translationChunkEvent.createdAt),
translationChapterId = translationChapterId,
chunkId = chunkId,
index = index,
text = translationChunkEvent.content,
signature = translationChunkEvent.sig
)
}
}
}
}
}
}

View File

@@ -9,6 +9,8 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ArtifactMetadataTag
import press.mantra.compose.nostr.nip30303.tags.DialectIdTag
@Immutable
@@ -20,6 +22,14 @@ class ArtifactEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
val artifactMetadata = tags.firstNotNullOfOrNull(ArtifactMetadataTag::parse)
fun url() = artifactMetadata?.url
fun visibility() = artifactMetadata?.visibility
fun license() = artifactMetadata?.license
fun dialectIdReference() = tags.firstNotNullOfOrNull(DialectIdTag::parse)?.ref
fun dialectId() = dialectIdReference()?.eventId
companion object {
const val KIND = 30300

View File

@@ -9,6 +9,8 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ArtifactIdTag
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionMetadataTag
@Immutable
@@ -21,6 +23,11 @@ class ArtifactVersionEvent(
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun versionLabel() = tags.firstNotNullOfOrNull(ArtifactVersionMetadataTag::parse)?.versionLabel
fun artifactIdReference() = tags.firstNotNullOfOrNull(ArtifactIdTag::parse)?.ref
fun artifactId() = artifactIdReference()?.eventId
companion object {
const val KIND = 30301
const val ALT_DESCRIPTION = "ArtifactVersion"

View File

@@ -5,10 +5,12 @@ 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.signers.eventTemplate
import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.ChapterMetadataTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.WordStatisticsTag
@Immutable
@@ -20,6 +22,18 @@ class ChapterEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
val chapterMetadata = tags.firstNotNullOfOrNull(ChapterMetadataTag::parse)
val wordStatisticsTag = tags.firstNotNullOfOrNull(WordStatisticsTag::parse)
fun artifactVersionIdReference() = tags.firstNotNullOfOrNull(ArtifactVersionIdTag::parse)?.ref
fun artifactVersionId() = artifactVersionIdReference()?.eventId
fun name() = chapterMetadata?.name
fun originalText() = chapterMetadata?.originalText
fun index() = tags.firstNotNullOfOrNull(IndexTag::parse)?.index
fun wordCount() = wordStatisticsTag?.wordCount
fun characterCount() = wordStatisticsTag?.characterCount
companion object {
const val KIND = 30302

View File

@@ -9,6 +9,9 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ChapterIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.WordStatisticsTag
@Immutable
@@ -20,6 +23,14 @@ class ChunkEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
val wordStatisticsTag = tags.firstNotNullOfOrNull(WordStatisticsTag::parse)
fun index() = tags.firstNotNullOfOrNull(IndexTag::parse)?.index
fun wordCount() = wordStatisticsTag?.wordCount
fun characterCount() = wordStatisticsTag?.characterCount
fun chapterIdReference() = tags.firstNotNullOfOrNull(ChapterIdTag::parse)?.ref
fun chapterId() = chapterIdReference()?.eventId
companion object {
const val KIND = 30303

View File

@@ -9,6 +9,7 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.DialectMetadataTag
@Immutable
@@ -20,6 +21,11 @@ class DialectEvent(
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
val dialectMetadata = tags.firstNotNullOfOrNull(DialectMetadataTag::parse)
fun name() = dialectMetadata?.name
fun country() = dialectMetadata?.country
fun language() = dialectMetadata?.language
companion object {
const val KIND = 30304

View File

@@ -5,10 +5,11 @@ 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.signers.eventTemplate
import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.DialectIdTag
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionMetadataTag
@Immutable
@@ -21,6 +22,14 @@ class TranslationArtifactVersionEvent(
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
val translationArtifactVersionMetadata = tags.firstNotNullOfOrNull(TranslationArtifactVersionMetadataTag::parse)
fun artifactVersionIdReference() = tags.firstNotNullOfOrNull(ArtifactVersionIdTag::parse)?.ref
fun artifactVersionId() = artifactVersionIdReference()?.eventId
fun dialectIdReference() = tags.firstNotNullOfOrNull(DialectIdTag::parse)?.ref
fun dialectId() = dialectIdReference()?.eventId
companion object {
const val KIND = 30306
const val ALT_DESCRIPTION = "TranslationArtifactVersion"

View File

@@ -9,6 +9,9 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ChapterIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionIdTag
@Immutable
@@ -21,6 +24,14 @@ class TranslationChapterEvent(
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun translationArtifactVersionIdReference() = tags.firstNotNullOfOrNull(TranslationArtifactVersionIdTag::parse)?.ref
fun translationArtifactVersionId() = translationArtifactVersionIdReference()?.eventId
fun chapterIdReference() = tags.firstNotNullOfOrNull(ChapterIdTag::parse)?.ref
fun chapterId() = chapterIdReference()?.eventId
fun index() = tags.firstNotNullOfOrNull(IndexTag::parse)?.index
companion object {
const val KIND = 30308
const val ALT_DESCRIPTION = "TranslationChapter"

View File

@@ -9,6 +9,10 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.ChunkIdTag
import press.mantra.compose.nostr.nip30303.tags.IndexTag
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.TranslationChapterIdTag
@Immutable
@@ -21,6 +25,14 @@ class TranslationChunkEvent(
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun translationChapterIdReference() = tags.firstNotNullOfOrNull(TranslationChapterIdTag::parse)?.ref
fun translationChapterId() = translationChapterIdReference()?.eventId
fun index() = tags.firstNotNullOfOrNull(IndexTag::parse)?.index
fun chunkIdReference() = tags.firstNotNullOfOrNull(ChunkIdTag::parse)?.ref
fun chunkId() = chunkIdReference()?.eventId
companion object {
const val KIND = 30309
const val ALT_DESCRIPTION = "TranslationChunk"

View File

@@ -9,6 +9,8 @@ import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import press.mantra.compose.nostr.nip30303.tags.TranslationArtifactVersionIdTag
import press.mantra.compose.nostr.nip30303.tags.TranslationChunkIdTag
@Immutable
@@ -21,6 +23,12 @@ class TranslationEvent(
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
fun translationChunkIdReference() = tags.firstNotNullOfOrNull(TranslationChunkIdTag::parse)?.ref
fun translationChunkId() = translationChunkIdReference()?.eventId
fun translationArtifactVersionIdReference() = tags.firstNotNullOfOrNull(TranslationArtifactVersionIdTag::parse)?.ref
fun translationArtifactVersionId() = translationArtifactVersionIdReference()?.eventId
companion object {
const val KIND = 30311
const val ALT_DESCRIPTION = "Translation"

View File

@@ -0,0 +1,49 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class ArtifactMetadataTag(
val url: String,
val visibility: String,
val license: String,
) {
fun toTagArray() = assemble(
url = url,
visibility = visibility,
license = license
)
companion object {
const val TAG_NAME = "artifact"
fun parse(tag: Array<String>): ArtifactMetadataTag? {
ensure(tag.has(3)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return ArtifactMetadataTag(
url = tag[1],
visibility = tag[2],
license = tag[3],
)
}
fun assemble(
url: String,
visibility: String,
license: String,
): Array<String> = arrayOf(
TAG_NAME,
url,
visibility,
license
)
fun assemble(artifactMetadataTag: ArtifactMetadataTag) = assemble(
url = artifactMetadataTag.url,
visibility = artifactMetadataTag.visibility,
license = artifactMetadataTag.license
)
}
}

View File

@@ -0,0 +1,36 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class ArtifactVersionMetadataTag(
val versionLabel: String,
) {
fun toTagArray() = assemble(
versionLabel = versionLabel,
)
companion object {
const val TAG_NAME = "artifactVersion"
fun parse(tag: Array<String>): ArtifactVersionMetadataTag? {
ensure(tag.has(1)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return ArtifactVersionMetadataTag(
versionLabel = tag[1],
)
}
fun assemble(
versionLabel: String,
): Array<String> = arrayOf(
TAG_NAME,
versionLabel
)
fun assemble(artifactVersionMetadataTag: ArtifactVersionMetadataTag) = assemble(
versionLabel = artifactVersionMetadataTag.versionLabel,
)
}
}

View File

@@ -0,0 +1,42 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class ChapterMetadataTag(
val name: String,
val originalText: String,
) {
fun toTagArray() = assemble(
name = name,
originalText = originalText,
)
companion object {
const val TAG_NAME = "chapter"
fun parse(tag: Array<String>): ChapterMetadataTag? {
ensure(tag.has(2)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return ChapterMetadataTag(
name = tag[1],
originalText = tag[2],
)
}
fun assemble(
name: String,
originalText: String,
): Array<String> = arrayOf(
TAG_NAME,
name,
originalText,
)
fun assemble(chapterMetadataTag: ChapterMetadataTag) = assemble(
name = chapterMetadataTag.name,
originalText = chapterMetadataTag.originalText,
)
}
}

View File

@@ -0,0 +1,48 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class DialectMetadataTag(
val name: String,
val country: String,
val language: String,
) {
fun toTagArray() = assemble(
name = name,
country = country,
language = language
)
companion object {
const val TAG_NAME = "dialect"
fun parse(tag: Array<String>): DialectMetadataTag? {
ensure(tag.has(3)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return DialectMetadataTag(
name = tag[1],
country = tag[2],
language = tag[3],
)
}
fun assemble(
name: String,
country: String,
language: String,
): Array<String> = arrayOf(
TAG_NAME,
name,
country,
language
)
fun assemble(dialectMetadataTag: DialectMetadataTag) = assemble(
name = dialectMetadataTag.name,
country = dialectMetadataTag.country,
language = dialectMetadataTag.language
)
}
}

View File

@@ -0,0 +1,36 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class IndexTag(
val index: Int,
) {
fun toTagArray() = assemble(
index = index,
)
companion object {
const val TAG_NAME = "index"
fun parse(tag: Array<String>): IndexTag? {
ensure(tag.has(1)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
// TODO: Check that it is an int...
return IndexTag(
index = tag[1].toInt(),
)
}
fun assemble(
index: Int,
): Array<String> = arrayOf(
TAG_NAME,
index.toString()
)
fun assemble(indexTag: IndexTag) = assemble(
index = indexTag.index,
)
}
}

View File

@@ -0,0 +1,49 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class TranslationArtifactVersionMetadataTag(
val name: String,
val visibility: String,
val license: String,
) {
fun toTagArray() = assemble(
name = name,
visibility = visibility,
license = license
)
companion object {
const val TAG_NAME = "artifact"
fun parse(tag: Array<String>): TranslationArtifactVersionMetadataTag? {
ensure(tag.has(3)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return TranslationArtifactVersionMetadataTag(
name = tag[1],
visibility = tag[2],
license = tag[3],
)
}
fun assemble(
name: String,
visibility: String,
license: String,
): Array<String> = arrayOf(
TAG_NAME,
name,
visibility,
license
)
fun assemble(translationArtifactVersionMetadataTag: TranslationArtifactVersionMetadataTag) = assemble(
name = translationArtifactVersionMetadataTag.name,
visibility = translationArtifactVersionMetadataTag.visibility,
license = translationArtifactVersionMetadataTag.license
)
}
}

View File

@@ -0,0 +1,42 @@
package press.mantra.compose.nostr.nip30303.tags
import com.vitorpamplona.quartz.nip01Core.core.has
import com.vitorpamplona.quartz.utils.ensure
class WordStatisticsTag(
val wordCount: Int,
val characterCount: Int,
) {
fun toTagArray() = assemble(
wordCount = wordCount,
characterCount = characterCount,
)
companion object {
const val TAG_NAME = "word_stats"
fun parse(tag: Array<String>): WordStatisticsTag? {
ensure(tag.has(3)) { return null }
ensure(tag[0] == TAG_NAME) { return null }
return WordStatisticsTag(
wordCount = tag[1].toInt(),
characterCount = tag[2].toInt(),
)
}
fun assemble(
wordCount: Int,
characterCount: Int,
): Array<String> = arrayOf(
TAG_NAME,
wordCount.toString(),
characterCount.toString(),
)
fun assemble(wordStatisticsTag: WordStatisticsTag) = assemble(
wordCount = wordStatisticsTag.wordCount,
characterCount = wordStatisticsTag.characterCount,
)
}
}

View File

@@ -11,10 +11,14 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountTree
import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.material.icons.filled.LibraryBooks
import androidx.compose.material.icons.filled.PersonAdd
import androidx.compose.material.icons.filled.Schema
import androidx.compose.material.icons.filled.Unsubscribe
import androidx.compose.material.icons.filled.WaterfallChart
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -120,8 +124,92 @@ fun ChatRoomDetailScreen(
item {
HorizontalDivider()
// Should add media and attachments here
}
item {
// Artifacts
Text(
text = "Library",
style = MaterialTheme.typography.labelMedium
)
}
item {
Text("No artifacts exists in this group.")
}
item {
TextButton(
onClick = {
// Navigate to the invite user screen...
onNavigateToRoute.invoke(
ImplementationPendingRoute(
"Add new artifact"
)
)
}
) {
Icon(
Icons.Default.LibraryBooks,
contentDescription = "Add new artifact"
)
Spacer(
modifier = Modifier.width(10.dp)
)
Text("Add Artifact to Library")
}
}
item {
HorizontalDivider()
}
// TODO: Add projects...
item {
// Artifacts
Text(
text = "Projects",
style = MaterialTheme.typography.labelMedium
)
}
item {
Text("No projects exists in this group.")
}
item {
TextButton(
onClick = {
// Navigate to the invite user screen...
onNavigateToRoute.invoke(
ImplementationPendingRoute(
"Add new project"
)
)
}
) {
Icon(
Icons.Default.Schema,
contentDescription = "create new projec"
)
Spacer(
modifier = Modifier.width(10.dp)
)
Text("Create project")
}
}
item {
HorizontalDivider()
}
item {
Text(
text = "members",