diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/nip19/Nip19.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/nip19/Nip19.kt
index eef4955ce..b4bdda203 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/service/nip19/Nip19.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/service/nip19/Nip19.kt
@@ -7,7 +7,7 @@ import java.util.regex.Pattern
object Nip19 {
enum class Type {
- USER, NOTE, RELAY, ADDRESS
+ USER, NOTE, EVENT, RELAY, ADDRESS
}
val nip19regex = Pattern.compile("(nostr:)?@?(nsec1|npub1|nevent1|naddr1|note1|nprofile1|nrelay1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)(.*)", Pattern.CASE_INSENSITIVE)
@@ -76,7 +76,7 @@ object Nip19 {
?.get(0)
?.toString(Charsets.UTF_8)
- return Return(Type.USER, hex, relay)
+ return Return(Type.EVENT, hex, relay)
}
private fun nrelay(bytes: ByteArray): Return? {
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
index 3cc32af87..3afecdcb7 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
@@ -37,6 +37,8 @@ class MainActivity : FragmentActivity() {
val startingPage = when (nip19?.type) {
Nip19.Type.USER -> "User/${nip19.hex}"
Nip19.Type.NOTE -> "Note/${nip19.hex}"
+ Nip19.Type.EVENT -> "Event/${nip19.hex}"
+ Nip19.Type.ADDRESS -> "Note/${nip19.hex}"
else -> null
}
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt
index b8a37000c..881947e14 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt
@@ -87,6 +87,8 @@ class NewPostViewModel : ViewModel() {
addUserToMentions(LocalCache.getOrCreateUser(results.key.hex))
} else if (results?.key?.type == Nip19.Type.NOTE) {
addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex))
+ } else if (results?.key?.type == Nip19.Type.EVENT) {
+ addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex))
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
if (note != null) {
@@ -107,6 +109,10 @@ class NewPostViewModel : ViewModel() {
} else if (results?.key?.type == Nip19.Type.NOTE) {
val note = LocalCache.getOrCreateNote(results.key.hex)
+ "#[${tagIndex(note)}]${results.restOfWord}"
+ } else if (results?.key?.type == Nip19.Type.EVENT) {
+ val note = LocalCache.getOrCreateNote(results.key.hex)
+
"#[${tagIndex(note)}]${results.restOfWord}"
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt
index 0e02d1e9f..f9117a13e 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt
@@ -12,6 +12,7 @@ import androidx.compose.ui.text.withStyle
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
+import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
import com.vitorpamplona.amethyst.service.nip19.Nip19
@Composable
@@ -47,11 +48,28 @@ fun ClickableRoute(
if (note.event is ChannelCreateEvent) {
CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Channel/${nip19.hex}", navController)
+ } else if (note.event is PrivateDmEvent) {
+ CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Room/${note.author?.pubkeyHex}", navController)
} else if (channel != null) {
CreateClickableText(channel.toBestDisplayName(), nip19.additionalChars, "Channel/${note.channel()?.idHex}", navController)
} else {
CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Note/${nip19.hex}", navController)
}
+ } else if (nip19.type == Nip19.Type.EVENT) {
+ val noteBase = LocalCache.getOrCreateNote(nip19.hex)
+ val noteState by noteBase.live().metadata.observeAsState()
+ val note = noteState?.note ?: return
+ val channel = note.channel()
+
+ if (note.event is ChannelCreateEvent) {
+ CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Channel/${nip19.hex}", navController)
+ } else if (note.event is PrivateDmEvent) {
+ CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Room/${note.author?.pubkeyHex}", navController)
+ } else if (channel != null) {
+ CreateClickableText(channel.toBestDisplayName(), nip19.additionalChars, "Channel/${note.channel()?.idHex}", navController)
+ } else {
+ CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Event/${nip19.hex}", navController)
+ }
} else {
Text(
"@${nip19.hex}${nip19.additionalChars} "
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
index a4565e4bc..f22e0ddda 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
@@ -23,6 +23,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HashtagScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HomeScreen
+import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.NotificationScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen
@@ -126,6 +127,16 @@ fun AppNavigation(
)
})
}
+
+ Route.Event.let { route ->
+ composable(route.route, route.arguments, content = {
+ LoadRedirectScreen(
+ eventId = it.arguments?.getString("id"),
+ accountViewModel = accountViewModel,
+ navController = navController
+ )
+ })
+ }
}
if (nextPage != null) {
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
index 2062c2005..99ea241af 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
@@ -87,6 +87,12 @@ sealed class Route(
icon = R.drawable.ic_moments,
arguments = listOf(navArgument("id") { type = NavType.StringType })
)
+
+ object Event : Route(
+ route = "Event/{id}",
+ icon = R.drawable.ic_moments,
+ arguments = listOf(navArgument("id") { type = NavType.StringType })
+ )
}
// **
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt
index 3fe48a5df..c1f31f99c 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt
@@ -1,5 +1,6 @@
package com.vitorpamplona.amethyst.ui.qrcode
+import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -19,6 +20,8 @@ fun NIP19QrCodeScanner(onScan: (String?) -> Unit) {
val startingPage = when (nip19?.type) {
Nip19.Type.USER -> "User/${nip19.hex}"
Nip19.Type.NOTE -> "Note/${nip19.hex}"
+ Nip19.Type.EVENT -> "Event/${nip19.hex}"
+ Nip19.Type.ADDRESS -> "Note/${nip19.hex}"
else -> null
}
@@ -28,6 +31,7 @@ fun NIP19QrCodeScanner(onScan: (String?) -> Unit) {
onScan(null)
}
} catch (e: Throwable) {
+ Log.e("NIP19 Scanner", "Error parsing $it", e)
// QR can be anything, do not throw errors.
onScan(null)
}
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt
new file mode 100644
index 000000000..1cac914e9
--- /dev/null
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt
@@ -0,0 +1,63 @@
+package com.vitorpamplona.amethyst.ui.screen.loggedIn
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import com.vitorpamplona.amethyst.R
+import com.vitorpamplona.amethyst.model.LocalCache
+import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
+import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
+
+@Composable
+fun LoadRedirectScreen(eventId: String?, accountViewModel: AccountViewModel, navController: NavController) {
+ if (eventId == null) return
+
+ val baseNote = LocalCache.checkGetOrCreateNote(eventId) ?: return
+
+ val noteState by baseNote.live().metadata.observeAsState()
+ val note = noteState?.note
+
+ LaunchedEffect(key1 = noteState) {
+ val event = note?.event
+ val channel = note?.channel()
+
+ if (event == null) {
+ // stay here, loading
+ } else if (event is ChannelCreateEvent) {
+ navController.backQueue.removeLast()
+ navController.navigate("Channel/${note.idHex}")
+ } else if (event is PrivateDmEvent) {
+ navController.backQueue.removeLast()
+ navController.navigate("Room/${note.author?.pubkeyHex}")
+ } else if (channel != null) {
+ navController.backQueue.removeLast()
+ navController.navigate("Channel/${channel.idHex}")
+ } else {
+ navController.backQueue.removeLast()
+ navController.navigate("Note/${note.idHex}")
+ }
+ }
+
+ Column(
+ Modifier
+ .fillMaxHeight()
+ .fillMaxWidth()
+ .padding(horizontal = 50.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text(stringResource(R.string.looking_for_event, eventId))
+ }
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eb30c0bdc..4e0428a04 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -263,4 +263,6 @@
Wallet Connect Relay
Pledge Amount in Sats
+
+ "Looking for Event %1$s"
diff --git a/app/src/test/java/com/vitorpamplona/amethyst/NIP19ParserTest.kt b/app/src/test/java/com/vitorpamplona/amethyst/NIP19ParserTest.kt
index d7ee9db44..488cb27d2 100644
--- a/app/src/test/java/com/vitorpamplona/amethyst/NIP19ParserTest.kt
+++ b/app/src/test/java/com/vitorpamplona/amethyst/NIP19ParserTest.kt
@@ -69,4 +69,12 @@ class NIP19ParserTest {
assertEquals("30023:46fcbe3065eaf1ae7811465924e48923363ff3f526bd6f73d7c184b16bd8ce4d:1679509418", result?.hex)
assertEquals(null, result?.relay)
}
+
+ @Test
+ fun nEventParserTest() {
+ val result = Nip19.uriToRoute("nostr:nevent1qqs0tsw8hjacs4fppgdg7f5yhgwwfkyua4xcs3re9wwkpkk2qeu6mhql22rcy")
+ assertEquals(Nip19.Type.EVENT, result?.type)
+ assertEquals("f5c1c7bcbb8855210a1a8f2684ba1ce4d89ced4d8844792b9d60daca0679addc", result?.hex)
+ assertEquals(null, result?.relay)
+ }
}