Browse Source

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
qrcode-reboot
Matt Raymer 2 days ago
parent
commit
b491262bef
  1. 79
      src/components/ImageMethodDialog.vue

79
src/components/ImageMethodDialog.vue

@ -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&hellip;</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,
);

Loading…
Cancel
Save