Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add infos about how to connect #110

Merged
merged 2 commits into from
Sep 12, 2024
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
2 changes: 2 additions & 0 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import * as Font from "expo-font";
import { useInfo } from "~/hooks/useInfo";
import { secureStorage } from "~/lib/secureStorage";
import { hasOnboardedKey } from "~/lib/state/appStore";
import { PortalHost } from '@rn-primitives/portal';

const LIGHT_THEME: Theme = {
dark: false,
Expand Down Expand Up @@ -103,6 +104,7 @@ export default function RootLayout() {
<SafeAreaView className="w-full h-full bg-background">
<Stack />
<Toast config={toastConfig} position="bottom" bottomOffset={140} />
<PortalHost />
</SafeAreaView>
</ThemeProvider>
</SWRConfig>
Expand Down
3 changes: 3 additions & 0 deletions components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
CameraOff,
Palette,
Egg,
HelpCircle,
} from "lucide-react-native";
import { cssInterop } from "nativewind";

Expand Down Expand Up @@ -83,6 +84,7 @@ interopIcon(Power);
interopIcon(CameraOff);
interopIcon(Palette);
interopIcon(Egg);
interopIcon(HelpCircle);

export {
AlertCircle,
Expand Down Expand Up @@ -119,4 +121,5 @@ export {
Power,
Palette,
Egg,
HelpCircle,
};
149 changes: 149 additions & 0 deletions components/ui/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import * as DialogPrimitive from '@rn-primitives/dialog';
import * as React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
import { cn } from '~/lib/utils';
import { X } from '../Icons';

const Dialog = DialogPrimitive.Root;

const DialogTrigger = DialogPrimitive.Trigger;

const DialogPortal = DialogPrimitive.Portal;

const DialogClose = DialogPrimitive.Close;

const DialogOverlayWeb = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => {
const { open } = DialogPrimitive.useRootContext();
return (
<DialogPrimitive.Overlay
className={cn(
'z-50 bg-black/80 flex justify-center items-center p-2 absolute top-0 right-0 bottom-0 left-0',
open ? 'web:animate-in web:fade-in-0' : 'web:animate-out web:fade-out-0',
className
)}
{...props}
ref={ref}
/>
);
});

DialogOverlayWeb.displayName = 'DialogOverlayWeb';

const DialogOverlayNative = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, children, ...props }, ref) => {
return (
<DialogPrimitive.Overlay
style={StyleSheet.absoluteFill}
className={cn('z-50 flex bg-black/80 justify-center items-center p-2', className)}
{...props}
ref={ref}
>
<Animated.View entering={FadeIn.duration(150)} exiting={FadeOut.duration(150)}>
<>{children}</>
</Animated.View>
</DialogPrimitive.Overlay>
);
});

DialogOverlayNative.displayName = 'DialogOverlayNative';

const DialogOverlay = Platform.select({
web: DialogOverlayWeb,
default: DialogOverlayNative,
});

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { portalHost?: string }
>(({ className, children, portalHost, ...props }, ref) => {
const { open } = DialogPrimitive.useRootContext();
return (
<DialogPortal hostName={portalHost}>
<DialogOverlay>
<DialogPrimitive.Content
ref={ref}
className={cn(
'z-50 max-w-lg gap-4 border border-border web:cursor-default bg-background p-6 shadow-lg web:duration-200 rounded-lg',
open
? 'web:animate-in web:fade-in-0 web:zoom-in-95'
: 'web:animate-out web:fade-out-0 web:zoom-out-95',
className
)}
{...props}
>
{children}
<DialogPrimitive.Close
className={
'absolute right-4 top-4 p-0.5 web:group rounded-sm opacity-70 web:ring-offset-background web:transition-opacity web:hover:opacity-100 web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 web:disabled:pointer-events-none'
}
>
<X
size={Platform.OS === 'web' ? 16 : 18}
className={cn('text-muted-foreground', open && 'text-accent-foreground')}
/>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogOverlay>
</DialogPortal>
);
});
DialogContent.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) => (
<View className={cn('flex flex-col gap-1.5 text-center sm:text-left', className)} {...props} />
);
DialogHeader.displayName = 'DialogHeader';

const DialogFooter = ({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) => (
<View
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end gap-2', className)}
{...props}
/>
);
DialogFooter.displayName = 'DialogFooter';

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
'text-lg native:text-xl text-foreground font-semibold leading-none tracking-tight',
className
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm native:text-base text-muted-foreground', className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

export {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"@getalby/lightning-tools": "^5.0.3",
"@getalby/sdk": "^3.7.0",
"@react-native-async-storage/async-storage": "1.23.1",
"@rn-primitives/dialog": "^1.0.3",
"@rn-primitives/portal": "^1.0.3",
"bech32": "^2.0.0",
"buffer": "^6.0.3",
"class-variance-authority": "^0.7.0",
Expand Down
10 changes: 5 additions & 5 deletions pages/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ export function Settings() {

return (
<View className="flex-1 flex flex-col p-6 gap-6">
<Screen
title="Settings"
/>
<Screen title="Settings" />
<Link href="/settings/wallets" asChild>
<TouchableOpacity className="flex flex-row items-center gap-4">
<Wallet2 className="text-foreground" />
Expand Down Expand Up @@ -85,7 +83,7 @@ export function Settings() {
onPress: () => {
router.dismissAll();
useAppStore.getState().reset();
router.replace("/");
router.replace("/onboarding");
},
},
],
Expand Down Expand Up @@ -119,7 +117,9 @@ export function Settings() {
}}
>
<View className="flex-1 flex-col items-center justify-end">
<Text className="text-foreground">Alby Go v{Constants.expoConfig?.version}</Text>
<Text className="text-foreground">
Alby Go v{Constants.expoConfig?.version}
</Text>
</View>
</TouchableOpacity>
</View>
Expand Down
145 changes: 88 additions & 57 deletions pages/settings/wallets/WalletConnection.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Pressable, Text, View } from "react-native";
import { Pressable, Text, TouchableOpacity, View } from "react-native";
import React from "react";
import * as Clipboard from "expo-clipboard";
import { nwc } from "@getalby/sdk";
import { ClipboardPaste, X } from "~/components/Icons";
import { ClipboardPaste, HelpCircle, X } from "~/components/Icons";
import { useAppStore } from "lib/state/appStore";
import { Camera } from "expo-camera/legacy"; // TODO: check if Android camera detach bug is fixed and update camera
import { router } from "expo-router";
Expand All @@ -15,6 +15,7 @@ import { Nip47Capability } from "@getalby/sdk/dist/NWCClient";
import Loading from "~/components/Loading";
import QRCodeScanner from "~/components/QRCodeScanner";
import Screen from "~/components/Screen";
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogClose } from "~/components/ui/dialog";

export function WalletConnection() {
const hasConnection = useAppStore((store) => !!store.nwcClient);
Expand Down Expand Up @@ -102,65 +103,95 @@ export function WalletConnection() {
>
<X className="text-foreground" />
</Pressable>
) : null
) :

<Dialog>
<DialogTrigger asChild>
<TouchableOpacity>
<HelpCircle className="text-foreground" />
</TouchableOpacity>
</DialogTrigger>
<DialogContent className='sm:max-w-[425px]'>
<DialogHeader>
<DialogTitle>Connect Your Wallet</DialogTitle>
<View className="flex flex-col gap-2">
<Text className="text-muted-foreground">Follow these steps to connect Alby Go to your Hub:</Text>
<Text className="text-muted-foreground">1. Open your Alby Hub</Text>
<Text className="text-muted-foreground">2. Go to App Store &raquo; Alby Go</Text>
<Text className="text-muted-foreground">3. Scan the QR code with this app</Text>
</View>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button>
<Text>OK</Text>
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
}
/>
{hasConnection && (
<View className="flex-1 p-3">
<View className="flex-1 h-full flex flex-col items-center justify-center gap-5">
{walletInfo && <Text>Wallet Connected!</Text>}
{!walletInfo && <Text>Loading wallet...</Text>}
{walletInfo ? (
<Text className="self-start justify-self-start">
{JSON.stringify(walletInfo, null, 2)}
</Text>
) : (
<Loading />
{
hasConnection && (
<View className="flex-1 p-3">
<View className="flex-1 h-full flex flex-col items-center justify-center gap-5">
{walletInfo && <Text>Wallet Connected!</Text>}
{!walletInfo && <Text>Loading wallet...</Text>}
{walletInfo ? (
<Text className="self-start justify-self-start">
{JSON.stringify(walletInfo, null, 2)}
</Text>
) : (
<Loading />
)}
{balance && (
<Text className="self-start justify-self-start">
{JSON.stringify(balance, null, 2)}
</Text>
)}
</View>
<Button
variant="destructive"
onPress={() => {
useAppStore.getState().removeNostrWalletConnectUrl();
scan();
}}
>
<Text>Disconnect Wallet</Text>
</Button>
</View>
)
}
{
!hasConnection && (
<>
{isConnecting && (
<>
<View className="flex-1 justify-center items-center">
<Loading />
<Text className="mt-4">Connecting to your Wallet</Text>
</View>
</>
)}
{balance && (
<Text className="self-start justify-self-start">
{JSON.stringify(balance, null, 2)}
</Text>
{!isConnecting && (
<>
<QRCodeScanner onScanned={handleScanned} />
<View className="flex flex-row items-stretch justify-center gap-4 p-6">
<Button
onPress={paste}
variant="secondary"
className="flex-1 flex flex-col gap-2"
>
<ClipboardPaste className="text-secondary-foreground" />
<Text className="text-secondary-foreground">Paste</Text>
</Button>
</View>
</>
)}
</View>
<Button
variant="destructive"
onPress={() => {
useAppStore.getState().removeNostrWalletConnectUrl();
scan();
}}
>
<Text>Disconnect Wallet</Text>
</Button>
</View>
)}
{!hasConnection && (
<>
{isConnecting && (
<>
<View className="flex-1 justify-center items-center">
<Loading />
<Text className="mt-4">Connecting to your Wallet</Text>
</View>
</>
)}
{!isConnecting && (
<>
<QRCodeScanner onScanned={handleScanned} />
<View className="flex flex-row items-stretch justify-center gap-4 p-6">
<Button
onPress={paste}
variant="secondary"
className="flex-1 flex flex-col gap-2"
>
<ClipboardPaste className="text-secondary-foreground" />
<Text className="text-secondary-foreground">Paste</Text>
</Button>
</View>
</>
)}
</>
)}
</>
)
}
</>
);
}
Loading
Loading