Creates a Loading screen to get events before redirecting them to the appropriate screen (DMs, Channels, Threads)
This commit is contained in:
@@ -7,7 +7,7 @@ import java.util.regex.Pattern
|
|||||||
|
|
||||||
object Nip19 {
|
object Nip19 {
|
||||||
enum class Type {
|
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)
|
val nip19regex = Pattern.compile("(nostr:)?@?(nsec1|npub1|nevent1|naddr1|note1|nprofile1|nrelay1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)(.*)", Pattern.CASE_INSENSITIVE)
|
||||||
@@ -76,7 +76,7 @@ object Nip19 {
|
|||||||
?.get(0)
|
?.get(0)
|
||||||
?.toString(Charsets.UTF_8)
|
?.toString(Charsets.UTF_8)
|
||||||
|
|
||||||
return Return(Type.USER, hex, relay)
|
return Return(Type.EVENT, hex, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nrelay(bytes: ByteArray): Return? {
|
private fun nrelay(bytes: ByteArray): Return? {
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ class MainActivity : FragmentActivity() {
|
|||||||
val startingPage = when (nip19?.type) {
|
val startingPage = when (nip19?.type) {
|
||||||
Nip19.Type.USER -> "User/${nip19.hex}"
|
Nip19.Type.USER -> "User/${nip19.hex}"
|
||||||
Nip19.Type.NOTE -> "Note/${nip19.hex}"
|
Nip19.Type.NOTE -> "Note/${nip19.hex}"
|
||||||
|
Nip19.Type.EVENT -> "Event/${nip19.hex}"
|
||||||
|
Nip19.Type.ADDRESS -> "Note/${nip19.hex}"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class NewPostViewModel : ViewModel() {
|
|||||||
addUserToMentions(LocalCache.getOrCreateUser(results.key.hex))
|
addUserToMentions(LocalCache.getOrCreateUser(results.key.hex))
|
||||||
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
||||||
addNoteToReplyTos(LocalCache.getOrCreateNote(results.key.hex))
|
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) {
|
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
|
||||||
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
@@ -107,6 +109,10 @@ class NewPostViewModel : ViewModel() {
|
|||||||
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
} else if (results?.key?.type == Nip19.Type.NOTE) {
|
||||||
val note = LocalCache.getOrCreateNote(results.key.hex)
|
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}"
|
"#[${tagIndex(note)}]${results.restOfWord}"
|
||||||
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
|
} else if (results?.key?.type == Nip19.Type.ADDRESS) {
|
||||||
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
val note = LocalCache.checkGetOrCreateAddressableNote(results.key.hex)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import androidx.compose.ui.text.withStyle
|
|||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -47,11 +48,28 @@ fun ClickableRoute(
|
|||||||
|
|
||||||
if (note.event is ChannelCreateEvent) {
|
if (note.event is ChannelCreateEvent) {
|
||||||
CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Channel/${nip19.hex}", navController)
|
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) {
|
} else if (channel != null) {
|
||||||
CreateClickableText(channel.toBestDisplayName(), nip19.additionalChars, "Channel/${note.channel()?.idHex}", navController)
|
CreateClickableText(channel.toBestDisplayName(), nip19.additionalChars, "Channel/${note.channel()?.idHex}", navController)
|
||||||
} else {
|
} else {
|
||||||
CreateClickableText(note.idDisplayNote(), nip19.additionalChars, "Note/${nip19.hex}", navController)
|
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 {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
"@${nip19.hex}${nip19.additionalChars} "
|
"@${nip19.hex}${nip19.additionalChars} "
|
||||||
|
|||||||
@@ -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.HashtagScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.HomeScreen
|
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.NotificationScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen
|
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) {
|
if (nextPage != null) {
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ sealed class Route(
|
|||||||
icon = R.drawable.ic_moments,
|
icon = R.drawable.ic_moments,
|
||||||
arguments = listOf(navArgument("id") { type = NavType.StringType })
|
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 })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// **
|
// **
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.qrcode
|
package com.vitorpamplona.amethyst.ui.qrcode
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
@@ -19,6 +20,8 @@ fun NIP19QrCodeScanner(onScan: (String?) -> Unit) {
|
|||||||
val startingPage = when (nip19?.type) {
|
val startingPage = when (nip19?.type) {
|
||||||
Nip19.Type.USER -> "User/${nip19.hex}"
|
Nip19.Type.USER -> "User/${nip19.hex}"
|
||||||
Nip19.Type.NOTE -> "Note/${nip19.hex}"
|
Nip19.Type.NOTE -> "Note/${nip19.hex}"
|
||||||
|
Nip19.Type.EVENT -> "Event/${nip19.hex}"
|
||||||
|
Nip19.Type.ADDRESS -> "Note/${nip19.hex}"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +31,7 @@ fun NIP19QrCodeScanner(onScan: (String?) -> Unit) {
|
|||||||
onScan(null)
|
onScan(null)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
Log.e("NIP19 Scanner", "Error parsing $it", e)
|
||||||
// QR can be anything, do not throw errors.
|
// QR can be anything, do not throw errors.
|
||||||
onScan(null)
|
onScan(null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -263,4 +263,6 @@
|
|||||||
<string name="wallet_connect_service_relay">Wallet Connect Relay</string>
|
<string name="wallet_connect_service_relay">Wallet Connect Relay</string>
|
||||||
|
|
||||||
<string name="pledge_amount_in_sats">Pledge Amount in Sats</string>
|
<string name="pledge_amount_in_sats">Pledge Amount in Sats</string>
|
||||||
|
|
||||||
|
<string name="looking_for_event">"Looking for Event %1$s"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -69,4 +69,12 @@ class NIP19ParserTest {
|
|||||||
assertEquals("30023:46fcbe3065eaf1ae7811465924e48923363ff3f526bd6f73d7c184b16bd8ce4d:1679509418", result?.hex)
|
assertEquals("30023:46fcbe3065eaf1ae7811465924e48923363ff3f526bd6f73d7c184b16bd8ce4d:1679509418", result?.hex)
|
||||||
assertEquals(null, result?.relay)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user