Skip to content

Commit e6a0370

Browse files
committed
feat: update screenScan
1 parent 69e9b31 commit e6a0370

File tree

12 files changed

+96
-152
lines changed

12 files changed

+96
-152
lines changed

packages/neuron-ui/src/components/ScreenScanDialog/index.tsx

Lines changed: 31 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,62 @@
1-
import React, { useEffect, useRef, useMemo, useState } from 'react'
1+
import React, { useEffect, useState, useCallback } from 'react'
22
import { captureScreen } from 'services/remote'
3-
import Button from 'widgets/Button'
43
import { isSuccessResponse } from 'utils'
54
import { useTranslation } from 'react-i18next'
6-
import Dialog from 'widgets/Dialog'
75
import AlertDialog from 'widgets/AlertDialog'
6+
import LoadingDialog from 'widgets/LoadingDialog'
87
import jsQR from 'jsqr'
98

10-
import styles from './screenScanDialog.module.scss'
11-
12-
interface Point {
13-
x: number
14-
y: number
15-
}
16-
17-
const ScreenScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm: (result: string) => void }) => {
9+
const ScreenScanDialog = ({ close, onConfirm }: { close: () => void; onConfirm: (result: string[]) => void }) => {
1810
const [t] = useTranslation()
19-
const imgRef = useRef<HTMLImageElement>(null)
20-
const canvasRef = useRef<HTMLCanvasElement>(null)
21-
const canvas2dRef = useRef<CanvasRenderingContext2D>()
22-
const [sources, setSources] = useState<Controller.CaptureScreenSource[]>([])
23-
const [selectId, setSelectId] = useState('')
24-
const [dialogType, setDialogType] = useState<'' | 'access-fail' | 'scan'>('')
25-
const [uri, setUri] = useState('')
11+
const [dialogType, setDialogType] = useState<'' | 'scanning' | 'access-fail'>('')
2612

27-
const drawLine = (begin: Point, end: Point) => {
28-
if (!canvas2dRef.current) return
29-
canvas2dRef.current.beginPath()
30-
canvas2dRef.current.moveTo(begin.x, begin.y)
31-
canvas2dRef.current.lineTo(end.x, end.y)
32-
canvas2dRef.current.lineWidth = 4
33-
canvas2dRef.current.strokeStyle = '#00c891'
34-
canvas2dRef.current.stroke()
35-
}
13+
const handleScanResult = useCallback(async (sources: Controller.CaptureScreenSource[]) => {
14+
const uriList = [] as string[]
3615

37-
const source = useMemo(() => sources.find(item => item.id === selectId), [selectId, sources])
16+
const callArr = sources.map(async item => {
17+
const image = new Image()
18+
image.src = item.dataUrl
19+
await new Promise(resolve => {
20+
image.addEventListener('load', resolve)
21+
})
3822

39-
useEffect(() => {
40-
if (!source) return
41-
42-
if (imgRef.current) {
43-
const { width, height } = imgRef.current
44-
canvasRef.current?.setAttribute('height', `${height}px`)
45-
canvasRef.current?.setAttribute('width', `${width}px`)
46-
const canvas2d = canvasRef.current?.getContext('2d')
47-
if (canvas2d) {
48-
canvas2d.drawImage(imgRef.current, 0, 0, width, height)
49-
50-
canvas2dRef.current = canvas2d
51-
const imageData = canvas2d.getImageData(0, 0, width, height)
52-
const code = jsQR(imageData.data, imageData.width, imageData.height, {
23+
const canvas = document.createElement('canvas')
24+
canvas.width = image.width
25+
canvas.height = image.height
26+
const context = canvas.getContext('2d')
27+
if (context) {
28+
context.imageSmoothingEnabled = false
29+
context.drawImage(image, 0, 0)
30+
const imageData = context.getImageData(0, 0, image.width, image.height)
31+
const code = jsQR(imageData.data, image.width, image.height, {
5332
inversionAttempts: 'dontInvert',
5433
})
55-
5634
if (code?.data) {
57-
drawLine(code.location.topLeftCorner, code.location.topRightCorner)
58-
drawLine(code.location.topRightCorner, code.location.bottomRightCorner)
59-
drawLine(code.location.bottomRightCorner, code.location.bottomLeftCorner)
60-
drawLine(code.location.bottomLeftCorner, code.location.topLeftCorner)
61-
setUri(code.data)
35+
uriList.push(code.data)
6236
}
6337
}
64-
}
65-
}, [source])
38+
})
39+
40+
await Promise.all(callArr)
41+
42+
onConfirm(uriList)
43+
}, [])
6644

6745
useEffect(() => {
6846
captureScreen().then(res => {
6947
if (isSuccessResponse(res)) {
70-
setDialogType('scan')
48+
setDialogType('scanning')
7149
const result = res.result as Controller.CaptureScreenSource[]
72-
setSources(result)
73-
if (result.length) {
74-
setSelectId(result[0].id)
75-
}
50+
handleScanResult(result)
7651
} else {
7752
setDialogType('access-fail')
7853
}
7954
})
8055
}, [])
8156

82-
const handleSelect = (e: React.SyntheticEvent<HTMLButtonElement>) => {
83-
const { idx = '' } = e.currentTarget.dataset
84-
if (idx !== selectId) {
85-
setSelectId(idx)
86-
setUri('')
87-
}
88-
}
89-
90-
const handleConfirm = () => {
91-
onConfirm(uri)
92-
}
93-
9457
return (
9558
<>
96-
<Dialog
97-
show={dialogType === 'scan'}
98-
title={t('wallet-connect.scan-qrcode')}
99-
onCancel={close}
100-
disabled={!uri}
101-
onConfirm={handleConfirm}
102-
className={styles.scanDialog}
103-
>
104-
<div className={styles.container}>
105-
<div className={styles.chooseBox}>
106-
{sources.map(({ dataUrl, id }) => (
107-
<Button
108-
key={id}
109-
className={styles.chooseItem}
110-
data-idx={id}
111-
data-active={selectId === id}
112-
onClick={handleSelect}
113-
>
114-
<img src={dataUrl} alt="" />
115-
</Button>
116-
))}
117-
</div>
118-
<div className={styles.scanBox}>
119-
<canvas ref={canvasRef} />
120-
{source ? <img ref={imgRef} src={source?.dataUrl} alt="" /> : null}
121-
</div>
122-
</div>
123-
</Dialog>
59+
<LoadingDialog show={dialogType === 'scanning'} message={t('wallet-connect.scanning')} />
12460

12561
<AlertDialog
12662
show={dialogType === 'access-fail'}

packages/neuron-ui/src/components/ScreenScanDialog/screenScanDialog.module.scss

Lines changed: 0 additions & 48 deletions
This file was deleted.

packages/neuron-ui/src/components/WalletConnect/index.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,31 @@ const WalletConnect = () => {
6060
)
6161

6262
const handleConnect = useCallback(
63-
async (url: string) => {
64-
setDialogType('')
63+
async (url: string | string[]) => {
64+
setDialogType('connecting')
6565
setUri('')
6666

67-
setDialogType('connecting')
67+
const urlArr = typeof url === 'string' ? [url] : url
6868

69-
const res = await onConnect(url)
69+
if (!urlArr.length) {
70+
setDialogType('invalid-qrcode')
71+
return
72+
}
7073

71-
if (isSuccessResponse(res)) {
72-
setDialogType('')
74+
let successFlag = true
75+
const callArr = urlArr.map(async item => {
76+
const res = await onConnect(item)
77+
if (!isSuccessResponse(res)) {
78+
successFlag = false
79+
}
80+
})
81+
82+
await Promise.all(callArr)
83+
84+
if (successFlag) {
85+
setTimeout(() => {
86+
setDialogType('')
87+
}, 2000)
7388
} else {
7489
setDialogType('invalid-qrcode')
7590
}

packages/neuron-ui/src/containers/Navbar/index.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import { createPortal } from 'react-dom'
33
import { useLocation, NavLink, useNavigate } from 'react-router-dom'
44
import { useTranslation } from 'react-i18next'
55
import { NeuronWalletActions, showGlobalAlertDialog, useDispatch, useState as useGlobalState } from 'states'
6-
import { VerifyExternalCkbNodeRes, checkForUpdates, getVersion, verifyExternalCkbNode } from 'services/remote'
6+
import {
7+
VerifyExternalCkbNodeRes,
8+
checkForUpdates,
9+
getVersion,
10+
verifyExternalCkbNode,
11+
getWCState,
12+
} from 'services/remote'
713
import { AppUpdater as AppUpdaterSubject, WalletConnectUpdate as WalletConnectUpdateSubject } from 'services/subjects'
814
import { AppActions } from 'states/stateProvider/reducer'
915
import Badge from 'widgets/Badge'
@@ -115,6 +121,15 @@ const Navbar = () => {
115121
setVerifyCkbResult(res.result)
116122
}
117123
})
124+
125+
getWCState().then(res => {
126+
if (isSuccessResponse(res) && res.result) {
127+
dispatch({
128+
type: AppActions.UpdateWalletConnectState,
129+
payload: res.result,
130+
})
131+
}
132+
})
118133
}, [])
119134

120135
useEffect(() => {

packages/neuron-ui/src/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,7 @@
11601160
"uri-placeholder": "Please input the uri",
11611161
"connect": "Connect",
11621162
"connecting": "Connecting your wallet via WalletConnect now",
1163+
"scanning": "Scanning the QR code in the screen",
11631164
"invalid-qrcode": "Invalid QR code",
11641165
"invalid-qrcode-tip": "Make sure the WalletConnect QR code on the screen/camera feed is valid",
11651166
"connected-session": "Established connections",

packages/neuron-ui/src/locales/zh-tw.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,7 @@
11311131
"uri-placeholder": "請輸入連結碼",
11321132
"connect": "連結",
11331133
"connecting": "正在通過WalletConnect連結你的錢包",
1134+
"scanning": "正在掃描屏幕二維碼",
11341135
"invalid-qrcode": "無效的二維碼",
11351136
"invalid-qrcode-tip": "請確保屏幕上/攝像頭畫面中的WalletConnect二維碼有效",
11361137
"connected-session": "已建立的連結",

packages/neuron-ui/src/locales/zh.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,7 @@
11521152
"uri-placeholder": "请输入连接码",
11531153
"connect": "连接",
11541154
"connecting": "正在通过WalletConnect连接你的钱包",
1155+
"scanning": "正在扫描屏幕二维码",
11551156
"invalid-qrcode": "无效的二维码",
11561157
"invalid-qrcode-tip": "请确保屏幕上/摄像头画面中的WalletConnect二维码有效",
11571158
"connected-session": "已建立的连接",

packages/neuron-ui/src/services/remote/remoteApiWrapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ type Action =
158158
| 'wc-reject-session'
159159
| 'wc-approve-request'
160160
| 'wc-reject-request'
161+
| 'wc-get-state'
161162
| 'ask-camera-access'
162163
| 'capture-screen'
163164

packages/neuron-ui/src/services/remote/walletConnect.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { remoteApi } from './remoteApiWrapper'
33

44
export const connect = remoteApi<string>('wc-connect')
55
export const disconnect = remoteApi<string>('wc-disconnect')
6+
export const getWCState = remoteApi<void>('wc-get-state')
67
export const approveSession = remoteApi<{
78
id: number
89
scriptBases: string[]

packages/neuron-wallet/src/controllers/api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,9 @@ export default class ApiController {
841841
handle('wc-reject-request', async (_, params) => {
842842
return this.#walletConnectController.rejectRequest(params)
843843
})
844+
handle('wc-get-state', async _ => {
845+
return this.#walletConnectController.getState()
846+
})
844847
}
845848

846849
// Register handler, warp and serialize API response

0 commit comments

Comments
 (0)