Skip to content

Commit

Permalink
Merge pull request #25 from akopachov/ghi-24
Browse files Browse the repository at this point in the history
Implemented #24
  • Loading branch information
akopachov committed Sep 15, 2023
2 parents d2e7363 + 6fd0be2 commit 9ddcd13
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 66 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@sveltejs/kit": "1.25.0",
"@tailwindcss/forms": "^0.5.6",
"@tailwindcss/typography": "^0.5.10",
"@types/node": "^20.6.0",
"@types/node": "^20.6.1",
"@types/papaparse": "^5.3.8",
"@types/uuid": "^9.0.4",
"@typescript-eslint/eslint-plugin": "^6.7.0",
Expand Down
58 changes: 29 additions & 29 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 98 additions & 0 deletions src/components/camera-qr-scanner/camera-qr-scanner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import { ProgressRadial } from '@skeletonlabs/skeleton';
import QrScanner from 'qr-scanner';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
let videoEl: HTMLVideoElement;
let qrScanner: QrScanner;
const dispatch = createEventDispatcher();
let availableCameraDevices: MediaDeviceInfo[] | null = null;
let selectedCamera: MediaDeviceInfo;
let isScanning = true;
let scannerStartingPromise: Promise<void> | null;
async function startQrScanner(camera: MediaDeviceInfo) {
if (qrScanner && camera) {
if (scannerStartingPromise) {
scannerStartingPromise.then(() => startQrScanner(camera));
return;
}
await qrScanner.setCamera(camera.deviceId);
await qrScanner.start();
scannerStartingPromise = null;
}
}
$: {
if (isScanning) {
startQrScanner(selectedCamera);
} else {
qrScanner?.stop();
}
}
$: {
if (videoEl) {
if (qrScanner) {
qrScanner.stop();
qrScanner.destroy();
}
qrScanner = new QrScanner(
videoEl,
result => {
isScanning = false;
dispatch('scanned', { data: result.data });
},
{
returnDetailedScanResult: true,
highlightScanRegion: true,
},
);
}
}
async function loadCameraDevices() {
let devices = await navigator.mediaDevices.enumerateDevices();
availableCameraDevices = devices.filter(f => f.kind === 'videoinput');
if (availableCameraDevices.length > 0) {
selectedCamera = availableCameraDevices[0];
}
}
export function reset() {
isScanning = true;
}
onMount(() => {
loadCameraDevices();
});
onDestroy(() => {
if (qrScanner) {
qrScanner.destroy();
}
});
</script>

<div class="flex justify-center">
{#if availableCameraDevices && availableCameraDevices.length > 0}
<div class="flex flex-col w-full" class:hidden={!isScanning}>
<select class="select" bind:value={selectedCamera}>
{#each availableCameraDevices as cameraDevice}
<option value={cameraDevice}>{cameraDevice.label}</option>
{/each}
</select>
<!-- svelte-ignore a11y-media-has-caption -->
<video class="w-full mt-3" bind:this={videoEl}></video>
</div>
{:else if availableCameraDevices && availableCameraDevices.length <= 0}
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
<strong class="font-bold">Holy smokes!</strong>
<span class="block sm:inline">There are no available video input devices found.</span>
</div>
{:else}
<ProgressRadial stroke={40} meter="stroke-primary-500" track="stroke-primary-500/30" />
{/if}
</div>
Loading

0 comments on commit 9ddcd13

Please sign in to comment.