Uses the new nostrnwc deep link for connections

This commit is contained in:
Vitor Pamplona
2025-10-24 17:53:31 -04:00
parent a157c60697
commit 67e3b05a42
6 changed files with 71 additions and 28 deletions

View File

@@ -89,6 +89,7 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nostr" /> <data android:scheme="nostr" />
<data android:scheme="amethyst" />
</intent-filter> </intent-filter>
<intent-filter android:label="Amethyst"> <intent-filter android:label="Amethyst">
@@ -103,6 +104,7 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nostrwalletconnect" /> <data android:scheme="nostrwalletconnect" />
<data android:scheme="nostr+walletconnect" /> <data android:scheme="nostr+walletconnect" />
<data android:scheme="amethyst+walletconnect" />
</intent-filter> </intent-filter>
<intent-filter android:label="New Post"> <intent-filter android:label="New Post">

View File

@@ -50,6 +50,7 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.Log
import com.vitorpamplona.quartz.utils.UriParser
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -126,20 +127,28 @@ class MainActivity : AppCompatActivity() {
} }
} }
fun isNotificationRoute(uri: String) = uri.startsWith("notifications", true) || uri.startsWith("nostr:notifications", true)
fun isHashtagRoute(uri: String) = uri.startsWith("hashtag?id=") || uri.startsWith("nostr:hashtag?id=")
fun isWalletConnectRoute(uri: String) = uri.startsWith("dlnwc?value=") || uri.startsWith("amethyst+walletconnect:dlnwc?value=") || uri.startsWith("amethyst+walletconnect://dlnwc?value=")
fun uriToRoute( fun uriToRoute(
uri: String?, uri: String,
account: Account, account: Account,
): Route? = ): Route? {
if (uri?.startsWith("notifications", true) == true || uri?.startsWith("nostr:notifications", true) == true) { if (isNotificationRoute(uri)) {
Route.Notification return Route.Notification
} else { }
if (uri?.startsWith("hashtag?id=") == true || uri?.startsWith("nostr:hashtag?id=") == true) { if (isHashtagRoute(uri)) {
Route.Hashtag(uri.removePrefix("nostr:").removePrefix("hashtag?id=")) return Route.Hashtag(uri.removePrefix("nostr:").removePrefix("hashtag?id="))
} else { }
val nip19 = Nip19Parser.uriToRoute(uri)?.entity
if (nip19 != null) { val nip19 = Nip19Parser.uriToRoute(uri)?.entity
LocalCache.consume(nip19) if (nip19 != null) {
} LocalCache.consume(nip19)
val route =
when (nip19) { when (nip19) {
is NPub -> Route.Profile(nip19.hex) is NPub -> Route.Profile(nip19.hex)
is NProfile -> Route.Profile(nip19.hex) is NProfile -> Route.Profile(nip19.hex)
@@ -175,14 +184,27 @@ fun uriToRoute(
else -> null else -> null
} }
if (route != null) {
return route
} }
?: try {
uri?.let {
Nip47WalletConnect.parse(it)
Route.Nip47NWCSetup(it)
}
} catch (e: Exception) {
if (e is CancellationException) throw e
null
}
} }
if (isWalletConnectRoute(uri)) {
val url = UriParser(uri)
val nip47Uri = url.getQueryParameter("value")
if (nip47Uri != null) {
Nip47WalletConnect.parse(nip47Uri)
return Route.Nip47NWCSetup(nip47Uri)
}
}
try {
Nip47WalletConnect.parse(uri)
return Route.Nip47NWCSetup(uri)
} catch (e: Exception) {
if (e is CancellationException) throw e
}
return null
}

View File

@@ -46,6 +46,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.ContentPaste import androidx.compose.material.icons.outlined.ContentPaste
import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.material.icons.outlined.VisibilityOff
@@ -328,14 +329,19 @@ fun UpdateZapAmountContent(
IconButton( IconButton(
onClick = { onClick = {
onClose() onClose()
runCatching { uri.openUri("https://nwc.getalby.com/apps/new?c=Amethyst") }
try {
uri.openUri("nostrnwc://connect?appname=Amethyst&appicon=https%3A%2F%2Fraw.githubusercontent.com%2Fvitorpamplona%2Famethyst%2Frefs%2Fheads%2Fmain%2Ficon.png&callback=amethyst%2Bwalletconnect%3A%2F%2Fdlnwc")
} catch (_: IllegalArgumentException) {
accountViewModel.toastManager.toast(R.string.couldnt_find_nwc_wallets, R.string.couldnt_find_nwc_wallets_description)
}
}, },
) { ) {
Icon( Icon(
painter = painterRes(R.drawable.alby, 1), imageVector = Icons.Outlined.Add,
contentDescription = stringRes(id = R.string.accessibility_navigate_to_alby), contentDescription = stringRes(id = R.string.connect_to_new_nwc_wallet),
modifier = Size24Modifier, modifier = Size24Modifier,
tint = Color.Unspecified, tint = MaterialTheme.colorScheme.primary,
) )
} }
@@ -352,7 +358,7 @@ fun UpdateZapAmountContent(
}, },
) { ) {
Icon( Icon(
Icons.Outlined.ContentPaste, imageVector = Icons.Outlined.ContentPaste,
contentDescription = stringRes(id = R.string.paste_from_clipboard), contentDescription = stringRes(id = R.string.paste_from_clipboard),
modifier = Size24Modifier, modifier = Size24Modifier,
tint = MaterialTheme.colorScheme.primary, tint = MaterialTheme.colorScheme.primary,

View File

@@ -41,7 +41,9 @@ fun NIP19QrCodeScanner(
) { ) {
SimpleQrCodeScanner { SimpleQrCodeScanner {
try { try {
onScan(uriToRoute(it, accountViewModel.account)) if (it != null) {
onScan(uriToRoute(it, accountViewModel.account))
}
} catch (e: Throwable) { } catch (e: Throwable) {
if (e is CancellationException) throw e if (e is CancellationException) throw e
Log.e("NIP19 Scanner", "Error parsing $it", e) Log.e("NIP19 Scanner", "Error parsing $it", e)

View File

@@ -841,6 +841,17 @@
<string name="invalid_nip47_uri_title">Invalid NIP-47 URI</string> <string name="invalid_nip47_uri_title">Invalid NIP-47 URI</string>
<string name="invalid_nip47_uri_description">The URI %1$s is not a valid NIP-47 login URI.</string> <string name="invalid_nip47_uri_description">The URI %1$s is not a valid NIP-47 login URI.</string>
<string name="connect_to_new_nwc_wallet">Connect to new NWC wallet</string>
<string name="couldnt_find_nwc_wallets">Wallet not found</string>
<string name="couldnt_find_nwc_wallets_description">Amethyst couldn\'t find any wallet apps that support Nostr Wallet Connect (NWC).
\n\nWhat you can do:
\n\t1. Verify NWC Support: Double-check that your preferred wallet app is compatible with Nostr Wallet Connect.
\n\t2. Create Connection: Go to your wallet app and create a new NWC connection.
\n\t3. Link to Amethyst: Your wallet will usually give you three options:
\n\t\t3.1 Automatic Link: A button to automatically open and connect to Amethyst. If so, click that button, open Amethyst and hit save on the new screen.
\n\t\t3.2 Manual Link: A Connection URI you can copy and click the paste icon on this screen to directly input it.
\n\t\t3.3 QR Code: The wallet creates a QR code which you can read from the QR code button in this screen.
</string>
<string name="language_description">For the App\'s Interface</string> <string name="language_description">For the App\'s Interface</string>
<string name="theme_description">Dark, Light or System theme</string> <string name="theme_description">Dark, Light or System theme</string>

View File

@@ -38,7 +38,7 @@ class Nip47WalletConnect {
val url = UriParser(uri) val url = UriParser(uri)
if (url.scheme() != "nostrwalletconnect" && url.scheme() != "nostr+walletconnect") { if (url.scheme() != "nostrwalletconnect" && url.scheme() != "nostr+walletconnect" && url.scheme() != "amethyst+walletconnect") {
throw IllegalArgumentException("Not a Wallet Connect QR Code") throw IllegalArgumentException("Not a Wallet Connect QR Code")
} }