11<script lang =" ts" >
2- import AppNav from " $lib/fragments/AppNav/AppNav.svelte" ;
3- import { Drawer } from " $lib/ui" ;
4- import * as Button from " $lib/ui/Button" ;
5- import {
6- FlashlightIcon ,
7- Image02Icon ,
8- QrCodeIcon ,
9- } from " @hugeicons/core-free-icons" ;
10- import { HugeiconsIcon } from " @hugeicons/svelte" ;
11- import {
12- Format ,
13- type PermissionState ,
14- type Scanned ,
15- cancel ,
16- checkPermissions ,
17- requestPermissions ,
18- scan ,
19- } from " @tauri-apps/plugin-barcode-scanner" ;
20- import { onDestroy , onMount } from " svelte" ;
21- import type { SVGAttributes } from " svelte/elements" ;
22-
23- const pathProps: SVGAttributes <SVGPathElement > = {
24- stroke: " white" ,
25- " stroke-width" : 7 ,
26- " stroke-linecap" : " round" ,
27- " stroke-linejoin" : " round" ,
28- };
29-
30- let codeScannedDrawerOpen = $state (false );
31- let loggedInDrawerOpen = $state (false );
32- let flashlightOn = $state (false );
33-
34- let scannedData: Scanned | undefined = $state (undefined );
35-
36- let scanning = false ;
37- let loading = false ;
38-
39- let permissions_nullable: PermissionState | null ;
40-
41- async function startScan() {
42- let permissions = await checkPermissions ()
43- .then ((permissions ) => {
44- return permissions ;
45- })
46- .catch (() => {
47- return null ; // possibly return "denied"? or does that imply that the check has been successful, but was actively denied?
48- });
49-
50- // TODO: handle receiving "prompt-with-rationale" (issue: https://github.com/tauri-apps/plugins-workspace/issues/979)
51- if (permissions === " prompt" ) {
52- permissions = await requestPermissions (); // handle in more detail?
53- }
54-
55- permissions_nullable = permissions ;
56-
57- if (permissions === " granted" ) {
58- // Scanning parameters
59- const formats = [Format .QRCode ];
60- const windowed = true ;
61-
62- if (scanning ) return ;
63- scanning = true ;
64- scan ({ formats , windowed })
65- .then ((res ) => {
66- console .log (" Scan result:" , res );
67- scannedData = res ;
68- codeScannedDrawerOpen = true ;
69- })
70- .catch ((error ) => {
71- // TODO: display error to user
72- console .error (" Scan error:" , error );
2+ import AppNav from " $lib/fragments/AppNav/AppNav.svelte" ;
3+ import { Drawer } from " $lib/ui" ;
4+ import * as Button from " $lib/ui/Button" ;
5+ import {
6+ FlashlightIcon ,
7+ Image02Icon ,
8+ QrCodeIcon ,
9+ } from " @hugeicons/core-free-icons" ;
10+ import { HugeiconsIcon } from " @hugeicons/svelte" ;
11+ import {
12+ Format ,
13+ type PermissionState ,
14+ type Scanned ,
15+ cancel ,
16+ checkPermissions ,
17+ requestPermissions ,
18+ scan ,
19+ } from " @tauri-apps/plugin-barcode-scanner" ;
20+ import { onDestroy , onMount } from " svelte" ;
21+ import type { SVGAttributes } from " svelte/elements" ;
22+
23+ const pathProps: SVGAttributes <SVGPathElement > = {
24+ stroke: " white" ,
25+ " stroke-width" : 7 ,
26+ " stroke-linecap" : " round" ,
27+ " stroke-linejoin" : " round" ,
28+ };
29+
30+ let codeScannedDrawerOpen = $state (false );
31+ let loggedInDrawerOpen = $state (false );
32+ let flashlightOn = $state (false );
33+
34+ let scannedData: Scanned | undefined = $state (undefined );
35+
36+ let scanning = false ;
37+ let loading = false ;
38+
39+ let permissions_nullable: PermissionState | null ;
40+
41+ async function startScan() {
42+ let permissions = await checkPermissions ()
43+ .then ((permissions ) => {
44+ return permissions ;
7345 })
74- .finally (() => {
75- scanning = false ;
46+ .catch (() => {
47+ return null ; // possibly return "denied"? or does that imply that the check has been successful, but was actively denied?
7648 });
77- }
7849
79- console .error (" Permission denied or not granted" );
80- // TODO: consider handling GUI for permission denied
81- }
50+ // TODO: handle receiving "prompt-with-rationale" (issue: https://github.com/tauri-apps/plugins-workspace/issues/979)
51+ if (permissions === " prompt" ) {
52+ permissions = await requestPermissions (); // handle in more detail?
53+ }
54+
55+ permissions_nullable = permissions ;
56+
57+ if (permissions === " granted" ) {
58+ // Scanning parameters
59+ const formats = [Format .QRCode ];
60+ const windowed = true ;
61+
62+ if (scanning ) return ;
63+ scanning = true ;
64+ scan ({ formats , windowed })
65+ .then ((res ) => {
66+ console .log (" Scan result:" , res );
67+ scannedData = res ;
68+ codeScannedDrawerOpen = true ;
69+ })
70+ .catch ((error ) => {
71+ // TODO: display error to user
72+ console .error (" Scan error:" , error );
73+ })
74+ .finally (() => {
75+ scanning = false ;
76+ });
77+ }
78+
79+ console .error (" Permission denied or not granted" );
80+ // TODO: consider handling GUI for permission denied
81+ }
8282
83- async function cancelScan() {
84- await cancel ();
85- scanning = false ;
86- }
83+ async function cancelScan() {
84+ await cancel ();
85+ scanning = false ;
86+ }
8787
88- onMount (async () => {
89- startScan ();
90- });
88+ onMount (async () => {
89+ startScan ();
90+ });
9191
92- onDestroy (async () => {
93- await cancelScan ();
94- });
92+ onDestroy (async () => {
93+ await cancelScan ();
94+ });
9595 </script >
9696
9797<AppNav title =" Scan QR Code" titleClasses =" text-white" iconColor =" white" />
9898
99- <svg class =" mx-auto mt-48" width =" 204" height =" 215" viewBox =" 0 0 204 215" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
100- <path d ="M46 4H15C8.92487 4 4 8.92487 4 15V46" {...pathProps }/>
101- <path d ="M158 4H189C195.075 4 200 8.92487 200 15V46" {...pathProps }/>
102- <path d ="M46 211H15C8.92487 211 4 206.075 4 200V169" {...pathProps }/>
103- <path d ="M158 211H189C195.075 211 200 206.075 200 200V169" {...pathProps }/>
99+ <svg
100+ class =" mx-auto mt-48"
101+ width =" 204"
102+ height =" 215"
103+ viewBox =" 0 0 204 215"
104+ fill =" none"
105+ xmlns =" http://www.w3.org/2000/svg"
106+ >
107+ <path d ="M46 4H15C8.92487 4 4 8.92487 4 15V46" {...pathProps } />
108+ <path d ="M158 4H189C195.075 4 200 8.92487 200 15V46" {...pathProps } />
109+ <path d ="M46 211H15C8.92487 211 4 206.075 4 200V169" {...pathProps } />
110+ <path d ="M158 211H189C195.075 211 200 206.075 200 200V169" {...pathProps } />
104111</svg >
105112
106- <h4 class =" text-white font-semibold text-center mt-20" >Point the camera at the code</h4 >
113+ <h4 class =" text-white font-semibold text-center mt-20" >
114+ Point the camera at the code
115+ </h4 >
107116
108- <div class =" fixed bottom-2 left-1/2 -translate-x-1/2 z-10 flex gap-8 justify-center items-center" >
109- <Button .Icon
110- icon ={Image02Icon }
111- bgColor =" white"
112- bgSize =" md"
113- />
117+ <div
118+ class =" fixed bottom-2 left-1/2 -translate-x-1/2 z-10 flex gap-8 justify-center items-center"
119+ >
120+ <Button .Icon icon ={Image02Icon } bgColor =" white" bgSize =" md" />
114121 <Button .Icon
115122 icon ={QrCodeIcon }
116123 bgColor =" white"
117124 bgSize =" lg"
118125 iconSize =" lg"
119- callback ={() => { codeScannedDrawerOpen = true ; }}
126+ callback ={() => {
127+ codeScannedDrawerOpen = true ;
128+ }}
120129 />
121130 <Button .Icon
122- icon ={FlashlightIcon }
131+ icon ={FlashlightIcon }
123132 aria-label =" Toggle flashlight"
124133 bgSize =" md"
125134 iconSize ={32 }
@@ -135,9 +144,15 @@ onDestroy(async () => {
135144 bind:isPaneOpen ={codeScannedDrawerOpen }
136145 class =" flex flex-col gap-4 items-center justify-center"
137146>
138- <div class =" flex justify-center mb-4 relative items-center overflow-hidden bg-gray rounded-xl p-4 h-[72px] w-[72px]" >
139- <div class =" bg-white h-[16px] w-[200px] -rotate-45 absolute top-1" ></div >
140- <div class =" bg-white h-[16px] w-[200px] -rotate-45 absolute bottom-1" ></div >
147+ <div
148+ class =" flex justify-center mb-4 relative items-center overflow-hidden bg-gray rounded-xl p-4 h-[72px] w-[72px]"
149+ >
150+ <div
151+ class =" bg-white h-[16px] w-[200px] -rotate-45 absolute top-1"
152+ ></div >
153+ <div
154+ class =" bg-white h-[16px] w-[200px] -rotate-45 absolute bottom-1"
155+ ></div >
141156 <HugeiconsIcon
142157 size ={40 }
143158 className =" z-10"
@@ -152,22 +167,27 @@ onDestroy(async () => {
152167
153168 <div class =" bg-gray rounded-2xl w-full p-4 mt-4" >
154169 <h4 class =" text-base text-black-700" >Website URL</h4 >
155- <p class ="text-black-700 font-normal underline" >{scannedData ?.content }</p >
170+ <p class =" text-black-700 font-normal underline" >
171+ {scannedData ?.content }
172+ </p >
156173 </div >
157174 <div class =" flex justify-center gap-3 items-center mt-4" >
158175 <Button .Action
159176 variant =" danger-soft"
160177 class =" w-full"
161- callback ={() => { codeScannedDrawerOpen = false ; startScan (); }}
178+ callback ={() => {
179+ codeScannedDrawerOpen = false ;
180+ startScan ();
181+ }}
162182 >
163183 Decline
164184 </Button .Action >
165185 <Button .Action
166186 variant =" solid"
167187 class =" w-full"
168188 callback ={() => {
169- codeScannedDrawerOpen = false
170- loggedInDrawerOpen = true
189+ codeScannedDrawerOpen = false ;
190+ loggedInDrawerOpen = true ;
171191 startScan ();
172192 }}
173193 >
@@ -182,9 +202,15 @@ onDestroy(async () => {
182202 bind:isPaneOpen ={loggedInDrawerOpen }
183203 class =" flex flex-col gap-4 items-center justify-center"
184204>
185- <div class =" flex justify-center mb-4 relative items-center overflow-hidden bg-gray rounded-xl p-4 h-[72px] w-[72px]" >
186- <div class =" bg-white h-[16px] w-[200px] -rotate-45 absolute top-1" ></div >
187- <div class =" bg-white h-[16px] w-[200px] -rotate-45 absolute bottom-1" ></div >
205+ <div
206+ class =" flex justify-center mb-4 relative items-center overflow-hidden bg-gray rounded-xl p-4 h-[72px] w-[72px]"
207+ >
208+ <div
209+ class =" bg-white h-[16px] w-[200px] -rotate-45 absolute top-1"
210+ ></div >
211+ <div
212+ class =" bg-white h-[16px] w-[200px] -rotate-45 absolute bottom-1"
213+ ></div >
188214 <HugeiconsIcon
189215 size ={40 }
190216 className =" z-10"
@@ -201,10 +227,19 @@ onDestroy(async () => {
201227 <Button .Action
202228 variant =" solid"
203229 class =" w-full"
204- callback ={() => { loggedInDrawerOpen = false ; startScan (); }}
230+ callback ={() => {
231+ loggedInDrawerOpen = false ;
232+ startScan ();
233+ }}
205234 >
206235 Close
207236 </Button .Action >
208237 </div >
209238</Drawer >
210239
240+ <style >
241+ :global(body , * :not (button )) {
242+ background-color : #00000000 ;
243+ overflow-y : hidden ;
244+ }
245+ </style >
0 commit comments