-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Fixed]: Scanning modal remains open and blank when camera access is denied (#329) #406
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,86 @@ | ||
<template> | ||
<ion-toolbar> | ||
<ion-buttons slot="end" @click="closeScanner()" > | ||
<ion-button > | ||
<ion-buttons slot="end" @click="closeScanner()"> | ||
<ion-button> | ||
<ion-icon :icon="closeOutline" /> | ||
</ion-button> | ||
</ion-buttons> | ||
</ion-toolbar> | ||
</ion-buttons> | ||
</ion-toolbar> | ||
|
||
<div class="scanner"> | ||
<!-- Conditionally render the "Start Scanning" button based on camera access --> | ||
<ion-button v-if="!hasCameraAccess" @click="openScanner">Start Scanning</ion-button> | ||
|
||
<!-- Load the barcode scanner only if camera access is granted --> | ||
<StreamBarcodeReader | ||
v-if="hasCameraAccess" | ||
@decode="onDecode" | ||
@loaded="onLoaded" | ||
/> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import { StreamBarcodeReader } from "vue-barcode-reader"; | ||
import { IonButton,IonButtons, IonIcon, IonToolbar, modalController } from '@ionic/vue'; | ||
import { IonButton, IonButtons, IonIcon, IonToolbar, modalController, alertController } from '@ionic/vue'; | ||
import { closeOutline } from 'ionicons/icons'; | ||
|
||
export default { | ||
name: 'Scanner', | ||
components: { | ||
IonButton, | ||
IonButtons, | ||
IonIcon, | ||
IonIcon, | ||
IonToolbar, | ||
StreamBarcodeReader, | ||
}, | ||
}, | ||
data() { | ||
return { | ||
hasCameraAccess: false, // Track if the camera access is granted | ||
}; | ||
}, | ||
methods: { | ||
onDecode (result) { | ||
modalController.dismiss({dismissed: true}, result); | ||
// Request camera access when the user interacts | ||
async requestCameraAccess() { | ||
try { | ||
const stream = await navigator.mediaDevices.getUserMedia({ video: true }); | ||
if (stream) { | ||
this.hasCameraAccess = true; // Access granted, show scanner | ||
} | ||
} catch (error) { | ||
console.error('Camera access denied:', error); | ||
this.hasCameraAccess = false; // Access denied, show alert | ||
this.showAlert('Camera permission is denied. Please enable the camera permission in your device settings to use the scanner.'); | ||
} | ||
}, | ||
// Show an alert when camera access is denied | ||
async showAlert(message) { | ||
const alert = await alertController.create({ | ||
header: 'Camera Permission Denied', | ||
message: message, | ||
buttons: ['OK'], | ||
}); | ||
await alert.present(); | ||
}, | ||
// Triggered by user clicking "Start Scanning" button | ||
async openScanner() { | ||
await this.requestCameraAccess(); // Ask for camera access | ||
if (this.hasCameraAccess) { | ||
// Button will automatically disappear and scanner will be displayed | ||
} | ||
}, | ||
onDecode(result) { | ||
modalController.dismiss({ dismissed: true }, result); | ||
}, | ||
closeScanner() { | ||
modalController.dismiss({ dismissed: true }); | ||
}, | ||
closeScanner(){ | ||
modalController.dismiss({dismissed: true}); | ||
} | ||
}, | ||
setup() { | ||
return { | ||
closeOutline | ||
} | ||
} | ||
} | ||
</script> | ||
closeOutline, | ||
}; | ||
}, | ||
}; | ||
</script> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,4 +52,16 @@ const handleDateTimeInput = (dateTimeValue: any) => { | |
return DateTime.fromISO(dateTime).toMillis() | ||
} | ||
|
||
export { handleDateTimeInput, showToast, hasError, copyToClipboard } | ||
const hasCameraAccess = async () => { | ||
try { | ||
const stream = await navigator.mediaDevices.getUserMedia({ video: true }); | ||
if (stream) { | ||
showToast(translate('Camera access granted.')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do not need to display toast when the user has camera permission, because if the camera permission is already provided, then the modal will open up, and then displaying a toast will be a redundant behaviour. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, I think we can remove the stream check from here |
||
} | ||
} catch (error) { | ||
console.error('Camera access denied:', error); | ||
showToast(translate('Camera permission is denied. Please enable the camera permission in your device settings to use the scanner.')); | ||
} | ||
} | ||
|
||
export { handleDateTimeInput, showToast, hasError, copyToClipboard, hasCameraAccess } |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -190,6 +190,7 @@ import LocationPopover from '@/components/LocationPopover.vue' | |
import ImageModal from '@/components/ImageModal.vue'; | ||
import { copyToClipboard, hasError, showToast } from '@/utils'; | ||
import { Actions, hasPermission } from '@/authorization' | ||
import { hasCameraAccess } from '@/utils/'; | ||
|
||
export default defineComponent({ | ||
name: "PurchaseOrderDetails", | ||
|
@@ -249,6 +250,10 @@ export default defineComponent({ | |
return imageModal.present(); | ||
}, | ||
async scan() { | ||
if (!hasCameraAccess()) { | ||
showToast(translate("Camera access is required to scan items.")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as ReturnDetails. |
||
return; | ||
} | ||
const modal = await modalController | ||
.create({ | ||
component: Scanner, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,7 @@ import ImageModal from '@/components/ImageModal.vue'; | |
import { hasError } from '@/utils'; | ||
import { showToast } from '@/utils' | ||
import { Actions, hasPermission } from '@/authorization' | ||
import { hasCameraAccess } from '@/utils'; | ||
|
||
export default defineComponent({ | ||
name: "ReturnDetails", | ||
|
@@ -268,6 +269,10 @@ export default defineComponent({ | |
this.queryString = '' | ||
}, | ||
async scanCode () { | ||
if (!hasCameraAccess()) { | ||
showToast(translate("Camera access is required to scan items.")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we are having a toast message in the |
||
return; | ||
} | ||
const modal = await modalController | ||
.create({ | ||
component: Scanner, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need to make any change in this component, because once we have added the check of camera access in the parent component then this component will not open and thus there is no use of having any checks in this component.