Skip to content

Commit

Permalink
Adjust WalletConnect URI implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink committed Aug 5, 2024
1 parent 94c35f7 commit cedeea4
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 70 deletions.
47 changes: 47 additions & 0 deletions components/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { IconButton } from '@chakra-ui/react'
import CopyIcon from './Icons/CopyIcon'
import { ComponentProps, useRef, useState } from 'react'
import { CheckIcon } from '@chakra-ui/icons'

type CopyButtonProps = {
text: string
} & Partial<ComponentProps<typeof IconButton>>

export default function CopyButton({ text, ...props }: CopyButtonProps) {
const size = '1.75rem'
const checkSize = '1.15rem'

const [showCheck, setShowCheck] = useState(false)
const checkTimeoutRef = useRef<NodeJS.Timeout | null>(null)
const icon = showCheck ? (
<CheckIcon boxSize={checkSize} />
) : (
<CopyIcon boxSize={size} />
)

function onClick() {
navigator.clipboard.writeText(text)
setShowCheck(true)
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current)
}
checkTimeoutRef.current = setTimeout(() => {
setShowCheck(false)
}, 1000)
}

return (
<IconButton
variant={'ghost'}
size={'sm'}
isRound={true}
borderRadius={'full'}
aria-label={'Copy'}
minW={0}
boxSize={size}
icon={icon}
onClick={onClick}
{...props}
></IconButton>
)
}
9 changes: 8 additions & 1 deletion components/Discovery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,14 @@ export default function Discovery() {
}
break
case VIEWS.SCAN_CONNECT:
viewContent = <ScanConnect wallet={selectedWallet} />
viewContent = (
<ScanConnect
wallet={selectedWallet}
onGetWallet={() => {
setCurrentView(VIEWS.GET_WALLET)
}}
/>
)
headerProps = {
title: `Connect to ${selectedWallet.name}`,
onBack: () => setCurrentView(VIEWS.ABOUT_WALLETS),
Expand Down
22 changes: 22 additions & 0 deletions components/Icons/CopyIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createIcon } from '@chakra-ui/react'

export default createIcon({
displayName: 'CopyIcon',
viewBox: '0 0 28 28',
path: [
<path
id="Rectangle 7 (Stroke)"
fillRule="evenodd"
clipRule="evenodd"
d="M14 3.5H20C22.4853 3.5 24.5 5.51472 24.5 8V14C24.5 16.4853 22.4853 18.5 20 18.5H14C11.5147 18.5 9.5 16.4853 9.5 14V8C9.5 5.51472 11.5147 3.5 14 3.5ZM14 6C12.8954 6 12 6.89543 12 8V14C12 15.1046 12.8954 16 14 16H20C21.1046 16 22 15.1046 22 14V8C22 6.89543 21.1046 6 20 6H14Z"
fill="black"
fillOpacity="0.6"
/>,
<path
id="Subtract"
d="M8 9.5C5.51472 9.5 3.5 11.5147 3.5 14V20C3.5 22.4853 5.51472 24.5 8 24.5H14C16.4853 24.5 18.5 22.4853 18.5 20H16C16 21.1046 15.1046 22 14 22H8C6.89543 22 6 21.1046 6 20V14C6 12.8954 6.89543 12 8 12V9.5Z"
fill="black"
fillOpacity="0.6"
/>,
],
})
91 changes: 50 additions & 41 deletions components/QRCode.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Box, Image } from '@chakra-ui/react'
import { memo } from 'react'
import { Box, Flex, Image } from '@chakra-ui/react'
import { Fragment, memo } from 'react'
import QRCodeLib from 'qrcode'
import NextImage, { StaticImageData } from 'next/image'
import { isDataURL } from '../helpers/urls'
import { convertToPixels } from '../helpers/sizes'

type QRCodeProps = {
value: string
Expand All @@ -20,21 +22,43 @@ const QRCode = memo(function QRCode({
errorCorrectionLevel: 'H',
})
const modules1D = qr.modules.data

const modules: boolean[][] = []
const length = Math.sqrt(modules1D.length)

// Check if the module is part of the finder pattern
const isFindingPattern = (x: number, y: number) =>
(x < 8 && (y < 8 || y >= length - 8)) || (x >= length - 8 && y < 8)

// Compute the scale factor so we can determine which modules are behind the image
let isModuleBehindImage: (x: number, y: number) => boolean = () => false
if (image) {
const scaleFactor = length / convertToPixels(size)
const imageViewboxSize = convertToPixels(imageSize) * scaleFactor
const imagePadding = 1
const imageTop = Math.floor((length - imageViewboxSize) / 2 - imagePadding)
const imageBottom = Math.ceil(
imageTop + imageViewboxSize + imagePadding * 2
)
const imageLeft = Math.floor((length - imageViewboxSize) / 2 - imagePadding)
const imageRight = Math.ceil(
imageLeft + imageViewboxSize + imagePadding * 2
)
isModuleBehindImage = (x: number, y: number) => {
return (
x >= imageTop && x < imageBottom && y >= imageLeft && y < imageRight
)
}
}

for (let i = 0; i < length; i++) {
modules.push(
[...modules1D.slice(i * length, (i + 1) * length)].map((bit, j) => {
return bit && !isFindingPattern(i, j)
return bit && !isFindingPattern(i, j) && !isModuleBehindImage(i, j)
})
)
}

// Positions of the finder patterns used for custom rendering
const findingPatternPositions = [
[0, 0],
[0, length - 7],
Expand Down Expand Up @@ -62,20 +86,10 @@ const QRCode = memo(function QRCode({
)}

{findingPatternPositions.map(([x, y]) => (
<>
<rect
key={`${x}-${y}`}
x={x}
y={y}
width={7}
height={7}
fill="black"
rx={2}
ry={2}
/>
<Fragment key={`${x}-${y}`}>
<rect x={x} y={y} width={7} height={7} fill="black" rx={2} ry={2} />

<rect
key={`${x}-${y}-inner`}
x={x + 1}
y={y + 1}
width={5}
Expand All @@ -85,35 +99,30 @@ const QRCode = memo(function QRCode({
ry={1.5}
/>

<rect
key={`${x}-${y}-inner2`}
x={x + 2}
y={y + 2}
width={3}
height={3}
fill="black"
/>
</>
<rect x={x + 2} y={y + 2} width={3} height={3} fill="black" />
</Fragment>
))}
</svg>
<Box
<Flex
position="absolute"
top={`calc(50% - ${imageSize} / 2)`}
left={`calc(50% - ${imageSize} / 2)`}
width={imageSize}
height={imageSize}
bg="white"
top={0}
left={0}
right={0}
bottom={0}
justifyContent="center"
alignItems="center"
>
<Image
as={NextImage}
src={image as any}
alt="QR Code"
layout="fill"
objectFit="contain"
boxSize={imageSize}
borderRadius="lg"
/>
</Box>
{image && (
<Image
as={isDataURL(image as any) ? 'img' : NextImage}
src={image as any}
alt="QR Code"
objectFit="contain"
boxSize={imageSize}
borderRadius="lg"
/>
)}
</Flex>
</Box>
)
})
Expand Down
1 change: 0 additions & 1 deletion components/ViewHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default function ViewHeader({
onClick={onBack}
icon={<BackIcon h="1.125rem" pr="0.15rem" />}
aria-label="Close Modal"
borderRadius="full"
variant="ghost"
isRound={true}
boxSize="1.75rem"
Expand Down
8 changes: 5 additions & 3 deletions components/views/ConnectWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ export default function ConnectWallet({
onConnectQRCode,
wallet,
}: ConnectWalletProps) {
const { walletConnectUri } = useConfig()
const {
walletconnect: { uri },
} = useConfig()
const connectToService = useCallback(
async (service: Service) => {
// WC/RPC is a special case where we need to show a QR code within Discovery
if (service.method === FCL_SERVICE_METHODS.WC && walletConnectUri) {
if (service.method === FCL_SERVICE_METHODS.WC && uri) {
onConnectQRCode()
} else {
fcl.WalletUtils.redirect(service)
}
},
[walletConnectUri, onConnectQRCode],
[uri, onConnectQRCode]
)

const getServiceInfo = (service: Service) => {
Expand Down
55 changes: 42 additions & 13 deletions components/views/ScanConnect.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,59 @@
import { Box, Stack, Text } from '@chakra-ui/react'
import QRCode from 'react-qr-code'
import { Box, Flex, Stack, Text } from '@chakra-ui/react'
import { Wallet } from '../../data/wallets'
import { useConfig } from '../../contexts/ConfigContext'
import QRCode from '../QRCode'
import CopyButton from '../CopyButton'
import HybridButton from '../HybridButton'

interface ScanConnectProps {
wallet: Wallet
onGetWallet: () => void
}

export default function ScanConnect({ wallet }: ScanConnectProps) {
const { walletConnectUri } = useConfig()
export default function ScanConnect({ wallet, onGetWallet }: ScanConnectProps) {
const {
walletconnect: { uri },
} = useConfig()
return (
<Stack flexGrow={1} alignItems="center" spacing={8} padding={4}>
<Text color="gray" fontWeight="bold" maxW="2xs" textAlign="center">
Scan in the {wallet.name} app to connect
</Text>
<Stack
flexGrow={1}
alignItems="center"
spacing={2}
px={5}
pb={5}
justifyContent="space-evenly"
>
<Flex justifyContent="space-between" width="100%" alignItems="center">
<Text textStyle="body2">Scan in the {wallet.name} app to connect</Text>
<CopyButton text={uri} />
</Flex>

<Box
padding={4}
bg="white"
borderRadius="xl"
shadow="md"
padding={3}
borderRadius="0.75rem"
border="1px"
borderColor="gray.200"
>
<QRCode level="M" value={walletConnectUri} size={300} />
<QRCode value={uri} size="20rem" image={wallet.icon} imageSize="5rem" />
</Box>

<Flex width="100%" justifyContent="space-between" alignItems="center">
<Text textStyle="body2">Don't have {wallet.name}?</Text>
<HybridButton
variant="secondary"
size="sm"
ml="auto"
alignSelf="center"
borderRadius="full"
{...(!wallet.installLink
? { href: wallet.website }
: {
onClick: onGetWallet,
})}
>
Get
</HybridButton>
</Flex>
</Stack>
)
}
16 changes: 7 additions & 9 deletions components/views/ScanInstall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default function ScanInstall({ onContinue, wallet }: ScanInstallProps) {
flexGrow={1}
flexShrink={1}
alignItems="center"
justifyContent="space-evenly"
spacing="lg"
px="lg"
pb="lg"
Expand All @@ -21,26 +22,23 @@ export default function ScanInstall({ onContinue, wallet }: ScanInstallProps) {
Scan with your phone to install on iOS or Android
</Text>

<Flex
padding="md"
bg="white"
borderRadius="xl"
shadow="md"
<Box
padding={3}
borderRadius="0.75rem"
border="1px"
borderColor="gray.200"
>
<QRCode value={wallet.installLink?.mobile} size="18.75rem" />
</Flex>
<QRCode value={wallet.installLink?.mobile} size="15rem" />
</Box>

<Button
variant="primary"
size="sm"
onClick={onContinue}
fontWeight="bold"
borderRadius="full"
mt="auto"
>
Continue
Connect to {wallet.name}
</Button>
</Stack>
)
Expand Down
8 changes: 8 additions & 0 deletions helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,11 @@ export const BROWSERS = {
icon: ChromeIcon,
},
} as const

export enum PeerRpcMethod {
EXEC_SERVICE = 'exec_service',
}

export enum LocalRpcMethod {
NOTIFY_WC_URI_UPDATE = 'wc_uri_update',
}
Loading

0 comments on commit cedeea4

Please sign in to comment.