Merge pull request #3837 from bobrippling/feat/qrcode-custom

qrcode: permit custom app names
master
Rob Pilling 2025-05-01 20:20:40 +01:00 committed by GitHub
commit e628565309
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 247 additions and 242 deletions

View File

@ -4,3 +4,4 @@
0.04: Allow scanning of QR codes from camera or file 0.04: Allow scanning of QR codes from camera or file
0.05: Change brightness on touch 0.05: Change brightness on touch
0.06: Add ability to generate contact info (MeCard format) QR code 0.06: Add ability to generate contact info (MeCard format) QR code
0.07: Add custom appname (for storing multiple QR codes)

View File

@ -17,61 +17,61 @@
<hr> <hr>
<div id="srcText"> <div id="srcText">
<p>Text/URL: <input type="text" id="text" class="form-input" value="http://www.espruino.com"></p> <p>Text/URL: <input type="text" id="text" class="form-input" value="http://www.espruino.com"></p>
</div> </div>
<div id="srcScanCam"> <div id="srcScanCam">
<div> <div>
<video id="qrVideo" align="center" width="50%"></video> <video id="qrVideo" align="center" width="50%"></video>
</div> </div>
<div> <div>
<select id="camList"> <select id="camList">
</select> </select>
</div> </div>
<div> <div>
<button id="flashToggle">Flash: <span id="flashState">off</span></button> <button id="flashToggle">Flash: <span id="flashState">off</span></button>
</div> </div>
<br> <br>
Detected QR code: Detected QR code:
<span id="camQrResult">None</span> <span id="camQrResult">None</span>
<br> <br>
<button id="startButton" class="btn btn-primary">Start</button> <button id="startButton" class="btn btn-primary">Start</button>
<button id="stopButton" class="btn btn-primary">Stop</button> <button id="stopButton" class="btn btn-primary">Stop</button>
</div> </div>
<div id="srcScanFile"> <div id="srcScanFile">
<input type="file" id="fileSelector"> <input type="file" id="fileSelector">
<br> <br>
Detected QR code: Detected QR code:
<span id="fileQrResult">None</span> <span id="fileQrResult">None</span>
</div> </div>
<div id="srcWifi"> <div id="srcWifi">
<p>Wifi name: <input type="text" id="ssid" class="form-input" value=""></p> <p>Wifi name: <input type="text" id="ssid" class="form-input" value=""></p>
<p>Wifi password: <input type="password" id="password" class="form-input" value=""></p> <p>Wifi password: <input type="password" id="password" class="form-input" value=""></p>
<div class="form-group"> <div class="form-group">
<label for="encryption" class="control-label">Encryption</label> <label for="encryption" class="control-label">Encryption</label>
<div class="input-group"> <div class="input-group">
<select name="encryption" id="encryption" class="form-control"> <select name="encryption" id="encryption" class="form-control">
<option value="WPA">WPA/WPA2</option> <option value="WPA">WPA/WPA2</option>
<option value="WEP">WEP</option> <option value="WEP">WEP</option>
<option value="nopass">None</option> <option value="nopass">None</option>
</select> </select>
</div> </div>
</div> </div>
<div> <div>
<input type="checkbox" id="hidden" name="hidden"/> <input type="checkbox" id="hidden" name="hidden"/>
<label for="hidden">Wifi is hidden</label> <label for="hidden">Wifi is hidden</label>
</div> </div>
</div> </div>
<div id="srcMeCard"> <div id="srcMeCard">
<p>First Name: <input type="text" id="meNameFirst" class="form-input" value=""></p> <p>First Name: <input type="text" id="meNameFirst" class="form-input" value=""></p>
<p>Last Name: <input type="text" id="meNameLast" class="form-input" value=""></p> <p>Last Name: <input type="text" id="meNameLast" class="form-input" value=""></p>
<p>Phone Number: <input type="text" id="mePhoneNumber" class="form-input" value=""></p> <p>Phone Number: <input type="text" id="mePhoneNumber" class="form-input" value=""></p>
<p>Email: <input type="text" id="meEmail" class="form-input" value=""></p> <p>Email: <input type="text" id="meEmail" class="form-input" value=""></p>
<p>Website: <input type="text" id="meWebsite" class="form-input" value=""></p> <p>Website: <input type="text" id="meWebsite" class="form-input" value=""></p>
</div> </div>
<hr> <hr>
@ -82,34 +82,35 @@
<p>Additional options:</p> <p>Additional options:</p>
<input type="checkbox" id="preventIntegerScaling" name="preventIntegerScaling"/> <input type="checkbox" id="preventIntegerScaling" name="preventIntegerScaling"/>
<label for="preventIntegerScaling">Prevent integer scaling</label></br> <label for="preventIntegerScaling">Prevent integer scaling</label></br>
<input type="checkbox" id="preventBrightnessChangeOnTouch" name="preventBrightnessChangeOnTouch"/> <input type="checkbox" id="preventBrightnessChangeOnTouch" name="preventBrightnessChangeOnTouch"/>
<label for="preventBrightnessChangeOnTouch">Prevent brightness change on touch</label></br> <label for="preventBrightnessChangeOnTouch">Prevent brightness change on touch</label></br>
<input type="checkbox" id="boostBacklight" name="boostBacklight"/> <input type="checkbox" id="boostBacklight" name="boostBacklight"/>
<label for="boostBacklight">Set initial backlight to max. while QR is shown</label></br> <label for="boostBacklight">Set initial backlight to max. while QR is shown</label></br>
<input type="checkbox" id="stayOn" name="stayOn"/> <input type="checkbox" id="stayOn" name="stayOn"/>
<label for="stayOn">Do not lock or dim while showing QR</label></br> <label for="stayOn">Do not lock or dim while showing QR</label></br>
<input type="checkbox" id="hideDescription" name="hideDescription"/> <input type="checkbox" id="hideDescription" name="hideDescription"/>
<label for="hideDescription">Hide Description</label></br> <label for="hideDescription">Hide Description</label></br>
<label for="description">Replace default description:</label> <label for="description">Replace default description:</label>
<input type="text" id="description" class="form-input" value=""> <input type="text" id="description" class="form-input" value="">
<label for="correction">Error correction level:</label> <label for="correction">Error correction level:</label>
<div class="input-group"> <div class="input-group">
<select name="correction" id="correction" class="form-control"> <select name="correction" id="correction" class="form-control">
<option value="1">L - Low - 7%</option> <option value="1">L - Low - 7%</option>
<option value="0">M - Medium - 15%</option> <option value="0">M - Medium - 15%</option>
<option value="3">Q - Quartile - 25%</option> <option value="3">Q - Quartile - 25%</option>
<option value="2">H - High - 30%</option> <option value="2">H - High - 30%</option>
</select> </select>
</div> </div>
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p> <label for="appname">App name</label>
<input type="text" id="appname" class="form-input" value="qrcode">
<button id="upload" class="btn btn-primary">Upload</button>
<script src="../../core/lib/customize.js"></script>
<script src="../../core/lib/customize.js"></script> <script src="../../core/lib/qrcode.min.js"></script><!-- https://davidshimjs.github.io/qrcodejs/ -->
<script src="../../core/lib/qrcode.min.js"></script><!-- https://davidshimjs.github.io/qrcodejs/ --> <script src="../../webtools/heatshrink.js"></script>
<script src="../../webtools/heatshrink.js"></script> <script src="../../webtools/imageconverter.js"></script>
<script src="../../webtools/imageconverter.js"></script> <script src="./qr-scanner.umd.min.js"></script><!-- https://github.com/nimiq/qr-scanner -->
<script src="./qr-scanner.umd.min.js"></script><!-- https://github.com/nimiq/qr-scanner --> <script>
<script>
var targetSize = 200; var targetSize = 200;
var deviceWidth = targetSize; var deviceWidth = targetSize;
var deviceHeight = targetSize; var deviceHeight = targetSize;
@ -120,190 +121,190 @@
function onInit(device) { function onInit(device) {
console.info("onInit" + device); console.info("onInit" + device);
if (device && device.info && device.info.g) { if (device && device.info && device.info.g) {
deviceWidth = device.info.g.width; deviceWidth = device.info.g.width;
deviceHeight = device.info.g.height; deviceHeight = device.info.g.height;
} }
refreshQRCode(); refreshQRCode();
} }
const updateFlashAvailability = () => { const updateFlashAvailability = () => {
scanner.hasFlash().then(hasFlash => { scanner.hasFlash().then(hasFlash => {
document.getElementById('flashToggle').style.display = hasFlash ? 'inline-block' : 'none'; document.getElementById('flashToggle').style.display = hasFlash ? 'inline-block' : 'none';
}); });
}; };
function setResult(label, result) { function setResult(label, result) {
console.info("setResult " + result); console.info("setResult " + result);
label.textContent = result; label.textContent = result;
scanner.stop(); scanner.stop();
refreshQRCode(); refreshQRCode();
} }
function initQrScanner() { function initQrScanner() {
console.info("initQrScanner"); console.info("initQrScanner");
QrScanner.WORKER_PATH = './qr-scanner-worker.min.js'; QrScanner.WORKER_PATH = './qr-scanner-worker.min.js';
if (scanner == null) { if (scanner == null) {
scanner = new QrScanner(document.getElementById('qrVideo'), result => setResult(document.getElementById('camQrResult'), result), error => { scanner = new QrScanner(document.getElementById('qrVideo'), result => setResult(document.getElementById('camQrResult'), result), error => {
document.getElementById('camQrResult').textContent = error; document.getElementById('camQrResult').textContent = error;
document.getElementById('camQrResult').style.color = 'inherit'; document.getElementById('camQrResult').style.color = 'inherit';
}); });
} }
} }
function initQrCam(){ function initQrCam(){
scanner.start().then(() => { scanner.start().then(() => {
updateFlashAvailability(); updateFlashAvailability();
QrScanner.listCameras(true).then(cameras => cameras.forEach(camera => { QrScanner.listCameras(true).then(cameras => cameras.forEach(camera => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = camera.id; option.value = camera.id;
option.text = camera.label; option.text = camera.label;
document.getElementById('camList').add(option); document.getElementById('camList').add(option);
})); }));
}); });
} }
function toggleVis(id){ function toggleVis(id){
console.info("Got id", id); console.info("Got id", id);
["srcScanFile", "srcText", "srcWifi", "srcScanCam", "srcMeCard"].forEach(function (item){ ["srcScanFile", "srcText", "srcWifi", "srcScanCam", "srcMeCard"].forEach(function (item){
document.getElementById(item).style.display = "none"; document.getElementById(item).style.display = "none";
}); });
if (id != undefined && id != null) document.getElementById(id).style.display = "block"; if (id != undefined && id != null) document.getElementById(id).style.display = "block";
refreshQRCode(); refreshQRCode();
} }
toggleVis("srcText"); toggleVis("srcText");
//https://github.com/evgeni/qifi/blob/gh-pages/index.html#L168 //https://github.com/evgeni/qifi/blob/gh-pages/index.html#L168
function escapeString (string) { function escapeString (string) {
var to_escape = ['\\', ';', ',', ':', '"']; var to_escape = ['\\', ';', ',', ':', '"'];
var hex_only = /^[0-9a-f]+$/i; var hex_only = /^[0-9a-f]+$/i;
var output = ""; var output = "";
for (var i=0; i<string.length; i++) { for (var i=0; i<string.length; i++) {
if(string[i].includes(to_escape)) { if(string[i].includes(to_escape)) {
output += '\\'+string[i]; output += '\\'+string[i];
} }
else { else {
output += string[i]; output += string[i];
} }
} }
return output; return output;
} }
function generateWifiString(ssid, password, hidden,encryption){ function generateWifiString(ssid, password, hidden,encryption){
//https://github.com/evgeni/qifi/blob/gh-pages/index.html#L198 //https://github.com/evgeni/qifi/blob/gh-pages/index.html#L198
var qrstring = 'WIFI:S:'+escapeString(ssid)+';T:'+encryption+';P:'+escapeString(password)+';'; var qrstring = 'WIFI:S:'+escapeString(ssid)+';T:'+encryption+';P:'+escapeString(password)+';';
if (hidden) { if (hidden) {
qrstring += 'H:true'; qrstring += 'H:true';
} }
return qrstring; return qrstring;
} }
function generateMeCardString(meNameFirst, meNameLast, mePhoneNumber, meEmail, meWebsite){ function generateMeCardString(meNameFirst, meNameLast, mePhoneNumber, meEmail, meWebsite){
var meCardStringOutput = 'MECARD:'; var meCardStringOutput = 'MECARD:';
//first & Last name part of string, can have one or both //first & Last name part of string, can have one or both
if (meNameFirst.trim().length != 0 && meNameLast.trim().length != 0) { if (meNameFirst.trim().length != 0 && meNameLast.trim().length != 0) {
meCardStringOutput += 'N:'+meNameLast.trim()+','+meNameFirst.trim()+';'; meCardStringOutput += 'N:'+meNameLast.trim()+','+meNameFirst.trim()+';';
} }
else if (meNameLast.trim().length != 0) { else if (meNameLast.trim().length != 0) {
meCardStringOutput += 'N:'+meNameLast.trim()+';'; meCardStringOutput += 'N:'+meNameLast.trim()+';';
} }
else if (meNameFirst.trim().length != 0) { else if (meNameFirst.trim().length != 0) {
meCardStringOutput += 'N:'+meNameFirst.trim()+';'; meCardStringOutput += 'N:'+meNameFirst.trim()+';';
} }
if (mePhoneNumber.trim().length != 0) { if (mePhoneNumber.trim().length != 0) {
meCardStringOutput += 'TEL:'+mePhoneNumber.trim()+';'; meCardStringOutput += 'TEL:'+mePhoneNumber.trim()+';';
} }
if (meEmail.trim().length != 0) { if (meEmail.trim().length != 0) {
meCardStringOutput += 'EMAIL:'+meEmail.trim()+';'; meCardStringOutput += 'EMAIL:'+meEmail.trim()+';';
} }
if (meWebsite.trim().length != 0) { if (meWebsite.trim().length != 0) {
meCardStringOutput += 'URL:'+meWebsite.trim()+';'; meCardStringOutput += 'URL:'+meWebsite.trim()+';';
} }
meCardStringOutput += ';'; meCardStringOutput += ';';
return meCardStringOutput; return meCardStringOutput;
} }
function refreshQRCode(){ function refreshQRCode(){
if (qrcode == null){ if (qrcode == null){
qrcode = new QRCode("qrcode", { qrcode = new QRCode("qrcode", {
text: document.getElementById("text").value, text: document.getElementById("text").value,
colorDark : "#000000", colorDark : "#000000",
colorLight : "#ffffff" colorLight : "#ffffff"
}); });
} }
document.getElementById("errors").innerText=""; document.getElementById("errors").innerText="";
qrcode.clear(); // clear the code. qrcode.clear(); // clear the code.
var qrText = ""; var qrText = "";
if(document.getElementById("useWIFI").checked){ if(document.getElementById("useWIFI").checked){
const ssid = document.getElementById("ssid").value; const ssid = document.getElementById("ssid").value;
const password = document.getElementById("password").value; const password = document.getElementById("password").value;
const encryption = document.getElementById("encryption").value; const encryption = document.getElementById("encryption").value;
const hidden = document.getElementById("hidden").checked; const hidden = document.getElementById("hidden").checked;
const wifiString = generateWifiString(ssid, password, hidden, encryption); const wifiString = generateWifiString(ssid, password, hidden, encryption);
qrText= wifiString; qrText= wifiString;
} else if (document.getElementById("useMECARD").checked) { } else if (document.getElementById("useMECARD").checked) {
const meNameFirst = document.getElementById("meNameFirst").value; const meNameFirst = document.getElementById("meNameFirst").value;
const meNameLast = document.getElementById("meNameLast").value; const meNameLast = document.getElementById("meNameLast").value;
const mePhoneNumber = document.getElementById("mePhoneNumber").value; const mePhoneNumber = document.getElementById("mePhoneNumber").value;
const meEmail = document.getElementById("meEmail").value; const meEmail = document.getElementById("meEmail").value;
const meWebsite = document.getElementById("meWebsite").value; const meWebsite = document.getElementById("meWebsite").value;
const meCardString = generateMeCardString(meNameFirst, meNameLast, mePhoneNumber, meEmail, meWebsite); const meCardString = generateMeCardString(meNameFirst, meNameLast, mePhoneNumber, meEmail, meWebsite);
qrText = meCardString; qrText = meCardString;
} else if (document.getElementById("useCAM").checked) { } else if (document.getElementById("useCAM").checked) {
qrText= document.getElementById("camQrResult").innerText; qrText= document.getElementById("camQrResult").innerText;
} else if (document.getElementById("useFILE").checked) { } else if (document.getElementById("useFILE").checked) {
qrText= document.getElementById("fileQrResult").innerText; qrText= document.getElementById("fileQrResult").innerText;
} else { } else {
qrText = document.getElementById("text").value; qrText = document.getElementById("text").value;
} }
console.info("Given qrtext was: " + qrText);
qrcode._htOption.text = qrText;
qrcode._htOption.correctLevel = parseInt(document.getElementById("correction").value);
try {
qrcode.makeCode(qrText);
} catch (error) {
document.getElementById("errors").innerText="Error: QR could not be created.";
console.error(error);
return;
}
targetSize = Math.min(deviceWidth - border, deviceHeight - border);
console.info("Targetsize: " + targetSize);
var finalSizeQr=targetSize;
var finalSizeCanvas=targetSize;
console.info("Given qrtext was: " + qrText); var integerScale = Math.max(Math.floor(targetSize / (qrcode._oQRCode.moduleCount + 1)),1);
qrcode._htOption.text = qrText; if (integerScale == 1) document.getElementById("errors").innerText = "Warning, QR will probably be too small to properly scan. Try less data or less error correction.";
qrcode._htOption.correctLevel = parseInt(document.getElementById("correction").value);
try {
qrcode.makeCode(qrText);
} catch (error) {
document.getElementById("errors").innerText="Error: QR could not be created.";
console.error(error);
}
targetSize = Math.min(deviceWidth - border, deviceHeight - border); console.info("IntegerScale: " + integerScale);
console.info("Targetsize: " + targetSize);
var finalSizeQr=targetSize;
var finalSizeCanvas=targetSize;
var integerScale = Math.max(Math.floor(targetSize / (qrcode._oQRCode.moduleCount + 1)),1); if (!document.getElementById("preventIntegerScaling").checked){
if (integerScale == 1) document.getElementById("errors").innerText = "Warning, QR will probably be too small to properly scan. Try less data or less error correction."; finalSizeQr = integerScale * (qrcode._oQRCode.moduleCount + 1);
finalSizeCanvas = finalSizeQr - 1;
}
console.info("IntegerScale: " + integerScale); console.info("FinalSizeQr: " + finalSizeQr);
console.info("FinalSizeCanvas: " + finalSizeCanvas);
if (!document.getElementById("preventIntegerScaling").checked){ qrcode._htOption.width = finalSizeQr;
finalSizeQr = integerScale * (qrcode._oQRCode.moduleCount + 1); qrcode._htOption.height = finalSizeQr;
finalSizeCanvas = finalSizeQr - 1;
}
console.info("FinalSizeQr: " + finalSizeQr); document.getElementsByTagName("canvas")[0].width = finalSizeCanvas;
console.info("FinalSizeCanvas: " + finalSizeCanvas); document.getElementsByTagName("canvas")[0].height = finalSizeCanvas;
try {
qrcode._htOption.width = finalSizeQr; qrcode.makeCode(qrText);
qrcode._htOption.height = finalSizeQr; } catch (error) {
document.getElementById("errors").innerText="Error: QR could not be created.";
document.getElementsByTagName("canvas")[0].width = finalSizeCanvas; console.error(error);
document.getElementsByTagName("canvas")[0].height = finalSizeCanvas; return;
try { }
qrcode.makeCode(qrText);
} catch (error) {
document.getElementById("errors").innerText="Error: QR could not be created.";
console.error(error);
}
} }
document.getElementById("useTEXT").addEventListener("change",function(){toggleVis("srcText");}); document.getElementById("useTEXT").addEventListener("change",function(){toggleVis("srcText");});
@ -316,13 +317,13 @@
document.getElementById("meWebsite").addEventListener("change",refreshQRCode); document.getElementById("meWebsite").addEventListener("change",refreshQRCode);
document.getElementById("useCAM").addEventListener("change",function(){ document.getElementById("useCAM").addEventListener("change",function(){
initQrScanner(); initQrScanner();
initQrCam(); initQrCam();
toggleVis("srcScanCam"); toggleVis("srcScanCam");
}); });
document.getElementById("useFILE").addEventListener("change",function(){ document.getElementById("useFILE").addEventListener("change",function(){
initQrScanner(); initQrScanner();
toggleVis("srcScanFile"); toggleVis("srcScanFile");
}); });
document.getElementById("useWIFI").addEventListener("change",function(){toggleVis("srcWifi");}); document.getElementById("useWIFI").addEventListener("change",function(){toggleVis("srcWifi");});
document.getElementById("ssid").addEventListener("change",refreshQRCode); document.getElementById("ssid").addEventListener("change",refreshQRCode);
@ -336,17 +337,18 @@
document.getElementById("useWIFI").addEventListener("change",refreshQRCode); document.getElementById("useWIFI").addEventListener("change",refreshQRCode);
document.getElementById("preventIntegerScaling").addEventListener("change",refreshQRCode); document.getElementById("preventIntegerScaling").addEventListener("change",refreshQRCode);
document.getElementById("correction").addEventListener("change",refreshQRCode); document.getElementById("correction").addEventListener("change",refreshQRCode);
document.getElementById("upload").addEventListener("click", function() { document.getElementById("upload").addEventListener("click", function() {
var content = document.getElementById("text").value; var content = document.getElementById("text").value;
if(document.getElementById("useWIFI").checked){ if(document.getElementById("useWIFI").checked){
content = document.getElementById("ssid").value content = document.getElementById("ssid").value
} }
if(!(document.getElementById("description").value === "")){ if(document.getElementById("description").value !== ""){
content = document.getElementById("description").value; content = document.getElementById("description").value;
} }
var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true}); var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true});
var app = `var img = ${img}; var app = `var img = ${img};
${ document.getElementById("preventBrightnessChangeOnTouch").checked ? '' : `var backlight = 0; ${document.getElementById("preventBrightnessChangeOnTouch").checked ? '' : `var backlight = 0;
Bangle.on('touch', function(button, xy) { Bangle.on('touch', function(button, xy) {
backlight += 0.3; backlight += 0.3;
if (backlight > 1) backlight = 0; if (backlight > 1) backlight = 0;
@ -354,50 +356,52 @@ Bangle.on('touch', function(button, xy) {
}); });
`} `}
${document.getElementById("boostBacklight").checked ? 'Bangle.setLCDBrightness(1);' : ''} ${document.getElementById("boostBacklight").checked ? 'Bangle.setLCDBrightness(1);' : ''}
${document.getElementById("stayOn").checked ? 'Bangle.setLCDTimeout(0);' : ''} ${document.getElementById("stayOn").checked ? 'Bangle.setLCDTimeout(0);' : ''}
${document.getElementById("hideDescription").checked ? '' : `var content = ${JSON.stringify(content)};`} ${document.getElementById("hideDescription").checked ? '' : `var content = ${JSON.stringify(content)};`}
g.clear(1).setColor(1,1,1).setBgColor(0,0,0); g.clear(1).setColor(1,1,1).setBgColor(0,0,0);
g.fillRect(0,0,g.getWidth()-1,g.getHeight()-1); g.fillRect(0,0,g.getWidth()-1,g.getHeight()-1);
g.drawImage(img,(g.getWidth()-img[0])/2,(g.getHeight()-img[1])/2); g.drawImage(img,(g.getWidth()-img[0])/2,(g.getHeight()-img[1])/2);
${ document.getElementById("hideDescription").checked ? '' : `g.setFontAlign(0,0).setFont("6x8").setColor(0,0,0); ${document.getElementById("hideDescription").checked ? '' : `g.setFontAlign(0,0).setFont("6x8").setColor(0,0,0);
g.drawString(content,g.getWidth()/2,g.getHeight()-(g.getHeight()-img[1])/4); g.drawString(content,g.getWidth()/2,g.getHeight()-(g.getHeight()-img[1])/4);
`} `}
g.setColor(1,1,1); g.setColor(1,1,1);
`; `;
sendCustomizedApp({
storage:[{name:"qrcode.app.js", url:"app.js", content:app},] var appname = document.getElementById("appname").value.trim() || "qrcode";
}); sendCustomizedApp({
storage:[{name:`${appname}.app.js`, url:"app.js", content:app}]
});
}); });
document.getElementById('camList').addEventListener('change', event => { document.getElementById('camList').addEventListener('change', event => {
scanner.setCamera(event.target.value).then(updateFlashAvailability); scanner.setCamera(event.target.value).then(updateFlashAvailability);
}); });
document.getElementById('flashToggle').addEventListener('click', () => { document.getElementById('flashToggle').addEventListener('click', () => {
scanner.toggleFlash().then(() => document.getElementById('flashState').textContent = scanner.isFlashOn() ? 'on' : 'off'); scanner.toggleFlash().then(() => document.getElementById('flashState').textContent = scanner.isFlashOn() ? 'on' : 'off');
}); });
document.getElementById('startButton').addEventListener('click', () => { document.getElementById('startButton').addEventListener('click', () => {
scanner.start(); scanner.start();
}); });
document.getElementById('stopButton').addEventListener('click', () => { document.getElementById('stopButton').addEventListener('click', () => {
scanner.stop(); scanner.stop();
}); });
document.getElementById('fileSelector').addEventListener('change', event => { document.getElementById('fileSelector').addEventListener('change', event => {
const file = document.getElementById('fileSelector').files[0]; const file = document.getElementById('fileSelector').files[0];
if (!file) { if (!file) {
return; return;
} }
QrScanner.scanImage(file) QrScanner.scanImage(file)
.then(result => setResult(document.getElementById('fileQrResult'), result)) .then(result => setResult(document.getElementById('fileQrResult'), result))
.catch(e => setResult(document.getElementById('fileQrResult'), e || 'No QR code found.')); .catch(e => setResult(document.getElementById('fileQrResult'), e || 'No QR code found.'));
}); });
</script> </script>
</body> </body>
</html> </html>

View File

@ -2,7 +2,7 @@
"id": "qrcode", "id": "qrcode",
"name": "Custom QR Code", "name": "Custom QR Code",
"shortName": "QR Code", "shortName": "QR Code",
"version": "0.06", "version": "0.07",
"description": "Use this to upload a customised QR code to Bangle.js", "description": "Use this to upload a customised QR code to Bangle.js",
"icon": "app.png", "icon": "app.png",
"tags": "qrcode", "tags": "qrcode",