Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions components/CreateInvoice.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { Nip47Transaction } from "@getalby/sdk";
import * as Clipboard from "expo-clipboard";
import { router } from "expo-router";
import React from "react";
import { Platform, Share, View } from "react-native";
import Toast from "react-native-toast-message";
import { DualCurrencyInput } from "~/components/DualCurrencyInput";
import { CopyIcon, ShareIcon } from "~/components/Icons";
import Loading from "~/components/Loading";
Expand All @@ -13,7 +11,7 @@ import { Text } from "~/components/ui/text";
import { useGetFiatAmount } from "~/hooks/useGetFiatAmount";
import { errorToast } from "~/lib/errorToast";
import { useAppStore } from "~/lib/state/appStore";
import { cn, formatBitcoinAmount } from "~/lib/utils";
import { cn, copyToClipboard, formatBitcoinAmount } from "~/lib/utils";

export function CreateInvoice() {
const getFiatAmount = useGetFiatAmount();
Expand Down Expand Up @@ -53,17 +51,13 @@ export function CreateInvoice() {
})();
}

function copy() {
async function copy() {
const text = invoice;
if (!text) {
errorToast(new Error("Nothing to copy"));
return;
}
Clipboard.setStringAsync(text);
Toast.show({
type: "success",
text1: "Copied to clipboard",
});
await copyToClipboard(text);
}

async function share() {
Expand Down
31 changes: 31 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { sha256 } from "@noble/hashes/sha2.js";
import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/hashes/utils.js";
import { Buffer } from "buffer";
import { clsx, type ClassValue } from "clsx";
import * as Clipboard from "expo-clipboard";
import { getPublicKey, nip19 } from "nostr-tools";
import Toast from "react-native-toast-message";
import { twMerge } from "tailwind-merge";
import { errorToast } from "~/lib/errorToast";
import { BitcoinDisplayFormat } from "~/lib/state/appStore";

export function cn(...inputs: ClassValue[]) {
Expand Down Expand Up @@ -39,6 +42,34 @@ export function safeNpubEncode(hex: string): string | undefined {
}
}

export async function copyToClipboard(
text: string,
successMessage = "Copied to clipboard",
) {
// Clipboard.setStringAsync always resolves to true in iOS and
// android so we don't have to add a catch block for errors
await Clipboard.setStringAsync(text);
Toast.show({
type: "success",
text1: successMessage,
});
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

export async function readClipboardText() {
try {
const text = await Clipboard.getStringAsync();
if (!text) {
errorToast(new Error("Your clipboard is empty."));
return undefined;
}
return text;
} catch (error) {
console.error("Failed to read clipboard", error);
errorToast(error, "Failed to read clipboard");
return undefined;
}
}

export function formatBitcoinAmount(
amount: number,
displayFormat: BitcoinDisplayFormat = "bip177",
Expand Down
17 changes: 8 additions & 9 deletions pages/Transaction.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Nip47Transaction, Nip47TransactionMetadata } from "@getalby/sdk";
import { hexToBytes } from "@noble/hashes/utils.js";
import dayjs from "dayjs";
import * as Clipboard from "expo-clipboard";
import { Link, useLocalSearchParams } from "expo-router";
import { nip19 } from "nostr-tools";
import React from "react";
Expand All @@ -12,7 +11,6 @@ import {
TouchableOpacity,
View,
} from "react-native";
import Toast from "react-native-toast-message";
import { LinkIcon } from "~/components/Icons";
import AcceptedTransactionIcon from "~/components/icons/AcceptedTransaction";
import FailedTransactionIcon from "~/components/icons/FailedTransaction";
Expand All @@ -23,7 +21,12 @@ import Screen from "~/components/Screen";
import { Text } from "~/components/ui/text";
import { useGetFiatAmount } from "~/hooks/useGetFiatAmount";
import { BitcoinDisplayFormat, useAppStore } from "~/lib/state/appStore";
import { cn, formatBitcoinAmount, safeNpubEncode } from "~/lib/utils";
import {
cn,
copyToClipboard,
formatBitcoinAmount,
safeNpubEncode,
} from "~/lib/utils";

type TLVRecord = {
type: number;
Expand Down Expand Up @@ -308,12 +311,8 @@ function TransactionDetailRow(props: {
<Text className="w-32 text-secondary-foreground">{props.title}</Text>
<TouchableOpacity
className="flex-1"
onPress={() => {
Clipboard.setStringAsync(props.content);
Toast.show({
type: "success",
text1: "Copied to clipboard",
});
onPress={async () => {
await copyToClipboard(props.content);
}}
>
<Text className={cn("font-medium2 flex-shrink", props.className)}>
Expand Down
11 changes: 3 additions & 8 deletions pages/receive/Receive.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import * as Clipboard from "expo-clipboard";
import { router } from "expo-router";
import React from "react";
import { Share, TouchableOpacity, View } from "react-native";
import Toast from "react-native-toast-message";
import { CreateInvoice } from "~/components/CreateInvoice";
import {
AddressIcon,
Expand All @@ -18,23 +16,20 @@ import { Button } from "~/components/ui/button";
import { Text } from "~/components/ui/text";
import { errorToast } from "~/lib/errorToast";
import { useAppStore } from "~/lib/state/appStore";
import { copyToClipboard } from "~/lib/utils";

export function Receive() {
const selectedWalletId = useAppStore((store) => store.selectedWalletId);
const wallets = useAppStore((store) => store.wallets);
const lightningAddress = wallets[selectedWalletId].lightningAddress;

function copy() {
async function copy() {
const text = lightningAddress;
if (!text) {
errorToast(new Error("Nothing to copy"));
return;
}
Clipboard.setStringAsync(text);
Toast.show({
type: "success",
text1: "Copied to clipboard",
});
await copyToClipboard(text);
}

async function share() {
Expand Down
17 changes: 4 additions & 13 deletions pages/receive/Withdraw.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as Clipboard from "expo-clipboard";
import { router, useLocalSearchParams } from "expo-router";
import {
lnurl as lnurlLib,
Expand All @@ -16,6 +15,7 @@ import { Text } from "~/components/ui/text";
import { WalletSwitcher } from "~/components/WalletSwitcher";
import { errorToast } from "~/lib/errorToast";
import { useAppStore } from "~/lib/state/appStore";
import { readClipboardText } from "~/lib/utils";

export function Withdraw() {
const { url } = useLocalSearchParams<{ url: string }>();
Expand Down Expand Up @@ -57,26 +57,17 @@ export function Withdraw() {
}, [url]);

async function paste() {
let clipboardText;
try {
clipboardText = await Clipboard.getStringAsync();
} catch (error) {
console.error("Failed to read clipboard", error);
return;
const clipboardText = await readClipboardText();
if (clipboardText) {
loadWithdrawal(clipboardText);
}
loadWithdrawal(clipboardText);
}

const handleScanned = (data: string) => {
return loadWithdrawal(data);
};

async function loadWithdrawal(text: string): Promise<boolean> {
if (!text) {
errorToast(new Error("Your clipboard is empty."));
return false;
}

text = text.toLowerCase();

console.info("loading withdrawal", text);
Expand Down
13 changes: 4 additions & 9 deletions pages/send/Address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
BottomSheetTextInput,
BottomSheetView,
} from "@gorhom/bottom-sheet";
import * as Clipboard from "expo-clipboard";
import React, { useCallback, useRef, useState } from "react";
import {
Keyboard,
Expand All @@ -27,7 +26,7 @@ import { Text } from "~/components/ui/text";
import { initiatePaymentFlow } from "~/lib/initiatePaymentFlow";
import { useAppStore } from "~/lib/state/appStore";
import { useThemeColor } from "~/lib/useThemeColor";
import { cn } from "~/lib/utils";
import { cn, readClipboardText } from "~/lib/utils";

interface ContactInputProps {
lnAddress: string;
Expand Down Expand Up @@ -204,14 +203,10 @@ export function Address() {
}, [addressBookEntries, keyboardText]);

const paste = async () => {
let clipboardText;
try {
clipboardText = await Clipboard.getStringAsync();
} catch (error) {
console.error("Failed to read clipboard", error);
return;
const clipboardText = await readClipboardText();
if (clipboardText) {
setKeyboardText(clipboardText);
}
setKeyboardText(clipboardText);
};

return (
Expand Down
17 changes: 4 additions & 13 deletions pages/send/Send.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NWAClient } from "@getalby/sdk/nwc";
import { Camera } from "expo-camera";
import * as Clipboard from "expo-clipboard";
import * as ImagePicker from "expo-image-picker";
import { router, useLocalSearchParams } from "expo-router";
import React from "react";
Expand All @@ -13,6 +12,7 @@ import { Button } from "~/components/ui/button";
import { Text } from "~/components/ui/text";
import { errorToast } from "~/lib/errorToast";
import { initiatePaymentFlow } from "~/lib/initiatePaymentFlow";
import { readClipboardText } from "~/lib/utils";

export function Send() {
const { url, amount } = useLocalSearchParams<{
Expand Down Expand Up @@ -63,26 +63,17 @@ export function Send() {
}

async function paste() {
let clipboardText;
try {
clipboardText = await Clipboard.getStringAsync();
} catch (error) {
console.error("Failed to read clipboard", error);
return;
const clipboardText = await readClipboardText();
if (clipboardText) {
await loadPayment(clipboardText);
}
await loadPayment(clipboardText);
}

const handleScanned = async (data: string) => {
return loadPayment(data);
};

const loadPayment = async (text: string, amount = "") => {
if (!text) {
errorToast(new Error("Your clipboard is empty."));
return false;
}

if (text.startsWith("nostr+walletauth") /* can have : or +alby: */) {
const nwaOptions = NWAClient.parseWalletAuthUrl(text);
router.replace({
Expand Down
14 changes: 6 additions & 8 deletions pages/settings/wallets/EditWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as Clipboard from "expo-clipboard";
import { Link, router, useLocalSearchParams } from "expo-router";
import React, { useState } from "react";
import {
Expand All @@ -25,7 +24,7 @@ import { Text } from "~/components/ui/text";
import { IS_EXPO_GO, REQUIRED_CAPABILITIES } from "~/lib/constants";
import { deregisterWalletNotifications } from "~/lib/notifications";
import { useAppStore } from "~/lib/state/appStore";
import { cn } from "~/lib/utils";
import { cn, copyToClipboard } from "~/lib/utils";

export function EditWallet() {
const { id } = useLocalSearchParams() as { id: string };
Expand Down Expand Up @@ -171,7 +170,7 @@ export function EditWallet() {
},
{
text: "Confirm",
onPress: () => {
onPress: async () => {
const isSuperuser = useAppStore
.getState()
.wallets[
Expand All @@ -195,11 +194,10 @@ export function EditWallet() {
if (!nwcUrl) {
return;
}
Clipboard.setStringAsync(nwcUrl);
Toast.show({
type: "success",
text1: "Connection Secret copied to clipboard",
});
await copyToClipboard(
nwcUrl,
"Connection Secret copied to clipboard",
);
},
},
],
Expand Down
14 changes: 4 additions & 10 deletions pages/settings/wallets/SetupWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { NWCClient, type Nip47Capability } from "@getalby/sdk/nwc";
import * as Clipboard from "expo-clipboard";
import { router, useLocalSearchParams } from "expo-router";
import { useAppStore } from "lib/state/appStore";
import React from "react";
Expand All @@ -23,7 +22,7 @@ import { Text } from "~/components/ui/text";
import { IS_EXPO_GO, REQUIRED_CAPABILITIES } from "~/lib/constants";
import { errorToast } from "~/lib/errorToast";
import { registerWalletNotifications } from "~/lib/notifications";
import { cn } from "~/lib/utils";
import { cn, readClipboardText } from "~/lib/utils";

export function SetupWallet() {
const { nwcUrl: nwcUrlFromSchemeLink } = useLocalSearchParams<{
Expand All @@ -48,15 +47,10 @@ export function SetupWallet() {
};

async function paste() {
let nostrWalletConnectUrl;
try {
nostrWalletConnectUrl = await Clipboard.getStringAsync();
} catch (error) {
console.error("Failed to read clipboard", error);
errorToast(error, "Failed to read clipboard");
return;
const nostrWalletConnectUrl = await readClipboardText();
if (nostrWalletConnectUrl) {
connect(nostrWalletConnectUrl);
}
connect(nostrWalletConnectUrl);
}

const connect = React.useCallback(
Expand Down
Loading