Displays error messages when the URI sent to Amethyst is invalid
This commit is contained in:
Vitor Pamplona 2024-02-12 16:03:37 -05:00
parent bbc4ec2625
commit 1deed59d5b
5 changed files with 83 additions and 23 deletions

View File

@ -39,6 +39,7 @@ import androidx.core.util.Consumer
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.MainActivity import com.vitorpamplona.amethyst.ui.MainActivity
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
@ -359,31 +360,60 @@ fun AppNavigation(
} }
val activity = LocalContext.current.getActivity() val activity = LocalContext.current.getActivity()
var actionableNextPage by remember {
mutableStateOf(uriToRoute(activity.intent?.data?.toString()?.ifBlank { null })) var currentIntentNextPage by remember {
mutableStateOf(activity.intent?.data?.toString()?.ifBlank { null })
} }
actionableNextPage?.let {
LaunchedEffect(it) { currentIntentNextPage?.let { intentNextPage ->
navController.navigate(it) { var actionableNextPage by remember {
popUpTo(Route.Home.route) mutableStateOf(uriToRoute(intentNextPage))
launchSingleTop = true }
}
LaunchedEffect(intentNextPage) {
if (actionableNextPage != null) {
actionableNextPage?.let {
navController.navigate(it) {
popUpTo(Route.Home.route)
launchSingleTop = true
}
actionableNextPage = null
}
} else {
accountViewModel.toast(
R.string.invalid_nip19_uri,
R.string.invalid_nip19_uri_description,
intentNextPage,
)
}
currentIntentNextPage = null
} }
actionableNextPage = null
} }
DisposableEffect(activity) { DisposableEffect(activity) {
val consumer = val consumer =
Consumer<Intent> { intent -> Consumer<Intent> { intent ->
val uri = intent?.data?.toString() val uri = intent?.data?.toString()
val newPage = uriToRoute(uri) if (!uri.isNullOrBlank()) {
val newPage = uriToRoute(uri)
newPage?.let { route -> if (newPage != null) {
val currentRoute = getRouteWithArguments(navController) val currentRoute = getRouteWithArguments(navController)
if (!isSameRoute(currentRoute, route)) { if (!isSameRoute(currentRoute, newPage)) {
navController.navigate(route) { navController.navigate(newPage) {
popUpTo(Route.Home.route) popUpTo(Route.Home.route)
launchSingleTop = true launchSingleTop = true
}
}
} else {
scope.launch {
delay(1000)
accountViewModel.toast(
R.string.invalid_nip19_uri,
R.string.invalid_nip19_uri_description,
uri,
)
} }
} }
} }

View File

@ -105,7 +105,11 @@ import kotlin.time.measureTimedValue
@Immutable class StringToastMsg(val title: String, val msg: String) : ToastMsg() @Immutable class StringToastMsg(val title: String, val msg: String) : ToastMsg()
@Immutable class ResourceToastMsg(val titleResId: Int, val resourceId: Int) : ToastMsg() @Immutable class ResourceToastMsg(
val titleResId: Int,
val resourceId: Int,
val params: Array<out String>? = null,
) : ToastMsg()
@Stable @Stable
class AccountViewModel(val account: Account, val settings: SettingsState) : ViewModel(), Dao { class AccountViewModel(val account: Account, val settings: SettingsState) : ViewModel(), Dao {
@ -141,6 +145,14 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View
viewModelScope.launch { toasts.emit(ResourceToastMsg(titleResId, resourceId)) } viewModelScope.launch { toasts.emit(ResourceToastMsg(titleResId, resourceId)) }
} }
fun toast(
titleResId: Int,
resourceId: Int,
vararg params: String,
) {
viewModelScope.launch { toasts.emit(ResourceToastMsg(titleResId, resourceId, params)) }
}
fun isWriteable(): Boolean { fun isWriteable(): Boolean {
return account.isWriteable() return account.isWriteable()
} }

View File

@ -473,12 +473,22 @@ private fun DisplayErrorMessages(accountViewModel: AccountViewModel) {
openDialogMsg.value?.let { obj -> openDialogMsg.value?.let { obj ->
when (obj) { when (obj) {
is ResourceToastMsg -> is ResourceToastMsg ->
InformationDialog( if (obj.params != null) {
context.getString(obj.titleResId), InformationDialog(
context.getString(obj.resourceId), context.getString(obj.titleResId),
) { context.getString(obj.resourceId, *obj.params),
accountViewModel.clearToasts() ) {
accountViewModel.clearToasts()
}
} else {
InformationDialog(
context.getString(obj.titleResId),
context.getString(obj.resourceId),
) {
accountViewModel.clearToasts()
}
} }
is StringToastMsg -> is StringToastMsg ->
InformationDialog( InformationDialog(
obj.title, obj.title,

View File

@ -753,4 +753,7 @@
<string name="add_content_warning">Add content warning</string> <string name="add_content_warning">Add content warning</string>
<string name="remove_content_warning">Remove content warning</string> <string name="remove_content_warning">Remove content warning</string>
<string name="show_npub_as_a_qr_code">Show npub as a QR code</string> <string name="show_npub_as_a_qr_code">Show npub as a QR code</string>
<string name="invalid_nip19_uri">Invalid address</string>
<string name="invalid_nip19_uri_description">Amethyst received a URI to open but that uri was invalid: %1$s</string>
</resources> </resources>

View File

@ -97,7 +97,12 @@ object Nip19 {
"naddr1" -> naddr(bytes) "naddr1" -> naddr(bytes)
else -> null else -> null
} }
parsed?.copy(additionalChars = additionalChars ?: "")
if (parsed?.hex?.isBlank() == true) {
null
} else {
parsed?.copy(additionalChars = additionalChars ?: "")
}
} catch (e: Throwable) { } catch (e: Throwable) {
Log.w("NIP19 Parser", "Issue trying to Decode NIP19 $key: ${e.message}", e) Log.w("NIP19 Parser", "Issue trying to Decode NIP19 $key: ${e.message}", e)
null null