@ -1,6 +1,37 @@
< template >
< template >
< div v-if ="visible" class="dialog-overlay z-[60]" >
< div v-if ="visible" class="dialog-overlay z-[60]" >
< div class = "dialog relative" >
< 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" >
< div class = "text-lg text-center font-bold relative" >
< h1 id = "ViewHeading" class = "text-center font-bold" >
< h1 id = "ViewHeading" class = "text-center font-bold" >
< span v-if ="uploading" > Uploading Image & hellip ; < / span >
< span v-if ="uploading" > Uploading Image & hellip ; < / span >
@ -52,39 +83,10 @@
v - if = "showCameraPreview"
v - if = "showCameraPreview"
class = "camera-preview relative flex bg-black overflow-hidden mb-4"
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" >
< div class = "camera-container w-full h-full relative" >
< video
< video
ref = "videoElement"
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
autoplay
playsinline
playsinline
muted
muted
@ -312,14 +314,6 @@ export default class ImageMethodDialog extends Vue {
- 1 ,
- 1 ,
) ;
) ;
}
}
/ / T r y t o s t a r t c a m e r a p r e v i e w a u t o m a t i c a l l y i f n o t o n m o b i l e
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 ) {
} catch ( error ) {
logger . error ( "Error starting camera preview:" , 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 . cameraState = 'error' ;
this . cameraStateMessage = errorMessage ;
this . cameraStateMessage = errorMessage ;
this . error = errorMessage ;
this . error = errorMessage ;
@ -475,7 +474,7 @@ export default class ImageMethodDialog extends Vue {
group : "alert" ,
group : "alert" ,
type : "danger" ,
type : "danger" ,
title : "Error" ,
title : "Error" ,
text : "Failed to access camera. Please try again." ,
text : errorMessage ,
} ,
} ,
5000 ,
5000 ,
) ;
) ;