Skip to content

Commit

Permalink
Merge pull request #525 from aeternity/feature/fix-qr-code-reader
Browse files Browse the repository at this point in the history
Adapt QrCodeReader for new qr scanner packages
  • Loading branch information
mradkov authored Sep 24, 2020
2 parents 7864624 + e472888 commit 2dd343d
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 113 deletions.
64 changes: 48 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@stamp/it": "^1.1.0",
"@vue/cli-plugin-e2e-cypress": "^3.12.1",
"@vue/cli-service": "^3.12.0",
"@zxing/library": "^0.17.1",
"aepp-raendom": "github:aeternity/aepp-raendom#feature/layout-superhero",
"aeternity-tokens": "^1.0.2",
"axios": "^0.19.0",
Expand All @@ -46,6 +47,7 @@
"cordova-ios": "^5.1.1",
"cordova-plugin-headercolor": "^1.0.0",
"cordova-plugin-inappbrowser": "^3.2.0",
"cordova-plugin-qrscanner": "^3.0.1",
"cordova-plugin-splashscreen": "^5.0.4",
"cordova-plugin-statusbar": "^2.4.3",
"cordova-plugin-wkwebview-engine": "github:mwchambers/cordova-plugin-wkwebview-engine#da67d6bb6ce8597c38fc69e66b84566e34efea8d",
Expand All @@ -60,7 +62,6 @@
"vue": "^2.6.10",
"vue-clipboard2": "^0.3.1",
"vue-i18n": "^8.21.0",
"vue-qrcode-reader": "^2.3.12",
"vue-router": "^3.4.3",
"vue-tour": "^1.5.0",
"vuex": "^3.5.1",
Expand Down Expand Up @@ -130,7 +131,8 @@
"ionic-plugin-deeplinks": {
"URL_SCHEME": "superhero",
"DEEPLINK_HOST": "wallet.superhero.com"
}
},
"cordova-plugin-qrscanner": {}
},
"platforms": [
"android",
Expand Down
10 changes: 5 additions & 5 deletions src/popup/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@
"msg": "Insufficient balance"
}
},
"qrCodeReader": {
"cameraNotAllowed": "ERROR: you need to grant camera access permisson"
},
"cancel": "Cancel",
"confirm": "Confirm"
},
Expand Down Expand Up @@ -566,10 +569,6 @@
"heading": "Privacy Policy",
"content": "Your privacy is important to us. It is Superhero's policy to respect your privacy regarding any information we may collect from you across our website and other sites we own and operate. We don't ask for personal information to provide a service to you. We don't collect and retain any information for providing your requested service. We don’t share any personally identifying information publicly or with third-parties. Our website and browser extension may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies. Your continued use of our website will be regarded as acceptance of our practices around privacy and personal information. If you have any questions about how we handle user data and personal information, feel free to contact us. This policy is effective as of 31 January 2020."
},
"qrCodeReader": {
"backToAccount": "Back to account",
"heading": "Qr Code Scanner"
},
"receive": {
"backToAccount": "Back to account",
"heading": "To receive tokens, provide this address or have the payor scan the QR code below.",
Expand Down Expand Up @@ -645,7 +644,8 @@
"to": "To",
"from": "From",
"txhash": "Transaction Hash",
"home": "Home"
"home": "Home",
"scanAddress": "Scan AE Address"
},
"settings": {
"backToAccount": "Back to account",
Expand Down
155 changes: 155 additions & 0 deletions src/popup/router/components/Modals/QrCodeReader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<template>
<Modal v-if="browserReader || !cameraAllowed" @close="resolve" close>
<template slot="header">{{ title }}</template>
<div class="qr-code-reader" slot="body">
<div v-show="cameraAllowed">
<video v-show="cameraAllowed" ref="qrCodeVideo" />
</div>
<div v-if="!cameraAllowed">
{{ $t('modals.qrCodeReader.cameraNotAllowed') }}
</div>
</div>
</Modal>
</template>

<script>
import { BrowserQRCodeReader } from '@zxing/library/esm5/browser/BrowserQRCodeReader';
import Modal from '../Modal';
import openUrl from '../../../utils/openUrl';
const handleUnknownError = error => console.log(error);
export default {
components: { Modal },
props: {
title: { type: String, required: true },
resolve: { type: Function, required: true },
reject: { type: Function, required: true },
},
data: () => ({
// allow camera while QRScanner is loading to not show cameraNotAllowed before actual check
cameraAllowed: process.env.PLATFORM === 'cordova',
browserReader: !(process.env.PLATFORM === 'cordova') && new BrowserQRCodeReader(),
style: null,
headerText: '',
}),
watch: {
async cameraAllowed(value) {
if (!value) {
this.stopReading();
return;
}
try {
this.resolve(await this.scan());
} catch (error) {
if (error.name === 'NotAllowedError') {
try {
await new Promise((resolve, reject) => {
if (process.env.IS_EXTENSION) {
openUrl(browser.extension.getURL('./popup/CameraRequestPermission.html'));
reject();
}
if (navigator.mediaDevices.getUserMedia)
navigator.mediaDevices
.getUserMedia({ video: true })
.then(resolve)
.catch(reject);
else reject(new Error('Sorry, your browser does not support getUserMedia'));
});
} catch {
this.cameraAllowed = false;
}
return;
}
handleUnknownError(error);
}
},
$route() {
this.resolve();
},
},
async mounted() {
if (process.env.PLATFORM === 'cordova') {
try {
await new Promise((resolve, reject) =>
window.QRScanner.prepare((error, status) =>
!error && status.authorized
? resolve()
: reject(error || new Error('Denied to use the camera')),
),
);
} catch {
this.cameraAllowed = false;
}
this.resolve(await this.scan());
return;
}
const status =
navigator.permissions &&
(await navigator.permissions.query({ name: 'camera' }).catch(error => {
const firefoxExceptionMessage =
"'name' member of PermissionDescriptor 'camera' is not a valid value for enumeration PermissionName.";
if (error.message !== firefoxExceptionMessage) handleUnknownError(error);
return null;
}));
if (status) {
this.cameraAllowed = status.state !== 'denied';
status.onchange = () => {
this.cameraAllowed = status.state !== 'denied';
};
}
this.cameraAllowed = true;
},
beforeDestroy() {
this.stopReading();
},
methods: {
async scan() {
return process.env.PLATFORM === 'cordova'
? new Promise((resolve, reject) => {
window.QRScanner.scan((error, text) =>
!error && text ? resolve(text) : reject(error),
);
window.QRScanner.show();
this.style = document.createElement('style');
this.style.type = 'text/css';
this.style.appendChild(
document.createTextNode(
'html, body, .ae-main { background: transparent !important }',
),
);
document.head.appendChild(this.style);
document.querySelector('.popup').style.display = 'none';
document.querySelector('.header .content div:not(.title)').style.display = 'none';
this.headerText = document.querySelector('.header .title').innerText;
document.querySelector('.header .title').innerText = 'Scan QR';
})
: (
await this.browserReader.decodeFromInputVideoDevice(undefined, this.$refs.qrCodeVideo)
).getText();
},
stopReading() {
if (process.env.PLATFORM === 'cordova') {
if (document.head.contains(this.style)) document.head.removeChild(this.style);
document.querySelector('.popup').style.display = '';
document.querySelector('.header .content div:not(.title)').style.display = 'none';
document.querySelector('.header .title').innerText = this.headerText;
window.QRScanner.destroy();
} else this.browserReader.reset();
},
cancelReading() {
this.stopReading();
this.reject(new Error('Cancelled by user'));
},
},
};
</script>

<style lang="scss">
.qr-code-reader video {
max-width: 70vw;
}
</style>
2 changes: 2 additions & 0 deletions src/popup/router/modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Confirm from './components/Modals/Confirm';
import ErrorLog from './components/Modals/ErrorLog';
import ConfirmTransactionSign from './components/Modals/ConfirmTransactionSign';
import ConfirmRawSign from './components/Modals/ConfirmRawSign';
import QrCodeReader from './components/Modals/QrCodeReader';

export default () => {
registerModal({ name: 'default', component: Default });
Expand All @@ -26,4 +27,5 @@ export default () => {
showInPopupIfWebFrame: true,
});
registerModal({ name: 'confirm-connect', showInPopupIfWebFrame: true });
registerModal({ name: 'read-qr-code', component: QrCodeReader });
};
Loading

1 comment on commit 2dd343d

@davidyuk
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.