mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-22 21:51:57 +02:00
1. Moves AddressableNote index from NAddr to aTag format due to the presence of a preferred relay inside NAddr, which is an optional field and should not be part of the idex.
2. Parses relay information for Addressable Notes
This commit is contained in:
@@ -77,7 +77,7 @@ object LocalCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkGetOrCreateNote(key: String): Note? {
|
fun checkGetOrCreateNote(key: String): Note? {
|
||||||
if (key.startsWith("naddr1")) {
|
if (key.startsWith("naddr1") || key.contains(":")) {
|
||||||
return checkGetOrCreateAddressableNote(key)
|
return checkGetOrCreateAddressableNote(key)
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
@@ -120,7 +120,7 @@ object LocalCache {
|
|||||||
|
|
||||||
fun checkGetOrCreateAddressableNote(key: String): AddressableNote? {
|
fun checkGetOrCreateAddressableNote(key: String): AddressableNote? {
|
||||||
return try {
|
return try {
|
||||||
val addr = ATag.parse(key)
|
val addr = ATag.parse(key, null) // relay doesn't matter for the index.
|
||||||
if (addr != null)
|
if (addr != null)
|
||||||
getOrCreateAddressableNote(addr)
|
getOrCreateAddressableNote(addr)
|
||||||
else
|
else
|
||||||
@@ -133,10 +133,12 @@ object LocalCache {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun getOrCreateAddressableNote(key: ATag): AddressableNote {
|
fun getOrCreateAddressableNote(key: ATag): AddressableNote {
|
||||||
return addressables[key.toNAddr()] ?: run {
|
// we can't use naddr here because naddr might include relay info and
|
||||||
|
// the preferred relay should not be part of the index.
|
||||||
|
return addressables[key.toTag()] ?: run {
|
||||||
val answer = AddressableNote(key)
|
val answer = AddressableNote(key)
|
||||||
answer.author = checkGetOrCreateUser(key.pubKeyHex)
|
answer.author = checkGetOrCreateUser(key.pubKeyHex)
|
||||||
addressables.put(key.toNAddr(), answer)
|
addressables.put(key.toTag(), answer)
|
||||||
answer
|
answer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@ import kotlinx.coroutines.withContext
|
|||||||
val tagSearch = Pattern.compile("(?:\\s|\\A)\\#\\[([0-9]+)\\]")
|
val tagSearch = Pattern.compile("(?:\\s|\\A)\\#\\[([0-9]+)\\]")
|
||||||
|
|
||||||
|
|
||||||
class AddressableNote(val address: ATag): Note(address.toNAddr()) {
|
class AddressableNote(val address: ATag): Note(address.toTag()) {
|
||||||
override fun idNote() = address.toNAddr()
|
override fun idNote() = address.toNAddr()
|
||||||
override fun idDisplayNote() = idNote().toShortenHex()
|
override fun idDisplayNote() = idNote().toShortenHex()
|
||||||
override fun address() = address
|
override fun address() = address
|
||||||
|
@@ -35,8 +35,8 @@ class ThreadAssembler {
|
|||||||
@OptIn(ExperimentalTime::class)
|
@OptIn(ExperimentalTime::class)
|
||||||
fun findThreadFor(noteId: String): Set<Note> {
|
fun findThreadFor(noteId: String): Set<Note> {
|
||||||
val (result, elapsed) = measureTimedValue {
|
val (result, elapsed) = measureTimedValue {
|
||||||
val note = if (noteId.startsWith("naddr")) {
|
val note = if (noteId.contains(":")) {
|
||||||
val aTag = ATag.parse(noteId)
|
val aTag = ATag.parse(noteId, null)
|
||||||
if (aTag != null)
|
if (aTag != null)
|
||||||
LocalCache.getOrCreateAddressableNote(aTag)
|
LocalCache.getOrCreateAddressableNote(aTag)
|
||||||
else
|
else
|
||||||
|
@@ -11,7 +11,7 @@ class Nip19 {
|
|||||||
USER, NOTE, RELAY, ADDRESS
|
USER, NOTE, RELAY, ADDRESS
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Return(val type: Type, val hex: String)
|
data class Return(val type: Type, val hex: String, val relay: String?)
|
||||||
|
|
||||||
fun uriToRoute(uri: String?): Return? {
|
fun uriToRoute(uri: String?): Return? {
|
||||||
try {
|
try {
|
||||||
@@ -39,29 +39,39 @@ class Nip19 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun npub(bytes: ByteArray): Return {
|
private fun npub(bytes: ByteArray): Return {
|
||||||
return Return(Type.USER, bytes.toHexKey())
|
return Return(Type.USER, bytes.toHexKey(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun note(bytes: ByteArray): Return {
|
private fun note(bytes: ByteArray): Return {
|
||||||
return Return(Type.NOTE, bytes.toHexKey());
|
return Return(Type.NOTE, bytes.toHexKey(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nprofile(bytes: ByteArray): Return? {
|
private fun nprofile(bytes: ByteArray): Return? {
|
||||||
val hex = parseTLV(bytes)
|
val tlv = parseTLV(bytes)
|
||||||
.get(NIP19TLVTypes.SPECIAL.id)
|
|
||||||
|
val hex = tlv.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
?.get(0)
|
?.get(0)
|
||||||
?.toHexKey() ?: return null
|
?.toHexKey() ?: return null
|
||||||
|
|
||||||
return Return(Type.USER, hex)
|
val relay = tlv.get(NIP19TLVTypes.RELAY.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toString(Charsets.UTF_8)
|
||||||
|
|
||||||
|
return Return(Type.USER, hex, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nevent(bytes: ByteArray): Return? {
|
private fun nevent(bytes: ByteArray): Return? {
|
||||||
val hex = parseTLV(bytes)
|
val tlv = parseTLV(bytes)
|
||||||
.get(NIP19TLVTypes.SPECIAL.id)
|
|
||||||
|
val hex = tlv.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
?.get(0)
|
?.get(0)
|
||||||
?.toHexKey() ?: return null
|
?.toHexKey() ?: return null
|
||||||
|
|
||||||
return Return(Type.USER, hex)
|
val relay = tlv.get(NIP19TLVTypes.RELAY.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toString(Charsets.UTF_8)
|
||||||
|
|
||||||
|
return Return(Type.USER, hex, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nrelay(bytes: ByteArray): Return? {
|
private fun nrelay(bytes: ByteArray): Return? {
|
||||||
@@ -70,7 +80,7 @@ class Nip19 {
|
|||||||
?.get(0)
|
?.get(0)
|
||||||
?.toString(Charsets.UTF_8) ?: return null
|
?.toString(Charsets.UTF_8) ?: return null
|
||||||
|
|
||||||
return Return(Type.RELAY, relayUrl)
|
return Return(Type.RELAY, relayUrl, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun naddr(bytes: ByteArray): Return? {
|
private fun naddr(bytes: ByteArray): Return? {
|
||||||
@@ -92,7 +102,7 @@ class Nip19 {
|
|||||||
?.get(0)
|
?.get(0)
|
||||||
?.let { toInt32(it) }
|
?.let { toInt32(it) }
|
||||||
|
|
||||||
return Return(Type.ADDRESS, "$kind:$author:$d")
|
return Return(Type.ADDRESS, "$kind:$author:$d", relay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -84,7 +84,7 @@ object NostrUserProfileDataSource: NostrDataSource("UserProfileFeed") {
|
|||||||
types = FeedType.values().toSet(),
|
types = FeedType.values().toSet(),
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(BadgeProfilesEvent.kind),
|
kinds = listOf(BadgeProfilesEvent.kind),
|
||||||
tags = mapOf("p" to listOf(it.pubkeyHex)),
|
authors = listOf(it.pubkeyHex),
|
||||||
limit = 1
|
limit = 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@@ -11,35 +11,41 @@ import nostr.postr.Bech32
|
|||||||
import nostr.postr.bechToBytes
|
import nostr.postr.bechToBytes
|
||||||
import nostr.postr.toByteArray
|
import nostr.postr.toByteArray
|
||||||
|
|
||||||
data class ATag(val kind: Int, val pubKeyHex: String, val dTag: String) {
|
data class ATag(val kind: Int, val pubKeyHex: String, val dTag: String, val relay: String?) {
|
||||||
fun toTag() = "$kind:$pubKeyHex:$dTag"
|
fun toTag() = "$kind:$pubKeyHex:$dTag"
|
||||||
|
|
||||||
fun toNAddr(): String {
|
fun toNAddr(): String {
|
||||||
val kind = kind.toByteArray()
|
val kind = kind.toByteArray()
|
||||||
val addr = pubKeyHex.toByteArray()
|
val author = pubKeyHex.toByteArray()
|
||||||
val dTag = dTag.toByteArray(Charsets.UTF_8)
|
val dTag = dTag.toByteArray(Charsets.UTF_8)
|
||||||
|
val relay = relay?.toByteArray(Charsets.UTF_8)
|
||||||
|
|
||||||
val fullArray =
|
var fullArray =
|
||||||
byteArrayOf(NIP19TLVTypes.SPECIAL.id, dTag.size.toByte()) + dTag +
|
byteArrayOf(NIP19TLVTypes.SPECIAL.id, dTag.size.toByte()) + dTag
|
||||||
byteArrayOf(NIP19TLVTypes.AUTHOR.id, addr.size.toByte()) + addr +
|
|
||||||
|
if (relay != null)
|
||||||
|
fullArray = fullArray + byteArrayOf(NIP19TLVTypes.RELAY.id, relay.size.toByte()) + relay
|
||||||
|
|
||||||
|
fullArray = fullArray +
|
||||||
|
byteArrayOf(NIP19TLVTypes.AUTHOR.id, author.size.toByte()) + author +
|
||||||
byteArrayOf(NIP19TLVTypes.KIND.id, kind.size.toByte()) + kind
|
byteArrayOf(NIP19TLVTypes.KIND.id, kind.size.toByte()) + kind
|
||||||
|
|
||||||
return Bech32.encodeBytes(hrp = "naddr", fullArray, Bech32.Encoding.Bech32)
|
return Bech32.encodeBytes(hrp = "naddr", fullArray, Bech32.Encoding.Bech32)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(address: String): ATag? {
|
fun parse(address: String, relay: String?): ATag? {
|
||||||
return if (address.startsWith("naddr") || address.startsWith("nostr:naddr"))
|
return if (address.startsWith("naddr") || address.startsWith("nostr:naddr"))
|
||||||
parseNAddr(address)
|
parseNAddr(address)
|
||||||
else
|
else
|
||||||
parseAtag(address)
|
parseAtag(address, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseAtag(atag: String): ATag? {
|
fun parseAtag(atag: String, relay: String?): ATag? {
|
||||||
return try {
|
return try {
|
||||||
val parts = atag.split(":")
|
val parts = atag.split(":")
|
||||||
Hex.decode(parts[1])
|
Hex.decode(parts[1])
|
||||||
ATag(parts[0].toInt(), parts[1], parts[2])
|
ATag(parts[0].toInt(), parts[1], parts[2], relay)
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
Log.w("ATag", "Error parsing A Tag: ${atag}: ${t.message}")
|
Log.w("ATag", "Error parsing A Tag: ${atag}: ${t.message}")
|
||||||
null
|
null
|
||||||
@@ -58,7 +64,7 @@ data class ATag(val kind: Int, val pubKeyHex: String, val dTag: String) {
|
|||||||
val kind = tlv.get(NIP19TLVTypes.KIND.id)?.get(0)?.let { toInt32(it) }
|
val kind = tlv.get(NIP19TLVTypes.KIND.id)?.get(0)?.let { toInt32(it) }
|
||||||
|
|
||||||
if (kind != null && author != null)
|
if (kind != null && author != null)
|
||||||
return ATag(kind, author, d)
|
return ATag(kind, author, d, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
@@ -14,7 +14,12 @@ class BadgeAwardEvent(
|
|||||||
sig: HexKey
|
sig: HexKey
|
||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
fun awardees() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun awardees() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun awardDefinition() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun awardDefinition() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val kind = 8
|
const val kind = 8
|
||||||
|
@@ -14,7 +14,7 @@ class BadgeDefinitionEvent(
|
|||||||
sig: HexKey
|
sig: HexKey
|
||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
||||||
fun address() = ATag(kind, pubKey, dTag())
|
fun address() = ATag(kind, pubKey, dTag(), null)
|
||||||
|
|
||||||
fun name() = tags.filter { it.firstOrNull() == "name" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
fun name() = tags.filter { it.firstOrNull() == "name" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
||||||
fun thumb() = tags.filter { it.firstOrNull() == "thumb" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
fun thumb() = tags.filter { it.firstOrNull() == "thumb" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
||||||
|
@@ -11,10 +11,15 @@ class BadgeProfilesEvent(
|
|||||||
sig: HexKey
|
sig: HexKey
|
||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
fun badgeAwardEvents() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun badgeAwardEvents() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun badgeAwardDefinitions() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun badgeAwardDefinitions() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
||||||
fun address() = ATag(kind, pubKey, dTag())
|
fun address() = ATag(kind, pubKey, dTag(), null)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val kind = 30008
|
const val kind = 30008
|
||||||
|
@@ -24,8 +24,12 @@ class LnZapEvent(
|
|||||||
|
|
||||||
override fun taggedAddresses(): List<ATag> = tags
|
override fun taggedAddresses(): List<ATag> = tags
|
||||||
.filter { it.firstOrNull() == "a" }
|
.filter { it.firstOrNull() == "a" }
|
||||||
.mapNotNull { it.getOrNull(1) }
|
.mapNotNull {
|
||||||
.mapNotNull { ATag.parse(it) }
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
override fun amount(): BigDecimal? {
|
override fun amount(): BigDecimal? {
|
||||||
return lnInvoice()?.let { LnInvoiceUtil.getAmountInSats(it) }
|
return lnInvoice()?.let { LnInvoiceUtil.getAmountInSats(it) }
|
||||||
|
@@ -16,7 +16,12 @@ class LnZapRequestEvent (
|
|||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
fun zappedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun zappedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun zappedAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun zappedAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val kind = 9734
|
const val kind = 9734
|
||||||
|
@@ -17,7 +17,7 @@ class LongTextNoteEvent(
|
|||||||
fun mentions() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun mentions() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
|
|
||||||
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
fun dTag() = tags.filter { it.firstOrNull() == "d" }.mapNotNull { it.getOrNull(1) }.firstOrNull() ?: ""
|
||||||
fun address() = ATag(kind, pubKey, dTag())
|
fun address() = ATag(kind, pubKey, dTag(), null)
|
||||||
|
|
||||||
fun topics() = tags.filter { it.firstOrNull() == "t" }.mapNotNull { it.getOrNull(1) }
|
fun topics() = tags.filter { it.firstOrNull() == "t" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun title() = tags.filter { it.firstOrNull() == "title" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
fun title() = tags.filter { it.firstOrNull() == "title" }.mapNotNull { it.getOrNull(1) }.firstOrNull()
|
||||||
|
@@ -17,7 +17,12 @@ class ReactionEvent (
|
|||||||
|
|
||||||
fun originalPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun originalPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val kind = 7
|
const val kind = 7
|
||||||
|
@@ -48,7 +48,12 @@ class ReportEvent (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val kind = 1984
|
const val kind = 1984
|
||||||
|
@@ -18,7 +18,12 @@ class RepostEvent (
|
|||||||
|
|
||||||
fun boostedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun boostedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
fun containedPost() = try {
|
fun containedPost() = try {
|
||||||
fromJson(content, Client.lenient)
|
fromJson(content, Client.lenient)
|
||||||
|
@@ -14,7 +14,13 @@ class TextNoteEvent(
|
|||||||
sig: HexKey
|
sig: HexKey
|
||||||
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
): Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
fun mentions() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun mentions() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||||
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull { it.getOrNull(1) }.mapNotNull { ATag.parse(it) }
|
fun taggedAddresses() = tags.filter { it.firstOrNull() == "a" }.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
fun replyTos() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun replyTos() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.components
|
|||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.foundation.text.ClickableText
|
||||||
import androidx.compose.material.LocalTextStyle
|
import androidx.compose.material.LocalTextStyle
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@@ -31,7 +32,24 @@ fun ClickableRoute(
|
|||||||
onClick = { navController.navigate(route) },
|
onClick = { navController.navigate(route) },
|
||||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
||||||
)
|
)
|
||||||
|
} else if (nip19.type == Nip19.Type.ADDRESS) {
|
||||||
|
val noteBase = LocalCache.checkGetOrCreateAddressableNote(nip19.hex)
|
||||||
|
|
||||||
|
if (noteBase == null) {
|
||||||
|
Text(
|
||||||
|
"@${nip19.hex} "
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
|
val noteState by noteBase.live().metadata.observeAsState()
|
||||||
|
val note = noteState?.note ?: return
|
||||||
|
|
||||||
|
ClickableText(
|
||||||
|
text = AnnotatedString("@${note.idDisplayNote()} "),
|
||||||
|
onClick = { navController.navigate("Note/${nip19.hex}") },
|
||||||
|
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (nip19.type == Nip19.Type.NOTE) {
|
||||||
val noteBase = LocalCache.getOrCreateNote(nip19.hex)
|
val noteBase = LocalCache.getOrCreateNote(nip19.hex)
|
||||||
val noteState by noteBase.live().metadata.observeAsState()
|
val noteState by noteBase.live().metadata.observeAsState()
|
||||||
val note = noteState?.note ?: return
|
val note = noteState?.note ?: return
|
||||||
@@ -55,5 +73,9 @@ fun ClickableRoute(
|
|||||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
"@${nip19.hex} "
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -200,11 +200,13 @@ private fun isArabic(text: String): Boolean {
|
|||||||
fun isBechLink(word: String): Boolean {
|
fun isBechLink(word: String): Boolean {
|
||||||
return word.startsWith("nostr:", true)
|
return word.startsWith("nostr:", true)
|
||||||
|| word.startsWith("npub1", true)
|
|| word.startsWith("npub1", true)
|
||||||
|
|| word.startsWith("naddr1", true)
|
||||||
|| word.startsWith("note1", true)
|
|| word.startsWith("note1", true)
|
||||||
|| word.startsWith("nprofile1", true)
|
|| word.startsWith("nprofile1", true)
|
||||||
|| word.startsWith("nevent1", true)
|
|| word.startsWith("nevent1", true)
|
||||||
|| word.startsWith("@npub1", true)
|
|| word.startsWith("@npub1", true)
|
||||||
|| word.startsWith("@note1", true)
|
|| word.startsWith("@note1", true)
|
||||||
|
|| word.startsWith("@addr1", true)
|
||||||
|| word.startsWith("@nprofile1", true)
|
|| word.startsWith("@nprofile1", true)
|
||||||
|| word.startsWith("@nevent1", true)
|
|| word.startsWith("@nevent1", true)
|
||||||
}
|
}
|
||||||
|
@@ -18,15 +18,39 @@ class NIP19ParserTest {
|
|||||||
assertEquals("30023:d0debf9fb12def81f43d7c69429bb784812ac1e4d2d53a202db6aac7ea4b466c:guide-wireguard", result?.hex)
|
assertEquals("30023:d0debf9fb12def81f43d7c69429bb784812ac1e4d2d53a202db6aac7ea4b466c:guide-wireguard", result?.hex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nAddrParse3() {
|
||||||
|
val result = Nip19().uriToRoute("naddr1qqyrswtyv5mnjv3sqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsygx3uczxts4hwue9ayfn7ggq62anzstde2qs749pm9tx2csuthhpjvpsgqqqw4rs8pmj38")
|
||||||
|
assertEquals(Nip19.Type.ADDRESS, result?.type)
|
||||||
|
assertEquals("30023:d1e60465c2b777325e9133f2100d2bb31416dca810f54a1d95665621c5dee193:89de7920", result?.hex)
|
||||||
|
assertEquals("wss://relay.damus.io", result?.relay)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nAddrATagParse3() {
|
||||||
|
val address = ATag.parse("30023:d1e60465c2b777325e9133f2100d2bb31416dca810f54a1d95665621c5dee193:89de7920", "wss://relay.damus.io")
|
||||||
|
assertEquals(30023, address?.kind)
|
||||||
|
assertEquals("d1e60465c2b777325e9133f2100d2bb31416dca810f54a1d95665621c5dee193", address?.pubKeyHex)
|
||||||
|
assertEquals("89de7920", address?.dTag)
|
||||||
|
assertEquals("wss://relay.damus.io" , address?.relay)
|
||||||
|
assertEquals("naddr1qqyrswtyv5mnjv3sqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsygx3uczxts4hwue9ayfn7ggq62anzstde2qs749pm9tx2csuthhpjvpsgqqqw4rs8pmj38", address?.toNAddr())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nAddrFormatter() {
|
fun nAddrFormatter() {
|
||||||
val address = ATag(30023, "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", "" )
|
val address = ATag(30023, "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", "", null)
|
||||||
assertEquals("naddr1qqqqygzxpsj7dqha57pjk5k37gkn6g4nzakewtmqmnwryyhd3jfwlpgxtspsgqqqw4rs3xyxus", address.toNAddr())
|
assertEquals("naddr1qqqqygzxpsj7dqha57pjk5k37gkn6g4nzakewtmqmnwryyhd3jfwlpgxtspsgqqqw4rs3xyxus", address.toNAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nAddrFormatter2() {
|
fun nAddrFormatter2() {
|
||||||
val address = ATag(30023, "d0debf9fb12def81f43d7c69429bb784812ac1e4d2d53a202db6aac7ea4b466c", "guide-wireguard" )
|
val address = ATag(30023, "d0debf9fb12def81f43d7c69429bb784812ac1e4d2d53a202db6aac7ea4b466c", "guide-wireguard", null)
|
||||||
assertEquals("naddr1qq8kwatfv3jj6amfwfjkwatpwfjqygxsm6lelvfda7qlg0tud9pfhduysy4vrexj65azqtdk4tr75j6xdspsgqqqw4rsg32ag8", address.toNAddr())
|
assertEquals("naddr1qq8kwatfv3jj6amfwfjkwatpwfjqygxsm6lelvfda7qlg0tud9pfhduysy4vrexj65azqtdk4tr75j6xdspsgqqqw4rsg32ag8", address.toNAddr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nAddrFormatter3() {
|
||||||
|
val address = ATag(30023, "d1e60465c2b777325e9133f2100d2bb31416dca810f54a1d95665621c5dee193", "89de7920", "wss://relay.damus.io")
|
||||||
|
assertEquals("naddr1qqyrswtyv5mnjv3sqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsygx3uczxts4hwue9ayfn7ggq62anzstde2qs749pm9tx2csuthhpjvpsgqqqw4rs8pmj38", address.toNAddr())
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user