Skip to content
This repository was archived by the owner on Jan 2, 2021. It is now read-only.

Commit 4e9e9cd

Browse files
committed
Added support for ios devices to show capture picture
1 parent ea42e27 commit 4e9e9cd

7 files changed

Lines changed: 340 additions & 147 deletions

File tree

app/css/styles.css

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ video {
266266
box-shadow: 0 9px 46px 8px rgba(0,0,0,.14), 0 11px 15px -7px rgba(0,0,0,.12), 0 24px 38px 3px rgba(0,0,0,.2);
267267
}
268268

269-
.app__dialog h5 {
269+
.app__dialog h5 {
270270
margin-top: 20px;
271271
margin-left: 18px;
272272
font-weight: 500;
@@ -297,7 +297,7 @@ video {
297297
border: 0;
298298
height: 35px;
299299
width: 70px;
300-
font-size: 15px;
300+
font-size: 16px;
301301
background: transparent;
302302
font-weight: 500;
303303
outline: none;
@@ -338,11 +338,14 @@ video {
338338
position: absolute;
339339
bottom: -70px;
340340
font-size: 18px;
341-
left: 0;
342341
right: 0;
343342
text-align: center;
344343
user-select: none;
344+
}
345+
346+
.app__help-text {
345347
display: none;
348+
left: 0;
346349
}
347350

348351
.app__dialog-overlay {
@@ -363,19 +366,24 @@ video {
363366
}
364367

365368
.app__select-photos {
366-
font-size: 19px;
367-
font-weight: 500;
368-
width: 250px;
369-
height: 35px;
370-
line-height: 35px;
371-
margin: 0 auto;
369+
width: 58px;
370+
height: 58px;
372371
cursor: pointer;
373372
position: fixed;
374373
bottom: 20px;
375-
text-transform: uppercase;
374+
right: 20px;
375+
border-radius: 50%;
376+
background-color: #3F51B5;
377+
background-image: url("/images/photo-camera.svg");
378+
background-repeat: no-repeat;
379+
background-size: 26px;
380+
background-position: 16px 15px;
376381
}
377382

378383
.app__select-photos:active {
379-
opacity: 0.9;
380-
transform: scale(0.98);
384+
opacity: 0.8;
385+
}
386+
387+
input[type='file'] {
388+
display: none;
381389
}

app/images/photo-camera.svg

Lines changed: 9 additions & 0 deletions
Loading

app/index.html

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,36 @@
77
<meta name=description content="QR Code Scanner is the fastest and most user-friendly web application.">
88
<meta name="viewport" content="width=device-width,initial-scale=1.0">
99
<meta name="mobile-web-app-capable" content="yes">
10-
<meta name="apple-mobile-web-app-title" content="QR Scanner"/>
10+
<meta name="apple-mobile-web-app-title" content="QR Scanner" />
1111
<meta name="apple-mobile-web-app-status-bar-style" content="#e4e4e4">
1212
<meta name="apple-mobile-web-app-capable" content="yes">
13-
<meta name="application-name" content="QR Scanner"/>
14-
<meta name="msapplication-TileColor" content="#e4e4e4"/>
15-
<meta name="msapplication-TileImage" content="/images/touch/mstile-150x150.png"/>
16-
<meta name="theme-color" content="#fff"/>
17-
<link rel="apple-touch-icon" href="/images/touch/apple-touch-icon.jpg"/>
18-
<link rel="icon" type="image/png" href="/images/touch/favicon-32x32.png" sizes="32x32"/>
19-
<link rel="icon" type="image/png" href="/images/touch/favicon-16x16.png" sizes="16x16"/>
13+
<meta name="application-name" content="QR Scanner" />
14+
<meta name="msapplication-TileColor" content="#e4e4e4" />
15+
<meta name="msapplication-TileImage" content="/images/touch/mstile-150x150.png" />
16+
<meta name="theme-color" content="#fff" />
17+
<link rel="apple-touch-icon" href="/images/touch/apple-touch-icon.jpg" />
18+
<link rel="icon" type="image/png" href="/images/touch/favicon-32x32.png" sizes="32x32" />
19+
<link rel="icon" type="image/png" href="/images/touch/favicon-16x16.png" sizes="16x16" />
2020
<link rel="shortcut icon" href="/images/touch/favicon.ico">
2121
<link rel="manifest" href="/manifest.json">
22+
<link rel="preload" as="script" href="/decoder.min.js">
2223
</head>
2324
<body>
2425
<div class="app__layout">
2526
<!-- Header -->
2627
<header class="app__header">
2728
<span class="app__header-icon" onclick="window.open('https://github.com/code-kotis/barcode-scanner', '_blank', 'toolbar=0,location=0,menubar=0');">
2829
<svg fill="#FFFFFF" height="27" viewBox="0 0 24 24" width="27" xmlns="http://www.w3.org/2000/svg">
29-
<path d="M0 0h24v24H0z" fill="none"/>
30-
<path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"/>
30+
<path d="M0 0h24v24H0z" fill="none" />
31+
<path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"
32+
/>
3133
</svg>
3234
</span>
3335
</header>
34-
36+
3537
<main class="app__layout-content">
3638
<video autoplay></video>
37-
39+
3840
<!-- Dialog -->
3941
<div class="app__dialog app__dialog--hide">
4042
<div class="app__dialog-content">
@@ -57,16 +59,18 @@ <h5>QR Code</h5>
5759
<div class="app__overlay-frame"></div>
5860
<!-- Scanner animation -->
5961
<div class="custom-scanner"></div>
60-
<div class="app__help-text">Point your camera at a QR Code</div>
61-
<div class="app__select-photos">Select from photos</div>
62+
<div class="app__help-text">Your browser doesn't support Camera API</div>
63+
<div class="app__select-photos"></div>
6264
</div>
63-
65+
6466
<script>
6567
if (location.hostname !== "localhost") {
66-
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
67-
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
68-
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
69-
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
68+
(function (i, s, o, g, r, a, m) {
69+
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
70+
(i[r].q = i[r].q || []).push(arguments)
71+
}, i[r].l = 1 * new Date(); a = s.createElement(o),
72+
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
73+
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
7074
ga('create', 'pageview');
7175
}
7276
</script>

app/js/main.js

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ if (process.env.NODE_ENV === 'production') {
2020

2121
window.addEventListener("DOMContentLoaded", () => {
2222
//To check the device and add iOS support
23-
window.iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
23+
window.iOS = ["iPad", "iPhone", "iPod"].indexOf(navigator.platform) >= 0;
24+
window.isMediaStreamAPISupported = (navigator && navigator.mediaDevices && 'enumerateDevices' in navigator.mediaDevices);
2425

2526
var copiedText = null;
2627
var frame = null;
@@ -31,34 +32,36 @@ window.addEventListener("DOMContentLoaded", () => {
3132
var dialogCloseBtnElement = document.querySelector('.app__dialog-close');
3233
var scanningEle = document.querySelector('.custom-scanner');
3334
var textBoxEle = document.querySelector('#result');
34-
var helpText = document.querySelector('.app__help-text');
35+
var helpTextEle = document.querySelector('.app__help-text');
3536
var infoSvg = document.querySelector('.app__header-icon svg');
3637
var videoElement = document.querySelector('video');
3738
window.appOverlay = document.querySelector('.app__overlay');
38-
39+
3940
//Initializing qr scanner
4041
window.addEventListener('load', (event) => {
4142
QRReader.init(); //To initialize QR Scanner
4243
// Set camera overlay size
43-
setTimeout(() => {
44+
setTimeout(() => {
4445
setCameraOverlay();
45-
if (!window.iOS) {
46+
if (window.isMediaStreamAPISupported) {
4647
scan();
4748
}
4849
}, 1000);
50+
51+
// To support other browsers who dont have mediaStreamAPI
52+
selectFromPhoto();
4953
});
5054

5155
function setCameraOverlay() {
5256
window.appOverlay.style.borderStyle = 'solid';
53-
helpText.style.display = 'block';
5457
}
55-
58+
5659
function createFrame() {
5760
frame = document.createElement('img');
5861
frame.src = '';
5962
frame.id = 'frame';
6063
}
61-
64+
6265
//Dialog close btn event
6366
dialogCloseBtnElement.addEventListener('click', hideDialog, false);
6467
dialogOpenBtnElement.addEventListener('click', openInBrowser, false);
@@ -72,9 +75,11 @@ window.addEventListener("DOMContentLoaded", () => {
7275
}
7376

7477
//Scan
75-
function scan() {
76-
if (!window.iOS) scanningEle.style.display = 'block';
78+
function scan(forSelectedPhotos = false) {
79+
if (window.isMediaStreamAPISupported) scanningEle.style.display = 'block';
80+
else { helpTextEle.style.display = 'block'; }
7781
QRReader.scan((result) => {
82+
7883
copiedText = result;
7984
textBoxEle.value = result;
8085
textBoxEle.select();
@@ -84,15 +89,15 @@ window.addEventListener("DOMContentLoaded", () => {
8489
}
8590
dialogElement.classList.remove('app__dialog--hide');
8691
dialogOverlayElement.classList.remove('app__dialog--hide');
87-
});
92+
}, forSelectedPhotos);
8893
}
8994

9095
//Hide dialog
9196
function hideDialog() {
9297
copiedText = null;
9398
textBoxEle.value = "";
9499

95-
if (window.iOS) {
100+
if (!window.isMediaStreamAPISupported) {
96101
frame.src = "";
97102
frame.className = "";
98103
}
@@ -102,20 +107,12 @@ window.addEventListener("DOMContentLoaded", () => {
102107
scan();
103108
}
104109

105-
// For iOS support
106-
if (window.iOS) selectFromPhoto();
107-
108110
function selectFromPhoto() {
109-
if (videoElement) videoElement.remove(); //removing the video element
110-
111111
//Creating the camera element
112112
var camera = document.createElement('input');
113113
camera.setAttribute('type', 'file');
114114
camera.setAttribute('capture', 'camera');
115115
camera.id = 'camera';
116-
helpText.textContent = '';
117-
helpText.style.color = '#212121';
118-
helpText.style.bottom = '-60px';
119116
infoSvg.style.fill = '#212121';
120117
window.appOverlay.style.borderStyle = '';
121118
selectPhotoBtn.style.color = "#212121";
@@ -132,7 +129,7 @@ window.addEventListener("DOMContentLoaded", () => {
132129
scanningEle.style.display = 'none';
133130
document.querySelector("#camera").click();
134131
});
135-
132+
136133
//On camera change
137134
camera.addEventListener('change', (event) => {
138135
if (event.target && event.target.files.length > 0) {

app/js/vendor/qrscan.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,26 @@ QRReader.setCanvas = () => {
1313
QRReader.ctx = QRReader.canvas.getContext("2d");
1414
}
1515

16-
QRReader.init = () => {
17-
var baseurl = "";
18-
var streaming = false;
19-
20-
// Init Webcam + Canvas
21-
if (!window.iOS) {
16+
function setPhotoSourceToScan(forSelectedPhotos) {
17+
if (!forSelectedPhotos && window.isMediaStreamAPISupported) {
2218
QRReader.webcam = document.querySelector("video");
2319
}
2420
else {
2521
QRReader.webcam = document.querySelector("img");
2622
}
23+
}
24+
25+
QRReader.init = () => {
26+
var baseurl = "";
27+
var streaming = false;
28+
29+
// Init Webcam + Canvas
30+
setPhotoSourceToScan();
2731

2832
QRReader.setCanvas();
2933
QRReader.decoder = new Worker(baseurl + "decoder.min.js");
3034

31-
if (!window.iOS) {
35+
if (window.isMediaStreamAPISupported) {
3236
// Resize webcam according to input
3337
QRReader.webcam.addEventListener("play", function (ev) {
3438
if (!streaming) {
@@ -50,14 +54,19 @@ QRReader.init = () => {
5054
navigator.mediaDevices.getUserMedia(constraints)
5155
.then(function (stream) {
5256
QRReader.webcam.srcObject = stream;
57+
QRReader.webcam.setAttribute("playsinline", true);
58+
QRReader.webcam.setAttribute("controls", true);
59+
setTimeout(() => {
60+
this.videoElement.removeAttribute("controls");
61+
});
5362
})
5463
.catch(function(err) {
5564
console.log("Error occurred ", err);
5665
showErrorMsg();
5766
});
5867
}
5968

60-
if (!window.iOS) {
69+
if (window.isMediaStreamAPISupported) {
6170
navigator.mediaDevices.enumerateDevices()
6271
.then(function (devices) {
6372
var device = devices.filter(function(device) {
@@ -67,8 +76,9 @@ QRReader.init = () => {
6776
}
6877
});
6978

79+
var constraints;
7080
if (device.length > 1) {
71-
var constraints = {
81+
constraints = {
7282
video: {
7383
mandatory: {
7484
sourceId: device[1].deviceId ? device[1].deviceId : null
@@ -77,10 +87,14 @@ QRReader.init = () => {
7787
audio: false
7888
};
7989

90+
if (window.iOS) {
91+
constraints.video.facingMode = "environment";
92+
}
93+
8094
startCapture(constraints);
8195
}
8296
else if (device.length) {
83-
var constraints = {
97+
constraints = {
8498
video: {
8599
mandatory: {
86100
sourceId: device[0].deviceId ? device[0].deviceId : null
@@ -89,6 +103,10 @@ QRReader.init = () => {
89103
audio: false
90104
};
91105

106+
if (window.iOS) {
107+
constraints.video.facingMode = "environment";
108+
}
109+
92110
startCapture(constraints);
93111
}
94112
else {
@@ -114,7 +132,10 @@ QRReader.init = () => {
114132
*
115133
* \param A function(scan_result)
116134
*/
117-
QRReader.scan = function (callback) {
135+
QRReader.scan = function (callback, forSelectedPhotos) {
136+
setTimeout(() => {
137+
// setPhotoSourceToScan(forSelectedPhotos);
138+
})
118139
QRReader.active = true;
119140
QRReader.setCanvas();
120141
function onDecoderMessage(event) {

0 commit comments

Comments
 (0)