forked from jsnbuchanan/crowd-funder-for-time-pwa
style: improve code formatting and readability
- Format Vue template attributes and event handlers for better readability - Reorganize component props and event bindings - Improve error handling and state management in QR scanner - Add proper aria labels and accessibility attributes - Refactor camera state handling in WebInlineQRScanner - Clean up promise handling in WebPlatformService - Standardize string quotes to double quotes - Improve component structure and indentation No functional changes, purely code style and maintainability improvements.
This commit is contained in:
@@ -80,7 +80,9 @@ export class WebPlatformService implements PlatformService {
|
||||
*/
|
||||
async takePicture(): Promise<ImageResult> {
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
const hasGetUserMedia = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
|
||||
const hasGetUserMedia = !!(
|
||||
navigator.mediaDevices && navigator.mediaDevices.getUserMedia
|
||||
);
|
||||
|
||||
// If on mobile, use file input with capture attribute (existing behavior)
|
||||
if (isMobile || !hasGetUserMedia) {
|
||||
@@ -113,107 +115,120 @@ export class WebPlatformService implements PlatformService {
|
||||
}
|
||||
|
||||
// Desktop: Use getUserMedia for webcam capture
|
||||
return new Promise(async (resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let stream: MediaStream | null = null;
|
||||
let video: HTMLVideoElement | null = null;
|
||||
let captureButton: HTMLButtonElement | null = null;
|
||||
let overlay: HTMLDivElement | null = null;
|
||||
let cleanup = () => {
|
||||
const cleanup = () => {
|
||||
if (stream) {
|
||||
stream.getTracks().forEach((track) => track.stop());
|
||||
}
|
||||
if (video && video.parentNode) video.parentNode.removeChild(video);
|
||||
if (captureButton && captureButton.parentNode) captureButton.parentNode.removeChild(captureButton);
|
||||
if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
|
||||
if (captureButton && captureButton.parentNode)
|
||||
captureButton.parentNode.removeChild(captureButton);
|
||||
if (overlay && overlay.parentNode)
|
||||
overlay.parentNode.removeChild(overlay);
|
||||
};
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" } });
|
||||
// Create overlay for video and button
|
||||
overlay = document.createElement("div");
|
||||
overlay.style.position = "fixed";
|
||||
overlay.style.top = "0";
|
||||
overlay.style.left = "0";
|
||||
overlay.style.width = "100vw";
|
||||
overlay.style.height = "100vh";
|
||||
overlay.style.background = "rgba(0,0,0,0.8)";
|
||||
overlay.style.display = "flex";
|
||||
overlay.style.flexDirection = "column";
|
||||
overlay.style.justifyContent = "center";
|
||||
overlay.style.alignItems = "center";
|
||||
overlay.style.zIndex = "9999";
|
||||
|
||||
video = document.createElement("video");
|
||||
video.autoplay = true;
|
||||
video.playsInline = true;
|
||||
video.style.maxWidth = "90vw";
|
||||
video.style.maxHeight = "70vh";
|
||||
video.srcObject = stream;
|
||||
overlay.appendChild(video);
|
||||
// Move async operations inside Promise body
|
||||
navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: "user" },
|
||||
})
|
||||
.then((mediaStream) => {
|
||||
stream = mediaStream;
|
||||
// Create overlay for video and button
|
||||
overlay = document.createElement("div");
|
||||
overlay.style.position = "fixed";
|
||||
overlay.style.top = "0";
|
||||
overlay.style.left = "0";
|
||||
overlay.style.width = "100vw";
|
||||
overlay.style.height = "100vh";
|
||||
overlay.style.background = "rgba(0,0,0,0.8)";
|
||||
overlay.style.display = "flex";
|
||||
overlay.style.flexDirection = "column";
|
||||
overlay.style.justifyContent = "center";
|
||||
overlay.style.alignItems = "center";
|
||||
overlay.style.zIndex = "9999";
|
||||
|
||||
captureButton = document.createElement("button");
|
||||
captureButton.textContent = "Capture Photo";
|
||||
captureButton.style.marginTop = "2rem";
|
||||
captureButton.style.padding = "1rem 2rem";
|
||||
captureButton.style.fontSize = "1.2rem";
|
||||
captureButton.style.background = "#2563eb";
|
||||
captureButton.style.color = "white";
|
||||
captureButton.style.border = "none";
|
||||
captureButton.style.borderRadius = "0.5rem";
|
||||
captureButton.style.cursor = "pointer";
|
||||
overlay.appendChild(captureButton);
|
||||
video = document.createElement("video");
|
||||
video.autoplay = true;
|
||||
video.playsInline = true;
|
||||
video.style.maxWidth = "90vw";
|
||||
video.style.maxHeight = "70vh";
|
||||
video.srcObject = stream;
|
||||
overlay.appendChild(video);
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
captureButton = document.createElement("button");
|
||||
captureButton.textContent = "Capture Photo";
|
||||
captureButton.style.marginTop = "2rem";
|
||||
captureButton.style.padding = "1rem 2rem";
|
||||
captureButton.style.fontSize = "1.2rem";
|
||||
captureButton.style.background = "#2563eb";
|
||||
captureButton.style.color = "white";
|
||||
captureButton.style.border = "none";
|
||||
captureButton.style.borderRadius = "0.5rem";
|
||||
captureButton.style.cursor = "pointer";
|
||||
overlay.appendChild(captureButton);
|
||||
|
||||
captureButton.onclick = async () => {
|
||||
try {
|
||||
// Create a canvas to capture the frame
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = video!.videoWidth;
|
||||
canvas.height = video!.videoHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx?.drawImage(video!, 0, 0, canvas.width, canvas.height);
|
||||
canvas.toBlob((blob) => {
|
||||
cleanup();
|
||||
if (blob) {
|
||||
resolve({
|
||||
blob,
|
||||
fileName: `photo_${Date.now()}.jpg`,
|
||||
});
|
||||
} else {
|
||||
reject(new Error("Failed to capture image from webcam"));
|
||||
}
|
||||
}, "image/jpeg", 0.95);
|
||||
} catch (err) {
|
||||
cleanup();
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
cleanup();
|
||||
logger.error("Error accessing webcam:", error);
|
||||
// Fallback to file input
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.onchange = async (e) => {
|
||||
const file = (e.target as HTMLInputElement).files?.[0];
|
||||
if (file) {
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
captureButton.onclick = () => {
|
||||
try {
|
||||
const blob = await this.processImageFile(file);
|
||||
resolve({
|
||||
blob,
|
||||
fileName: file.name || "photo.jpg",
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Error processing fallback image:", error);
|
||||
reject(new Error("Failed to process fallback image"));
|
||||
// Create a canvas to capture the frame
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = video!.videoWidth;
|
||||
canvas.height = video!.videoHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx?.drawImage(video!, 0, 0, canvas.width, canvas.height);
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
cleanup();
|
||||
if (blob) {
|
||||
resolve({
|
||||
blob,
|
||||
fileName: `photo_${Date.now()}.jpg`,
|
||||
});
|
||||
} else {
|
||||
reject(new Error("Failed to capture image from webcam"));
|
||||
}
|
||||
},
|
||||
"image/jpeg",
|
||||
0.95,
|
||||
);
|
||||
} catch (err) {
|
||||
cleanup();
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
reject(new Error("No image selected"));
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
cleanup();
|
||||
logger.error("Error accessing webcam:", error);
|
||||
// Fallback to file input
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.onchange = (e) => {
|
||||
const file = (e.target as HTMLInputElement).files?.[0];
|
||||
if (file) {
|
||||
this.processImageFile(file)
|
||||
.then((blob) => {
|
||||
resolve({
|
||||
blob,
|
||||
fileName: file.name || "photo.jpg",
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error("Error processing fallback image:", error);
|
||||
reject(new Error("Failed to process fallback image"));
|
||||
});
|
||||
} else {
|
||||
reject(new Error("No image selected"));
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user