From b2980bc176e079dec0a9a14e1a16d8df32e9c803 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Wed, 11 Dec 2024 17:22:43 +0530 Subject: [PATCH 1/5] fix: boostagram types and 0 handling --- pages/Transaction.tsx | 60 ++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/pages/Transaction.tsx b/pages/Transaction.tsx index 4b4cf66..f09d693 100644 --- a/pages/Transaction.tsx +++ b/pages/Transaction.tsx @@ -22,11 +22,11 @@ type Boostagram = { name: string; podcast: string; url: string; - episode?: string; - itemID?: string; - ts?: string; + episode?: string | number; + itemID?: string | number; + ts?: string | number; message?: string; - sender_id: string; + sender_id: string | number; sender_name: string; time: string; action: string; @@ -204,40 +204,30 @@ function TransactionDetailRow(props: { } function PodcastingInfo({ boost }: { boost: Boostagram }) { + const renderDetail = (title: string, content: any) => { + if (content != null && content !== "") { + return ; + } + return null; + }; return ( <> - {boost.message && ( - - )} - {boost.podcast && ( - - )} - {boost.episode && ( - - )} - {boost.action && ( - - )} - {boost.ts && ( - - )} - {boost.value_msat_total && ( - - )} - {boost.sender_name && ( - - )} - {boost.app_name && ( - + {renderDetail("Message", boost.message)} + {renderDetail("Podcast", boost.podcast)} + {renderDetail("Episode", boost.episode)} + {renderDetail("Action", boost.action)} + {renderDetail("Timestamp", boost.ts)} + {renderDetail( + "Total amount", + boost.value_msat_total + ? Math.floor(boost.value_msat_total / 1000) + + (Math.floor(boost.value_msat_total / 1000) === 1 + ? " sat" + : " sats") + : null, )} + {renderDetail("Sender", boost.sender_name)} + {renderDetail("App", boost.app_name)} ); } - -export default PodcastingInfo; From 9a7c00ef23ba52076cb98c2d8b377c9d7e0dfcc3 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Tue, 17 Dec 2024 00:44:43 +0530 Subject: [PATCH 2/5] chore: add comment --- pages/Transaction.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/Transaction.tsx b/pages/Transaction.tsx index f09d693..991cc8f 100644 --- a/pages/Transaction.tsx +++ b/pages/Transaction.tsx @@ -205,6 +205,7 @@ function TransactionDetailRow(props: { function PodcastingInfo({ boost }: { boost: Boostagram }) { const renderDetail = (title: string, content: any) => { + // we want to check if content is not undefined, null or empty string if (content != null && content !== "") { return ; } From 4683576e0840e149cb22ed6744c70c1684ce8408 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Tue, 17 Dec 2024 18:14:05 +0530 Subject: [PATCH 3/5] chore: change content check --- pages/Transaction.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/Transaction.tsx b/pages/Transaction.tsx index 991cc8f..2106467 100644 --- a/pages/Transaction.tsx +++ b/pages/Transaction.tsx @@ -205,8 +205,7 @@ function TransactionDetailRow(props: { function PodcastingInfo({ boost }: { boost: Boostagram }) { const renderDetail = (title: string, content: any) => { - // we want to check if content is not undefined, null or empty string - if (content != null && content !== "") { + if (content === 0 || !!content) { return ; } return null; From e4c0d8b29e4181fba5c3b0fec300891a00ea1c63 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Wed, 18 Dec 2024 14:12:22 +0530 Subject: [PATCH 4/5] feat: support nwc connection urls --- app.json | 2 +- lib/link.ts | 20 +++- pages/settings/Wallets.tsx | 133 ++++++++++++------------- pages/settings/wallets/SetupWallet.tsx | 111 +++++++++++++-------- 4 files changed, 155 insertions(+), 111 deletions(-) diff --git a/app.json b/app.json index f6caee7..8e70276 100644 --- a/app.json +++ b/app.json @@ -3,7 +3,7 @@ "name": "Alby Go", "slug": "alby-mobile", "version": "1.7.2", - "scheme": ["lightning", "bitcoin", "alby"], + "scheme": ["lightning", "bitcoin", "alby", "nostr+walletconnect"], "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "automatic", diff --git a/lib/link.ts b/lib/link.ts index aa5db1f..5dfcb05 100644 --- a/lib/link.ts +++ b/lib/link.ts @@ -2,7 +2,12 @@ import { router } from "expo-router"; import { BOLT11_REGEX } from "./constants"; import { lnurl as lnurlLib } from "./lnurl"; -const SUPPORTED_SCHEMES = ["lightning:", "bitcoin:", "alby:"]; +const SUPPORTED_SCHEMES = [ + "lightning:", + "bitcoin:", + "alby:", + "nostr+walletconnect:", +]; // Register exp scheme for testing during development // https://docs.expo.dev/guides/linking/#creating-urls @@ -22,6 +27,19 @@ export const handleLink = async (url: string) => { if (SUPPORTED_SCHEMES.indexOf(parsedUrl.protocol) > -1) { let { username, hostname, protocol, pathname, search } = parsedUrl; + if (parsedUrl.protocol === "nostr+walletconnect:") { + if (router.canDismiss()) { + router.dismissAll(); + } + console.info("Navigating to wallet setup"); + router.push({ + pathname: "/settings/wallets/setup", + params: { + nwcUrl: protocol + hostname + search, + }, + }); + return; + } if (parsedUrl.protocol === "exp:") { if (!parsedUrl.pathname) { diff --git a/pages/settings/Wallets.tsx b/pages/settings/Wallets.tsx index 9fcd21b..1901068 100644 --- a/pages/settings/Wallets.tsx +++ b/pages/settings/Wallets.tsx @@ -14,76 +14,71 @@ export function Wallets() { const selectedWalletId = useAppStore((store) => store.selectedWalletId); const wallets = useAppStore((store) => store.wallets); return ( - <> - - - - { - const active = item.index === selectedWalletId; + + + + { + const active = item.index === selectedWalletId; - return ( - { - if (item.index !== selectedWalletId) { - useAppStore.getState().setSelectedWalletId(item.index); - router.dismissAll(); - router.navigate("/"); - Toast.show({ - type: "success", - text1: `Switched wallet to ${item.item.name || DEFAULT_WALLET_NAME}`, - position: "top", - }); - } - }} - className={cn( - "flex flex-row items-center justify-between p-6 rounded-2xl border-2", - active ? "border-primary" : "border-transparent", - )} - > - - - - {item.item.name || DEFAULT_WALLET_NAME} - - - {active && ( - - - - - - )} - - ); - }} - /> - - - - + return ( + { + if (item.index !== selectedWalletId) { + useAppStore.getState().setSelectedWalletId(item.index); + router.dismissAll(); + router.navigate("/"); + Toast.show({ + type: "success", + text1: `Switched wallet to ${item.item.name || DEFAULT_WALLET_NAME}`, + position: "top", + }); + } + }} + className={cn( + "flex flex-row items-center justify-between p-6 rounded-2xl border-2", + active ? "border-primary" : "border-transparent", + )} + > + + + + {item.item.name || DEFAULT_WALLET_NAME} + + + {active && ( + + + + + + )} + + ); + }} + /> - + + + + ); } diff --git a/pages/settings/wallets/SetupWallet.tsx b/pages/settings/wallets/SetupWallet.tsx index 8b8b404..8a83b65 100644 --- a/pages/settings/wallets/SetupWallet.tsx +++ b/pages/settings/wallets/SetupWallet.tsx @@ -1,7 +1,7 @@ import { nwc } from "@getalby/sdk"; import { Nip47Capability } from "@getalby/sdk/dist/NWCClient"; import * as Clipboard from "expo-clipboard"; -import { router } from "expo-router"; +import { router, useLocalSearchParams } from "expo-router"; import { useAppStore } from "lib/state/appStore"; import React from "react"; import { Pressable, TouchableOpacity, View } from "react-native"; @@ -28,6 +28,9 @@ import { REQUIRED_CAPABILITIES } from "~/lib/constants"; import { errorToast } from "~/lib/errorToast"; export function SetupWallet() { + const { nwcUrl } = useLocalSearchParams<{ + nwcUrl: string; + }>(); const wallets = useAppStore((store) => store.wallets); const walletIdWithConnection = wallets.findIndex( (wallet) => wallet.nostrWalletConnectUrl, @@ -39,6 +42,7 @@ export function SetupWallet() { const [capabilities, setCapabilities] = React.useState(); const [name, setName] = React.useState(""); + const [startScanning, setStartScanning] = React.useState(false); const handleScanned = (data: string) => { return connect(data); @@ -56,47 +60,55 @@ export function SetupWallet() { connect(nostrWalletConnectUrl); } - async function connect(nostrWalletConnectUrl: string) { - try { - setConnecting(true); - // make sure connection is valid - const nwcClient = new nwc.NWCClient({ - nostrWalletConnectUrl, - }); - const info = await nwcClient.getInfo(); - const capabilities = [...info.methods] as Nip47Capability[]; - if (info.notifications?.length) { - capabilities.push("notifications"); - } - if ( - !REQUIRED_CAPABILITIES.every((capability) => - capabilities.includes(capability), - ) - ) { - const missing = REQUIRED_CAPABILITIES.filter( - (capability) => !capabilities.includes(capability), - ); - throw new Error(`Missing required capabilities: ${missing.join(", ")}`); - } + const connect = React.useCallback( + async (nostrWalletConnectUrl: string): Promise => { + try { + setConnecting(true); + // make sure connection is valid + const nwcClient = new nwc.NWCClient({ + nostrWalletConnectUrl, + }); + const info = await nwcClient.getInfo(); + const capabilities = [...info.methods] as Nip47Capability[]; + if (info.notifications?.length) { + capabilities.push("notifications"); + } + if ( + !REQUIRED_CAPABILITIES.every((capability) => + capabilities.includes(capability), + ) + ) { + const missing = REQUIRED_CAPABILITIES.filter( + (capability) => !capabilities.includes(capability), + ); + throw new Error( + `Missing required capabilities: ${missing.join(", ")}`, + ); + } - console.info("NWC connected", info); + console.info("NWC connected", info); - setNostrWalletConnectUrl(nostrWalletConnectUrl); - setCapabilities(capabilities); - setName(nwcClient.lud16 || ""); + setNostrWalletConnectUrl(nostrWalletConnectUrl); + setCapabilities(capabilities); + setName(nwcClient.lud16 || ""); - Toast.show({ - type: "success", - text1: "Connection successful", - text2: "Please set your wallet name to finish", - position: "top", - }); - } catch (error) { - console.error(error); - errorToast(error); - } - setConnecting(false); - } + Toast.show({ + type: "success", + text1: "Connection successful", + text2: "Please set your wallet name to finish", + position: "top", + }); + setConnecting(false); + return true; + } catch (error) { + console.error(error); + errorToast(error); + } + setConnecting(false); + return false; + }, + [], + ); const addWallet = () => { if (!nostrWalletConnectUrl) { @@ -122,6 +134,22 @@ export function SetupWallet() { router.replace("/"); }; + React.useEffect(() => { + if (nwcUrl) { + (async () => { + const result = await connect(nwcUrl); + // Delay the camera to show the error message + if (!result) { + setTimeout(() => { + setStartScanning(true); + }, 2000); + } + })(); + } else { + setStartScanning(true); + } + }, [connect, nwcUrl]); + return ( <> ) : !nostrWalletConnectUrl ? ( <> - +