|
|
@ -77,11 +77,24 @@ |
|
|
|
|
|
|
|
<div class="text-center"> |
|
|
|
<h1 class="text-4xl text-center font-light pt-6">Scan Contact Info</h1> |
|
|
|
<qrcode-stream @detect="onScanDetect" @error="onScanError" /> |
|
|
|
<span> |
|
|
|
If you do not see a scanning camera window here, check your camera |
|
|
|
permissions. |
|
|
|
</span> |
|
|
|
<!-- Web QR Code Scanner --> |
|
|
|
<qrcode-stream |
|
|
|
v-if="useQRReader" |
|
|
|
@detect="onScanDetect" |
|
|
|
@error="onScanError" |
|
|
|
/> |
|
|
|
<!-- Mobile Camera Button --> |
|
|
|
<div v-else class="mt-4"> |
|
|
|
<button |
|
|
|
class="bg-blue-500 text-white px-4 py-2 rounded-md" |
|
|
|
@click="openMobileCamera" |
|
|
|
> |
|
|
|
Open Camera |
|
|
|
</button> |
|
|
|
<p class="mt-2 text-sm text-gray-600"> |
|
|
|
If you do not see the camera, check your camera permissions. |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</section> |
|
|
|
</template> |
|
|
@ -91,8 +104,8 @@ import { AxiosError } from "axios"; |
|
|
|
import QRCodeVue3 from "qr-code-generator-vue3"; |
|
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
import { QrcodeStream } from "vue-qrcode-reader"; |
|
|
|
import { useClipboard } from "@vueuse/core"; |
|
|
|
|
|
|
|
import { PlatformServiceFactory } from "../services/PlatformServiceFactory"; |
|
|
|
import { PlatformService } from "../services/PlatformService"; |
|
|
|
import QuickNav from "../components/QuickNav.vue"; |
|
|
|
import UserNameDialog from "../components/UserNameDialog.vue"; |
|
|
|
import { NotificationIface } from "../constants/app"; |
|
|
@ -110,9 +123,15 @@ import { decodeEndorserJwt, ETHR_DID_PREFIX } from "../libs/crypto/vc"; |
|
|
|
import { retrieveAccountMetadata } from "../libs/util"; |
|
|
|
import { Router } from "vue-router"; |
|
|
|
import { logger } from "../utils/logger"; |
|
|
|
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera"; |
|
|
|
|
|
|
|
// Declare global constants |
|
|
|
declare const __USE_QR_READER__: boolean; |
|
|
|
declare const __IS_MOBILE__: boolean; |
|
|
|
|
|
|
|
@Component({ |
|
|
|
components: { |
|
|
|
QrcodeStream, |
|
|
|
QrcodeStream: __USE_QR_READER__ ? QrcodeStream : null, |
|
|
|
QRCodeVue3, |
|
|
|
QuickNav, |
|
|
|
UserNameDialog, |
|
|
@ -121,6 +140,11 @@ import { logger } from "../utils/logger"; |
|
|
|
export default class ContactQRScanShow extends Vue { |
|
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|
|
|
$router!: Router; |
|
|
|
declare $refs: { |
|
|
|
userNameDialog: { |
|
|
|
open: (callback: (name: string) => void) => void; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
activeDid = ""; |
|
|
|
apiServer = ""; |
|
|
@ -131,6 +155,9 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
|
|
|
|
ETHR_DID_PREFIX = ETHR_DID_PREFIX; |
|
|
|
|
|
|
|
private platformService: PlatformService = |
|
|
|
PlatformServiceFactory.getInstance(); |
|
|
|
|
|
|
|
async created() { |
|
|
|
const settings = await retrieveSettingsForActiveAccount(); |
|
|
|
this.activeDid = settings.activeDid || ""; |
|
|
@ -144,19 +171,149 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
if (account) { |
|
|
|
const name = |
|
|
|
(settings.firstName || "") + |
|
|
|
(settings.lastName ? ` ${settings.lastName}` : ""); // lastName is deprecated, pre v 0.1.3 |
|
|
|
(settings.lastName ? ` ${settings.lastName}` : ""); |
|
|
|
|
|
|
|
this.qrValue = await generateEndorserJwtUrlForAccount( |
|
|
|
account, |
|
|
|
!!settings.isRegistered, |
|
|
|
name, |
|
|
|
settings.profileImageUrl, |
|
|
|
settings.profileImageUrl || "", |
|
|
|
false, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// Initialize camera with retry logic |
|
|
|
if (this.useQRReader) { |
|
|
|
await this.initializeCamera(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async initializeCamera(retryCount = 0): Promise<void> { |
|
|
|
try { |
|
|
|
const capabilities = this.platformService.getCapabilities(); |
|
|
|
if (!capabilities.hasCamera) { |
|
|
|
this.danger("No camera available on this device.", "Camera Error"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Check camera permissions |
|
|
|
const hasPermission = await this.checkCameraPermission(); |
|
|
|
if (!hasPermission) { |
|
|
|
this.danger( |
|
|
|
"Camera permission is required to scan QR codes. Please enable camera access in your device settings.", |
|
|
|
"Permission Required" |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// If we get here, camera should be available |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Camera Ready", |
|
|
|
text: "Camera is ready to scan QR codes.", |
|
|
|
}, |
|
|
|
3000 |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
logger.error("Error initializing camera:", error); |
|
|
|
|
|
|
|
// Retry up to 3 times for certain errors |
|
|
|
if (retryCount < 3) { |
|
|
|
const isPermissionError = error instanceof Error && |
|
|
|
(error.message.includes("permission") || |
|
|
|
error.message.includes("NotReadableError")); |
|
|
|
|
|
|
|
if (isPermissionError) { |
|
|
|
// Wait before retrying |
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000)); |
|
|
|
return this.initializeCamera(retryCount + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.danger( |
|
|
|
"Failed to initialize camera. Please check your camera permissions and try again.", |
|
|
|
"Camera Error" |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async checkCameraPermission(): Promise<boolean> { |
|
|
|
try { |
|
|
|
const capabilities = this.platformService.getCapabilities(); |
|
|
|
if (!capabilities.hasCamera) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Try to access camera to check permissions |
|
|
|
await this.platformService.takePicture(); |
|
|
|
return true; |
|
|
|
} catch (error) { |
|
|
|
logger.error("Camera permission check failed:", error); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async openMobileCamera(): Promise<void> { |
|
|
|
try { |
|
|
|
// Check permissions first |
|
|
|
const hasPermission = await this.checkCameraPermission(); |
|
|
|
if (!hasPermission) { |
|
|
|
this.danger( |
|
|
|
"Camera permission is required. Please enable camera access in your device settings.", |
|
|
|
"Permission Required" |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const image = await Camera.getPhoto({ |
|
|
|
quality: 90, |
|
|
|
allowEditing: false, |
|
|
|
resultType: CameraResultType.DataUrl, |
|
|
|
source: CameraSource.Camera, |
|
|
|
}); |
|
|
|
|
|
|
|
if (image.dataUrl) { |
|
|
|
await this.processImageForQRCode(image.dataUrl); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
logger.error("Error taking picture:", error); |
|
|
|
this.danger( |
|
|
|
"Failed to access camera. Please check your camera permissions.", |
|
|
|
"Camera Error" |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
danger(message: string, title: string = "Error", timeout = 5000) { |
|
|
|
async processImageForQRCode(_imageDataUrl: string) { |
|
|
|
try { |
|
|
|
// Here you would implement QR code scanning from the image |
|
|
|
// For example, using jsQR: |
|
|
|
// const image = new Image(); |
|
|
|
// image.src = imageDataUrl; |
|
|
|
// image.onload = () => { |
|
|
|
// const canvas = document.createElement('canvas'); |
|
|
|
// const context = canvas.getContext('2d'); |
|
|
|
// canvas.width = image.width; |
|
|
|
// canvas.height = image.height; |
|
|
|
// context.drawImage(image, 0, 0); |
|
|
|
// const imageData = context.getImageData(0, 0, canvas.width, canvas.height); |
|
|
|
// const code = jsQR(imageData.data, imageData.width, imageData.height); |
|
|
|
// if (code) { |
|
|
|
// this.onScanDetect([{ rawValue: code.data }]); |
|
|
|
// } |
|
|
|
// }; |
|
|
|
} catch (error) { |
|
|
|
logger.error("Error processing image for QR code:", error); |
|
|
|
this.danger( |
|
|
|
"Failed to process the image. Please try again.", |
|
|
|
"Processing Error", |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
danger(message: string, title = "Error", timeout = 5000): void { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
@ -174,131 +331,157 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
*/ |
|
|
|
// Unfortunately, there are not typescript definitions for the qrcode-stream component yet. |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
async onScanDetect(content: any) { |
|
|
|
async onScanDetect(content: any): Promise<void> { |
|
|
|
const url = content[0]?.rawValue; |
|
|
|
if (url) { |
|
|
|
let newContact: Contact; |
|
|
|
try { |
|
|
|
const jwt = getContactJwtFromJwtUrl(url); |
|
|
|
if (!jwt) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "No Contact Info", |
|
|
|
text: "The contact info could not be parsed.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
const { payload } = decodeEndorserJwt(jwt); |
|
|
|
newContact = { |
|
|
|
did: payload.own.did || payload.iss, // ".own.did" is reliable as of v 0.3.49 |
|
|
|
name: payload.own.name, |
|
|
|
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash, |
|
|
|
profileImageUrl: payload.own.profileImageUrl, |
|
|
|
publicKeyBase64: payload.own.publicEncKey, |
|
|
|
registered: payload.own.registered, |
|
|
|
}; |
|
|
|
if (!newContact.did) { |
|
|
|
this.danger("There is no DID.", "Incomplete Contact"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (!isDid(newContact.did)) { |
|
|
|
this.danger("The DID must begin with 'did:'", "Invalid DID"); |
|
|
|
return; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
logger.error("Error parsing QR info:", e); |
|
|
|
this.danger("Could not parse the QR info.", "Read Error"); |
|
|
|
if (!url) { |
|
|
|
this.danger("No QR code detected. Please try again.", "Scan Error"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Validate URL format first |
|
|
|
if (!url.startsWith("http://") && !url.startsWith("https://")) { |
|
|
|
this.danger( |
|
|
|
"Invalid QR code format. Please scan a valid TimeSafari contact QR code.", |
|
|
|
"Invalid Format", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
let newContact: Contact; |
|
|
|
try { |
|
|
|
// Extract JWT from URL |
|
|
|
const jwt = getContactJwtFromJwtUrl(url); |
|
|
|
if (!jwt) { |
|
|
|
this.danger( |
|
|
|
"Could not extract contact information from the QR code. Please try again.", |
|
|
|
"Invalid QR Code", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
await db.open(); |
|
|
|
await db.contacts.add(newContact); |
|
|
|
// Validate JWT format |
|
|
|
if ( |
|
|
|
!jwt.match(/^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/) |
|
|
|
) { |
|
|
|
this.danger( |
|
|
|
"The QR code contains invalid data. Please scan a valid TimeSafari contact QR code.", |
|
|
|
"Invalid Data", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
let addedMessage; |
|
|
|
if (this.activeDid) { |
|
|
|
await this.setVisibility(newContact, true); |
|
|
|
newContact.seesMe = true; // didn't work inside setVisibility |
|
|
|
addedMessage = |
|
|
|
"They were added, and your activity is visible to them."; |
|
|
|
} else { |
|
|
|
addedMessage = "They were added."; |
|
|
|
} |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Contact Added", |
|
|
|
text: addedMessage, |
|
|
|
}, |
|
|
|
3000, |
|
|
|
const { payload } = decodeEndorserJwt(jwt); |
|
|
|
if (!payload) { |
|
|
|
this.danger( |
|
|
|
"Could not decode the contact information. Please try again.", |
|
|
|
"Decode Error", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.isRegistered) { |
|
|
|
if (!this.hideRegisterPromptOnNewContact && !newContact.registered) { |
|
|
|
setTimeout(() => { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Register", |
|
|
|
text: "Do you want to register them?", |
|
|
|
onCancel: async (stopAsking: boolean) => { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
}, |
|
|
|
onNo: async (stopAsking: boolean) => { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
}, |
|
|
|
onYes: async () => { |
|
|
|
await this.register(newContact); |
|
|
|
}, |
|
|
|
promptToStopAsking: true, |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
}, 500); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
logger.error("Error saving contact info:", e); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Contact Error", |
|
|
|
text: "Could not save contact info. Check if it already exists.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
// Validate required fields |
|
|
|
if (!payload.own && !payload.iss) { |
|
|
|
this.danger( |
|
|
|
"Missing required contact information. Please scan a valid TimeSafari contact QR code.", |
|
|
|
"Incomplete Data", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
newContact = { |
|
|
|
did: payload.own?.did || payload.iss, |
|
|
|
name: payload.own?.name, |
|
|
|
nextPubKeyHashB64: payload.own?.nextPublicEncKeyHash, |
|
|
|
profileImageUrl: payload.own?.profileImageUrl, |
|
|
|
publicKeyBase64: payload.own?.publicEncKey, |
|
|
|
registered: payload.own?.registered, |
|
|
|
}; |
|
|
|
|
|
|
|
if (!newContact.did) { |
|
|
|
this.danger( |
|
|
|
"Missing contact identifier. Please scan a valid TimeSafari contact QR code.", |
|
|
|
"Incomplete Contact", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!isDid(newContact.did)) { |
|
|
|
this.danger( |
|
|
|
"Invalid contact identifier format. The identifier must begin with 'did:'.", |
|
|
|
"Invalid Identifier", |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
await db.open(); |
|
|
|
await db.contacts.add(newContact); |
|
|
|
|
|
|
|
let addedMessage; |
|
|
|
if (this.activeDid) { |
|
|
|
await this.setVisibility(newContact, true); |
|
|
|
newContact.seesMe = true; |
|
|
|
addedMessage = "They were added, and your activity is visible to them."; |
|
|
|
} else { |
|
|
|
addedMessage = "They were added."; |
|
|
|
} |
|
|
|
|
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Invalid Contact QR Code", |
|
|
|
text: "No QR code detected with contact information.", |
|
|
|
type: "success", |
|
|
|
title: "Contact Added", |
|
|
|
text: addedMessage, |
|
|
|
}, |
|
|
|
5000, |
|
|
|
3000, |
|
|
|
); |
|
|
|
|
|
|
|
if ( |
|
|
|
this.isRegistered && |
|
|
|
!this.hideRegisterPromptOnNewContact && |
|
|
|
!newContact.registered |
|
|
|
) { |
|
|
|
setTimeout(() => { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Register", |
|
|
|
text: "Do you want to register them?", |
|
|
|
onCancel: async (stopAsking?: boolean) => { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
}, |
|
|
|
onNo: async (stopAsking?: boolean) => { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
}, |
|
|
|
onYes: async () => { |
|
|
|
await this.register(newContact); |
|
|
|
}, |
|
|
|
promptToStopAsking: true, |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
}, 500); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
logger.error("Error processing QR code:", e); |
|
|
|
this.danger( |
|
|
|
"Could not process the QR code. Please make sure you're scanning a valid TimeSafari contact QR code.", |
|
|
|
"Processing Error", |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async setVisibility(contact: Contact, visibility: boolean) { |
|
|
|
async setVisibility(contact: Contact, visibility: boolean): Promise<void> { |
|
|
|
const result = await setVisibilityUtil( |
|
|
|
this.activeDid, |
|
|
|
this.apiServer, |
|
|
@ -314,7 +497,7 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async register(contact: Contact) { |
|
|
|
async register(contact: Contact): Promise<void> { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
@ -364,17 +547,19 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
let userMessage = "There was an error."; |
|
|
|
const serverError = error as AxiosError; |
|
|
|
if (serverError) { |
|
|
|
if (serverError.response?.data?.error?.message) { |
|
|
|
userMessage = serverError.response.data.error.message; |
|
|
|
const responseData = serverError.response?.data as { |
|
|
|
error?: { message?: string }; |
|
|
|
}; |
|
|
|
if (responseData?.error?.message) { |
|
|
|
userMessage = responseData.error.message; |
|
|
|
} else if (serverError.message) { |
|
|
|
userMessage = serverError.message; // Info for the user |
|
|
|
userMessage = serverError.message; |
|
|
|
} else { |
|
|
|
userMessage = JSON.stringify(serverError.toJSON()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
userMessage = error as string; |
|
|
|
} |
|
|
|
// Now set that error for the user to see. |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
@ -388,7 +573,7 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
onScanError(error: any) { |
|
|
|
onScanError(error: any): void { |
|
|
|
logger.error("Scan was invalid:", error); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
@ -401,39 +586,131 @@ export default class ContactQRScanShow extends Vue { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
onCopyUrlToClipboard() { |
|
|
|
//this.onScanDetect([{ rawValue: this.qrValue }]); // good for testing |
|
|
|
useClipboard() |
|
|
|
.copy(this.qrValue) |
|
|
|
.then(() => { |
|
|
|
// console.log("Contact URL:", this.qrValue); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "toast", |
|
|
|
title: "Copied", |
|
|
|
text: "Contact URL was copied to clipboard.", |
|
|
|
}, |
|
|
|
2000, |
|
|
|
); |
|
|
|
async onCopyUrlToClipboard(): Promise<void> { |
|
|
|
try { |
|
|
|
await this.platformService.writeToClipboard(this.qrValue); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "toast", |
|
|
|
title: "Copied", |
|
|
|
text: "Contact URL was copied to clipboard.", |
|
|
|
}, |
|
|
|
2000, |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
logger.error("Error copying to clipboard:", error); |
|
|
|
this.danger("Failed to copy to clipboard", "Error"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async onCopyDidToClipboard(): Promise<void> { |
|
|
|
try { |
|
|
|
await this.platformService.writeToClipboard(this.activeDid); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "info", |
|
|
|
title: "Copied", |
|
|
|
text: "Your DID was copied to the clipboard. Have them paste it in the box on their 'People' screen to add you.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
logger.error("Error copying to clipboard:", error); |
|
|
|
this.danger("Failed to copy to clipboard", "Error"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async copyToClipboard(text: string): Promise<void> { |
|
|
|
try { |
|
|
|
await this.platformService.writeToClipboard(text); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Copied to clipboard", |
|
|
|
text: "The DID has been copied to your clipboard.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: "Failed to copy to clipboard.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async requestCameraPermission(): Promise<void> { |
|
|
|
try { |
|
|
|
const capabilities = this.platformService.getCapabilities(); |
|
|
|
if (capabilities.hasCamera) { |
|
|
|
try { |
|
|
|
await this.platformService.takePicture(); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Camera Access Granted", |
|
|
|
text: "You can now scan QR codes.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Camera Access Denied", |
|
|
|
text: "Please enable camera access in your device settings.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: "Failed to request camera permission.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async onCancel(stopAsking?: boolean) { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
onCopyDidToClipboard() { |
|
|
|
//this.onScanDetect([{ rawValue: this.qrValue }]); // good for testing |
|
|
|
useClipboard() |
|
|
|
.copy(this.activeDid) |
|
|
|
.then(() => { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "info", |
|
|
|
title: "Copied", |
|
|
|
text: "Your DID was copied to the clipboard. Have them paste it in the box on their 'People' screen to add you.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
async onNo(stopAsking?: boolean) { |
|
|
|
if (stopAsking) { |
|
|
|
await db.settings.update(MASTER_SETTINGS_KEY, { |
|
|
|
hideRegisterPromptOnNewContact: stopAsking, |
|
|
|
}); |
|
|
|
this.hideRegisterPromptOnNewContact = stopAsking; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
get useQRReader(): boolean { |
|
|
|
return __USE_QR_READER__; |
|
|
|
} |
|
|
|
|
|
|
|
get isMobile(): boolean { |
|
|
|
return __IS_MOBILE__; |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|