forked from trent_larson/crowd-funder-for-time-pwa
Only request camera permissions on user gesture in ImageMethodDialog
- Removed automatic call to startCameraPreview() from mounted() lifecycle hook - Camera preview (and permission prompt) now only starts in open(), triggered by user action - Prevents unnecessary permission prompts on page load and improves UX
This commit is contained in:
@@ -1,6 +1,37 @@
|
||||
<template>
|
||||
<div v-if="visible" class="dialog-overlay z-[60]">
|
||||
<div class="dialog relative">
|
||||
<!-- Diagnostic Panel -->
|
||||
<div
|
||||
v-if="showDiagnostics"
|
||||
class="absolute top-0 left-0 right-0 bg-black/80 text-white text-xs p-2 z-20 overflow-auto max-h-[30vh]"
|
||||
>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<p><strong>Camera State:</strong> {{ cameraState }}</p>
|
||||
<p><strong>State Message:</strong> {{ cameraStateMessage || 'None' }}</p>
|
||||
<p><strong>Error:</strong> {{ error || 'None' }}</p>
|
||||
<p><strong>Preview Active:</strong> {{ showCameraPreview ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>Stream Active:</strong> {{ !!cameraStream ? 'Yes' : 'No' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>Browser:</strong> {{ userAgent }}</p>
|
||||
<p><strong>HTTPS:</strong> {{ isSecureContext ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>MediaDevices:</strong> {{ hasMediaDevices ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>GetUserMedia:</strong> {{ hasGetUserMedia ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>Platform:</strong> {{ platformCapabilities.isMobile ? 'Mobile' : 'Desktop' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toggle Diagnostics Button -->
|
||||
<button
|
||||
@click="toggleDiagnostics"
|
||||
class="absolute top-2 right-2 bg-black/50 text-white px-2 py-1 rounded text-xs z-30"
|
||||
>
|
||||
{{ showDiagnostics ? 'Hide Diagnostics' : 'Show Diagnostics' }}
|
||||
</button>
|
||||
|
||||
<div class="text-lg text-center font-bold relative">
|
||||
<h1 id="ViewHeading" class="text-center font-bold">
|
||||
<span v-if="uploading">Uploading Image…</span>
|
||||
@@ -52,39 +83,10 @@
|
||||
v-if="showCameraPreview"
|
||||
class="camera-preview relative flex bg-black overflow-hidden mb-4"
|
||||
>
|
||||
<!-- Diagnostic Panel -->
|
||||
<div
|
||||
v-if="showDiagnostics"
|
||||
class="absolute top-0 left-0 right-0 bg-black/80 text-white text-xs p-2 pt-8 z-20 overflow-auto max-h-[50vh]"
|
||||
>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<p><strong>Camera State:</strong> {{ cameraState }}</p>
|
||||
<p><strong>State Message:</strong> {{ cameraStateMessage || 'None' }}</p>
|
||||
<p><strong>Error:</strong> {{ error || 'None' }}</p>
|
||||
<p><strong>Preview Active:</strong> {{ showCameraPreview ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>Stream Active:</strong> {{ !!cameraStream ? 'Yes' : 'No' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>Browser:</strong> {{ userAgent }}</p>
|
||||
<p><strong>HTTPS:</strong> {{ isSecureContext ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>MediaDevices:</strong> {{ hasMediaDevices ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>GetUserMedia:</strong> {{ hasGetUserMedia ? 'Yes' : 'No' }}</p>
|
||||
<p><strong>Platform:</strong> {{ platformCapabilities.isMobile ? 'Mobile' : 'Desktop' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggle Diagnostics Button -->
|
||||
<button
|
||||
@click="toggleDiagnostics"
|
||||
class="absolute top-2 right-2 bg-black/50 text-white px-2 py-1 rounded text-xs z-30"
|
||||
>
|
||||
{{ showDiagnostics ? 'Hide Diagnostics' : 'Show Diagnostics' }}
|
||||
</button>
|
||||
<div class="camera-container w-full h-full relative">
|
||||
<video
|
||||
ref="videoElement"
|
||||
class="camera-video w-full h-full portrait:max-h-[40vh] object-cover"
|
||||
class="camera-video w-full h-full object-cover"
|
||||
autoplay
|
||||
playsinline
|
||||
muted
|
||||
@@ -312,14 +314,6 @@ export default class ImageMethodDialog extends Vue {
|
||||
-1,
|
||||
);
|
||||
}
|
||||
// Try to start camera preview automatically if not on mobile
|
||||
if (!this.platformCapabilities.isNativeApp) {
|
||||
this.startCameraPreview();
|
||||
} else {
|
||||
logger.warn("Camera preview not started: running in native app context.");
|
||||
this.cameraState = 'off';
|
||||
this.cameraStateMessage = 'Camera preview not started due to native app context.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,7 +460,12 @@ export default class ImageMethodDialog extends Vue {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error starting camera preview:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to access camera';
|
||||
let errorMessage = error instanceof Error ? error.message : 'Failed to access camera';
|
||||
if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {
|
||||
errorMessage = 'Camera is in use by another application. Please close any other apps or browser tabs using the camera and try again.';
|
||||
} else if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
|
||||
errorMessage = 'Camera access was denied. Please allow camera access in your browser settings.';
|
||||
}
|
||||
this.cameraState = 'error';
|
||||
this.cameraStateMessage = errorMessage;
|
||||
this.error = errorMessage;
|
||||
@@ -475,7 +474,7 @@ export default class ImageMethodDialog extends Vue {
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Failed to access camera. Please try again.",
|
||||
text: errorMessage,
|
||||
},
|
||||
5000,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user