Creates links to njump when events can't be found on Amethyst

This commit is contained in:
Vitor Pamplona 2024-08-21 17:05:14 -04:00
parent a8a3c94115
commit 83f1e523ea
6 changed files with 88 additions and 43 deletions

View File

@ -25,6 +25,7 @@ import android.util.LruCache
import androidx.compose.runtime.Stable
import androidx.lifecycle.LiveData
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.note.njumpLink
import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.ammolite.relays.RelayStats
@ -82,7 +83,7 @@ class AntiSpamFilter {
logOffender(hash, event)
if (relay != null) {
RelayStats.newSpam(relay.url, "https://njump.me/${Nip19Bech32.createNEvent(event.id, event.pubKey, event.kind, relay.url)}")
RelayStats.newSpam(relay.url, njumpLink(Nip19Bech32.createNEvent(event.id, event.pubKey, event.kind, relay.url)))
}
liveSpam.invalidateData()

View File

@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
@ -59,7 +60,7 @@ import coil.compose.AsyncImage
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.note.LoadChannel
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import com.vitorpamplona.amethyst.ui.note.njumpLink
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.Nip19Bech32
@ -80,12 +81,12 @@ fun ClickableRoute(
nav: (String) -> Unit,
) {
when (val entity = nip19.entity) {
is Nip19Bech32.NPub -> DisplayUser(entity.hex, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NProfile -> DisplayUser(entity.hex, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.Note -> DisplayEvent(entity.hex, null, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NEvent -> DisplayEvent(entity.hex, entity.kind, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NPub -> DisplayUser(entity.hex, nip19.nip19raw, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NProfile -> DisplayUser(entity.hex, nip19.nip19raw, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.Note -> DisplayEvent(entity.hex, null, nip19.nip19raw, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NEvent -> DisplayEvent(entity.hex, entity.kind, nip19.nip19raw, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NEmbed -> LoadAndDisplayEvent(entity.event, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NAddress -> DisplayAddress(entity, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NAddress -> DisplayAddress(entity, nip19.nip19raw, nip19.additionalChars, accountViewModel, nav)
is Nip19Bech32.NRelay -> {
Text(word)
}
@ -127,11 +128,16 @@ private fun LoadAndDisplayEvent(
if (it != null) {
DisplayNoteLink(it, event.id, event.kind, additionalChars, accountViewModel, nav)
} else {
val externalLink = event.toNIP19()
val uri = LocalUriHandler.current
CreateClickableText(
clickablePart = remember(event.id) { "@${event.toNIP19()}" },
clickablePart = "@$externalLink",
suffix = additionalChars,
route = remember(event.id) { "Event/${event.id}" },
nav = nav,
maxLines = 1,
onClick = {
runCatching { uri.openUri(njumpLink(externalLink)) }
},
)
}
}
@ -141,6 +147,7 @@ private fun LoadAndDisplayEvent(
fun DisplayEvent(
hex: HexKey,
kind: Int?,
nip19: String,
additionalChars: String?,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
@ -149,11 +156,16 @@ fun DisplayEvent(
if (it != null) {
DisplayNoteLink(it, hex, kind, additionalChars, accountViewModel, nav)
} else {
val externalLink = njumpLink(nip19)
val uri = LocalUriHandler.current
CreateClickableText(
clickablePart = remember(hex) { "@${hex.toShortenHex()}" },
clickablePart = remember(nip19) { "@$nip19" },
suffix = additionalChars,
route = remember(hex) { "Event/$hex" },
nav = nav,
maxLines = 1,
onClick = {
runCatching { uri.openUri(externalLink) }
},
)
}
}
@ -218,6 +230,7 @@ private fun DisplayNoteLink(
@Composable
private fun DisplayAddress(
nip19: Nip19Bech32.NAddress,
originalNip19: String,
additionalChars: String?,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
@ -245,21 +258,23 @@ private fun DisplayAddress(
}
if (noteBase == null) {
if (additionalChars != null) {
Text(
remember { "@${nip19.atag}$additionalChars" },
)
} else {
Text(
remember { "@${nip19.atag}" },
)
}
val uri = LocalUriHandler.current
CreateClickableText(
clickablePart = "@$originalNip19",
suffix = additionalChars,
maxLines = 1,
onClick = {
runCatching { uri.openUri(njumpLink(originalNip19)) }
},
)
}
}
@Composable
public fun DisplayUser(
userHex: HexKey,
originalNip19: String,
additionalChars: String?,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
@ -280,15 +295,16 @@ public fun DisplayUser(
userBase?.let { RenderUserAsClickableText(it, additionalChars, nav) }
if (userBase == null) {
if (additionalChars != null) {
Text(
remember { "@${userHex}$additionalChars" },
)
} else {
Text(
remember { "@$userHex" },
)
}
val uri = LocalUriHandler.current
CreateClickableText(
clickablePart = "@$originalNip19",
suffix = additionalChars,
maxLines = 1,
onClick = {
runCatching { uri.openUri(njumpLink(originalNip19)) }
},
)
}
}
@ -320,6 +336,26 @@ fun CreateClickableText(
fontSize: TextUnit = TextUnit.Unspecified,
route: String,
nav: (String) -> Unit,
) {
CreateClickableText(
clickablePart,
suffix,
maxLines,
overrideColor,
fontWeight,
fontSize,
) { nav(route) }
}
@Composable
fun CreateClickableText(
clickablePart: String,
suffix: String?,
maxLines: Int = Int.MAX_VALUE,
overrideColor: Color? = null,
fontWeight: FontWeight? = null,
fontSize: TextUnit = TextUnit.Unspecified,
onClick: (Int) -> Unit,
) {
val primaryColor = MaterialTheme.colorScheme.primary
val onBackgroundColor = MaterialTheme.colorScheme.onBackground
@ -351,7 +387,8 @@ fun CreateClickableText(
ClickableText(
text = text,
maxLines = maxLines,
onClick = { nav(route) },
overflow = TextOverflow.Ellipsis,
onClick = onClick,
)
}

View File

@ -162,8 +162,8 @@ class MarkdownMediaRenderer(
}
} else if (loadedLink?.nip19 != null) {
when (val entity = loadedLink.nip19.entity) {
is Nip19Bech32.NPub -> renderObservableUser(entity.hex, richTextStringBuilder)
is Nip19Bech32.NProfile -> renderObservableUser(entity.hex, richTextStringBuilder)
is Nip19Bech32.NPub -> renderObservableUser(entity.hex, loadedLink.nip19.nip19raw, richTextStringBuilder)
is Nip19Bech32.NProfile -> renderObservableUser(entity.hex, loadedLink.nip19.nip19raw, richTextStringBuilder)
is Nip19Bech32.Note -> renderObservableShortNoteUri(loadedLink, uri, richTextStringBuilder)
is Nip19Bech32.NEvent -> renderObservableShortNoteUri(loadedLink, uri, richTextStringBuilder)
is Nip19Bech32.NEmbed -> renderObservableShortNoteUri(loadedLink, uri, richTextStringBuilder)
@ -201,10 +201,11 @@ class MarkdownMediaRenderer(
fun renderObservableUser(
userHex: String,
nip19: String,
richTextStringBuilder: RichTextString.Builder,
) {
renderInline(richTextStringBuilder) {
DisplayUser(userHex, null, accountViewModel, nav)
DisplayUser(userHex, nip19, null, accountViewModel, nav)
}
}

View File

@ -111,7 +111,11 @@ private fun lightenColor(
}
val externalLinkForUser = { user: User ->
"https://njump.me/${user.toNProfile()}"
njumpLink(user.toNProfile())
}
val njumpLink = { nip19BechAddress: String ->
"https://njump.me/$nip19BechAddress"
}
val externalLinkForNote = { note: Note ->
@ -119,17 +123,17 @@ val externalLinkForNote = { note: Note ->
if (note.event?.getReward() != null) {
"https://nostrbounties.com/b/${note.address().toNAddr()}"
} else if (note.event is PeopleListEvent) {
"https://listr.lol/a/${note.address()?.toNAddr()}"
"https://listr.lol/a/${note.address().toNAddr()}"
} else if (note.event is AudioTrackEvent) {
"https://zapstr.live/?track=${note.address()?.toNAddr()}"
"https://zapstr.live/?track=${note.address().toNAddr()}"
} else {
"https://njump.me/${note.address()?.toNAddr()}"
njumpLink(note.address().toNAddr())
}
} else {
if (note.event is FileHeaderEvent) {
"https://filestr.vercel.app/e/${note.toNEvent()}"
} else {
"https://njump.me/${note.toNEvent()}"
njumpLink(note.toNEvent())
}
}
}

View File

@ -257,7 +257,7 @@ fun DisplayEntryForNote(
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
)
} else {
DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav)
DisplayEvent(noteEvent.id, noteEvent.kind, noteEvent.toNIP19(), null, accountViewModel, nav)
}
}

View File

@ -57,6 +57,7 @@ object Nip19Bech32 {
@Immutable
data class ParseReturn(
val entity: Entity,
val nip19raw: String,
val additionalChars: String? = null,
)
@ -138,7 +139,8 @@ object Nip19Bech32 {
additionalChars: String?,
): ParseReturn? =
try {
val bytes = (type + key).bechToBytes()
val nip19 = (type + key)
val bytes = nip19.bechToBytes()
when (type.lowercase()) {
"nsec1" -> nsec(bytes)
@ -151,7 +153,7 @@ object Nip19Bech32 {
"nembed1" -> nembed(bytes)
else -> null
}?.let {
ParseReturn(it, additionalChars)
ParseReturn(it, nip19, additionalChars)
}
} catch (e: Throwable) {
Log.w("NIP19 Parser", "Issue trying to Decode NIP19 $key: ${e.message}", e)