Skip to content

Commit

Permalink
Merge pull request #110 from getAlby/feat/connect-to-hub-v2
Browse files Browse the repository at this point in the history
feat: add infos about how to connect
  • Loading branch information
rolznz authored Sep 12, 2024
2 parents fd174fa + 2abcb53 commit a802318
Show file tree
Hide file tree
Showing 7 changed files with 481 additions and 62 deletions.
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.1",
"@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

0 comments on commit a802318

Please sign in to comment.