mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {View} from 'react-native'
3import ViewShot from 'react-native-view-shot'
4import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker'
5import {createAssetAsync} from 'expo-media-library'
6import * as Sharing from 'expo-sharing'
7import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
8import {msg, Trans} from '@lingui/macro'
9import {useLingui} from '@lingui/react'
10
11import {logger} from '#/logger'
12import {logEvent} from 'lib/statsig/statsig'
13import {isNative, isWeb} from 'platform/detection'
14import * as Toast from '#/view/com/util/Toast'
15import {atoms as a} from '#/alf'
16import {Button, ButtonText} from '#/components/Button'
17import * as Dialog from '#/components/Dialog'
18import {DialogControlProps} from '#/components/Dialog'
19import {Loader} from '#/components/Loader'
20import {QrCode} from '#/components/StarterPack/QrCode'
21
22export function QrCodeDialog({
23 starterPack,
24 link,
25 control,
26}: {
27 starterPack: AppBskyGraphDefs.StarterPackView
28 link?: string
29 control: DialogControlProps
30}) {
31 const {_} = useLingui()
32 const [isProcessing, setIsProcessing] = React.useState(false)
33
34 const ref = React.useRef<ViewShot>(null)
35
36 const getCanvas = (base64: string): Promise<HTMLCanvasElement> => {
37 return new Promise(resolve => {
38 const image = new Image()
39 image.onload = () => {
40 const canvas = document.createElement('canvas')
41 canvas.width = image.width
42 canvas.height = image.height
43
44 const ctx = canvas.getContext('2d')
45 ctx?.drawImage(image, 0, 0)
46 resolve(canvas)
47 }
48 image.src = base64
49 })
50 }
51
52 const onSavePress = async () => {
53 ref.current?.capture?.().then(async (uri: string) => {
54 if (isNative) {
55 const res = await requestMediaLibraryPermissionsAsync()
56
57 if (!res) {
58 Toast.show(
59 _(
60 msg`You must grant access to your photo library to save a QR code`,
61 ),
62 )
63 return
64 }
65
66 // Incase of a FS failure, don't crash the app
67 try {
68 await createAssetAsync(`file://${uri}`)
69 } catch (e: unknown) {
70 Toast.show(
71 _(msg`An error occurred while saving the QR code!`),
72 'xmark',
73 )
74 logger.error('Failed to save QR code', {error: e})
75 return
76 }
77 } else {
78 setIsProcessing(true)
79
80 if (!AppBskyGraphStarterpack.isRecord(starterPack.record)) {
81 return
82 }
83
84 const canvas = await getCanvas(uri)
85 const imgHref = canvas
86 .toDataURL('image/png')
87 .replace('image/png', 'image/octet-stream')
88
89 const link = document.createElement('a')
90 link.setAttribute(
91 'download',
92 `${starterPack.record.name.replaceAll(' ', '_')}_Share_Card.png`,
93 )
94 link.setAttribute('href', imgHref)
95 link.click()
96 }
97
98 logEvent('starterPack:share', {
99 starterPack: starterPack.uri,
100 shareType: 'qrcode',
101 qrShareType: 'save',
102 })
103 setIsProcessing(false)
104 Toast.show(
105 isWeb
106 ? _(msg`QR code has been downloaded!`)
107 : _(msg`QR code saved to your camera roll!`),
108 )
109 control.close()
110 })
111 }
112
113 const onCopyPress = async () => {
114 setIsProcessing(true)
115 ref.current?.capture?.().then(async (uri: string) => {
116 const canvas = await getCanvas(uri)
117 // @ts-expect-error web only
118 canvas.toBlob((blob: Blob) => {
119 const item = new ClipboardItem({'image/png': blob})
120 navigator.clipboard.write([item])
121 })
122
123 logEvent('starterPack:share', {
124 starterPack: starterPack.uri,
125 shareType: 'qrcode',
126 qrShareType: 'copy',
127 })
128 Toast.show(_(msg`QR code copied to your clipboard!`))
129 setIsProcessing(false)
130 control.close()
131 })
132 }
133
134 const onSharePress = async () => {
135 ref.current?.capture?.().then(async (uri: string) => {
136 control.close(() => {
137 Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then(
138 () => {
139 logEvent('starterPack:share', {
140 starterPack: starterPack.uri,
141 shareType: 'qrcode',
142 qrShareType: 'share',
143 })
144 },
145 )
146 })
147 })
148 }
149
150 return (
151 <Dialog.Outer control={control}>
152 <Dialog.Handle />
153 <Dialog.ScrollableInner
154 label={_(msg`Create a QR code for a starter pack`)}>
155 <View style={[a.flex_1, a.align_center, a.gap_5xl]}>
156 {!link ? (
157 <View style={[a.align_center, a.p_xl]}>
158 <Loader size="xl" />
159 </View>
160 ) : (
161 <>
162 <QrCode starterPack={starterPack} link={link} ref={ref} />
163 {isProcessing ? (
164 <View>
165 <Loader size="xl" />
166 </View>
167 ) : (
168 <View
169 style={[a.w_full, a.gap_md, isWeb && [a.flex_row_reverse]]}>
170 <Button
171 label={_(msg`Copy QR code`)}
172 variant="solid"
173 color="secondary"
174 size="small"
175 onPress={isWeb ? onCopyPress : onSharePress}>
176 <ButtonText>
177 {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>}
178 </ButtonText>
179 </Button>
180 <Button
181 label={_(msg`Save QR code`)}
182 variant="solid"
183 color="secondary"
184 size="small"
185 onPress={onSavePress}>
186 <ButtonText>
187 <Trans>Save</Trans>
188 </ButtonText>
189 </Button>
190 </View>
191 )}
192 </>
193 )}
194 </View>
195 </Dialog.ScrollableInner>
196 </Dialog.Outer>
197 )
198}