From 3380500a2da52f973c6792caeed28f8caa2e24f0 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 2 Sep 2019 11:31:07 +1000 Subject: [PATCH 1/5] Added QR code viewing. --- _locales/en/messages.json | 5 ++++ background.html | 8 ++++++ js/background.js | 7 +++++ js/views/app_view.js | 4 +++ js/views/qr_dialog_view.js | 49 ++++++++++++++++++++++++++++++++++ stylesheets/_conversation.scss | 1 + stylesheets/_global.scss | 15 +++++++++++ test/index.html | 1 + ts/components/MainHeader.tsx | 7 +++++ 9 files changed, 97 insertions(+) create mode 100644 js/views/qr_dialog_view.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 729cc1181..71d5f0b07 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1920,6 +1920,11 @@ "description": "Button action that the user can click to view their unique seed" }, + "showQRCode": { + "message": "Show QR code", + "description": + "Button action that the user can click to view their QR code" + }, "seedViewTitle": { "message": diff --git a/background.html b/background.html index a62c7dd4c..35f2b6686 100644 --- a/background.html +++ b/background.html @@ -281,6 +281,13 @@ + + diff --git a/js/background.js b/js/background.js index 799d8f8f3..7f62f551b 100644 --- a/js/background.js +++ b/js/background.js @@ -757,6 +757,13 @@ } }); + Whisper.events.on('showQRDialog', async () => { + if (appView) { + const ourNumber = textsecure.storage.user.getNumber(); + appView.showQRDialog(ourNumber); + } + }); + Whisper.events.on('calculatingPoW', ({ pubKey, timestamp }) => { try { const conversation = ConversationController.get(pubKey); diff --git a/js/views/app_view.js b/js/views/app_view.js index f9f306789..31235bf9f 100644 --- a/js/views/app_view.js +++ b/js/views/app_view.js @@ -196,5 +196,9 @@ const dialog = new Whisper.SeedDialogView({ seed }); this.el.append(dialog.el); }, + showQRDialog(string) { + const dialog = new Whisper.QRDialogView({ string }); + this.el.append(dialog.el); + }, }); })(); diff --git a/js/views/qr_dialog_view.js b/js/views/qr_dialog_view.js new file mode 100644 index 000000000..5a710fe7f --- /dev/null +++ b/js/views/qr_dialog_view.js @@ -0,0 +1,49 @@ +/* global Whisper, i18n, QRCode */ + +/* eslint-disable more/no-then */ + +// eslint-disable-next-line func-names +(function() { + 'use strict'; + + window.Whisper = window.Whisper || {}; + + Whisper.QRDialogView = Whisper.View.extend({ + templateName: 'qr-code-template', + className: 'loki-dialog qr-dialog modal', + initialize(options = {}) { + this.okText = options.okText || i18n('ok'); + this.render(); + this.$('.qr-dialog').bind('keyup', event => + this.onKeyup(event) + ); + + if (options.string) { + this.qr = new QRCode(this.$('#qr')[0]).makeCode(options.string); + this.$('#qr').addClass('ready'); + } + }, + events: { + 'click .ok': 'close', + }, + render_attributes() { + return { + ok: this.okText, + }; + }, + close() { + this.remove(); + }, + onKeyup(event) { + switch (event.key) { + case 'Enter': + case 'Escape': + case 'Esc': + this.close(); + break; + default: + break; + } + }, + }); +})(); diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss index 8495b38f5..8ea4f05b4 100644 --- a/stylesheets/_conversation.scss +++ b/stylesheets/_conversation.scss @@ -383,6 +383,7 @@ border: 1px solid $color-loki-green; color: white; outline: none; + user-select: none; &:hover, &:disabled { diff --git a/stylesheets/_global.scss b/stylesheets/_global.scss index a928ad882..f275fa9f2 100644 --- a/stylesheets/_global.scss +++ b/stylesheets/_global.scss @@ -860,3 +860,18 @@ $loading-height: 16px; .inbox { position: relative; } + +.qr-dialog { + + .content { + width: 300px !important; + max-width: none !important; + min-width: auto !important; + } + + #qr { + display: flex; + justify-content: center; + margin-bottom: 1em; + } +} diff --git a/test/index.html b/test/index.html index 61087bb86..5ebafa95f 100644 --- a/test/index.html +++ b/test/index.html @@ -567,6 +567,7 @@ + diff --git a/ts/components/MainHeader.tsx b/ts/components/MainHeader.tsx index 946077894..90a9b543f 100644 --- a/ts/components/MainHeader.tsx +++ b/ts/components/MainHeader.tsx @@ -327,6 +327,13 @@ export class MainHeader extends React.Component { trigger('showSeedDialog'); }, }, + { + id: 'showQRCode', + name: i18n('showQRCode'), + onClick: () => { + trigger('showQRDialog'); + }, + } ]; const passItem = (type: string) => ({ From a89358676c95848e848286d6d2f3bfbfed47bdd7 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 2 Sep 2019 12:32:43 +1000 Subject: [PATCH 2/5] Update electron-context-menu. Only allow copying QR code since saving doesn't work. --- package.json | 2 +- preload.js | 21 +++++++++++++++------ yarn.lock | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 306574796..f745135b6 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "bunyan": "1.8.12", "classnames": "2.2.5", "config": "1.28.1", - "electron-context-menu": "^0.11.0", + "electron-context-menu": "^0.15.0", "electron-editor-context-menu": "1.1.1", "electron-is-dev": "0.3.0", "emoji-datasource": "4.0.0", diff --git a/preload.js b/preload.js index 54577110a..d6dfd14e3 100644 --- a/preload.js +++ b/preload.js @@ -402,14 +402,23 @@ window.Signal.Logs = require('./js/modules/logs'); // Add right-click listener for selected text and urls const contextMenu = require('electron-context-menu'); +const isQR = (params) => params.mediaType === 'image' && params.titleText === 'Scan me!'; + +// QR saving doesn't work so we just disable it contextMenu({ showInspectElement: false, - shouldShowMenu: (event, params) => - Boolean( - !params.isEditable && - params.mediaType === 'none' && - (params.linkURL || params.selectionText) - ), + shouldShowMenu: (event, params) => { + const isRegular = params.mediaType === 'none' && (params.linkURL || params.selectionText); + return Boolean( + !params.isEditable && (isQR(params) || isRegular) + ) + }, + menu: (actions, params) => { + // If it's not a QR then show the default options + if (!isQR(params)) return actions; + + return [actions.copyImage()]; + }, }); // We pull this in last, because the native module involved appears to be sensitive to diff --git a/yarn.lock b/yarn.lock index 02a220ec9..20f42cec8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -726,6 +726,11 @@ ast-types@^0.7.2: version "0.7.8" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -1632,6 +1637,14 @@ cli-spinners@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.0.tgz#6ba8b357395f07b7981c1acc2614485ee8c02a2d" +cli-truncate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.0.0.tgz#68ff6aaa53b203b52ad89b8b1a80f1f61ad1e1d5" + integrity sha512-C4hp+8GCIFVsUUiXcw+ce+7wexVWImw8rQrgMBFsqerx9LvvcGlwm6sMjQYAEmV/Xb87xc1b5Ttx505MSpZVqg== + dependencies: + slice-ansi "^2.1.0" + string-width "^4.1.0" + cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" @@ -2649,11 +2662,12 @@ electron-chromedriver@~3.0.0: electron-download "^4.1.0" extract-zip "^1.6.5" -electron-context-menu@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.11.0.tgz#3ecefb0231151add474c9b0df2fb66fde3ad5731" - integrity sha512-sgDIGqjgazUQ5fbfz0ObRkmODAsw00eylQprp5q4jyuL6dskd27yslhoJTrjLbFGErfVVYzRXPW2rQPJxARKmg== +electron-context-menu@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.15.0.tgz#0a5abe8e73aca9cd9b891ce62830c984ecedff51" + integrity sha512-XLdtbX90NPkWycG3IzwtCmfX4ggu+lofNOW1nVRStb+ScFs49WTourW1k77Z4DTyThR3gUHg3UPXVBMbW1gNsg== dependencies: + cli-truncate "^2.0.0" electron-dl "^1.2.0" electron-is-dev "^1.0.1" @@ -2790,6 +2804,11 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -4768,6 +4787,11 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1, is-function@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" @@ -8645,6 +8669,15 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -9041,6 +9074,15 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" + integrity sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^5.2.0" + string_decoder@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -9091,7 +9133,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0: +strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== From 3d179909c72307d0cf0f876035c6ace764cfad9e Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 2 Sep 2019 13:24:56 +1000 Subject: [PATCH 3/5] Decrease the correctness level on the QR code. --- js/views/qr_dialog_view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/views/qr_dialog_view.js b/js/views/qr_dialog_view.js index 5a710fe7f..1a53eb85f 100644 --- a/js/views/qr_dialog_view.js +++ b/js/views/qr_dialog_view.js @@ -19,7 +19,9 @@ ); if (options.string) { - this.qr = new QRCode(this.$('#qr')[0]).makeCode(options.string); + this.qr = new QRCode(this.$('#qr')[0], { + correctLevel: QRCode.CorrectLevel.L, + }).makeCode(options.string); this.$('#qr').addClass('ready'); } }, From 21dad58537ffd27d79e716e9ee569d405d6bbbb8 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 2 Sep 2019 14:27:52 +1000 Subject: [PATCH 4/5] Linting. --- _locales/en/messages.json | 3 +-- js/views/qr_dialog_view.js | 4 +--- preload.js | 10 +++++----- stylesheets/_global.scss | 1 - ts/components/MainHeader.tsx | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 71d5f0b07..43e7f9222 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1922,8 +1922,7 @@ }, "showQRCode": { "message": "Show QR code", - "description": - "Button action that the user can click to view their QR code" + "description": "Button action that the user can click to view their QR code" }, "seedViewTitle": { diff --git a/js/views/qr_dialog_view.js b/js/views/qr_dialog_view.js index 1a53eb85f..a55d1f99c 100644 --- a/js/views/qr_dialog_view.js +++ b/js/views/qr_dialog_view.js @@ -14,9 +14,7 @@ initialize(options = {}) { this.okText = options.okText || i18n('ok'); this.render(); - this.$('.qr-dialog').bind('keyup', event => - this.onKeyup(event) - ); + this.$('.qr-dialog').bind('keyup', event => this.onKeyup(event)); if (options.string) { this.qr = new QRCode(this.$('#qr')[0], { diff --git a/preload.js b/preload.js index d6dfd14e3..d1d26243b 100644 --- a/preload.js +++ b/preload.js @@ -402,16 +402,16 @@ window.Signal.Logs = require('./js/modules/logs'); // Add right-click listener for selected text and urls const contextMenu = require('electron-context-menu'); -const isQR = (params) => params.mediaType === 'image' && params.titleText === 'Scan me!'; +const isQR = params => + params.mediaType === 'image' && params.titleText === 'Scan me!'; // QR saving doesn't work so we just disable it contextMenu({ showInspectElement: false, shouldShowMenu: (event, params) => { - const isRegular = params.mediaType === 'none' && (params.linkURL || params.selectionText); - return Boolean( - !params.isEditable && (isQR(params) || isRegular) - ) + const isRegular = + params.mediaType === 'none' && (params.linkURL || params.selectionText); + return Boolean(!params.isEditable && (isQR(params) || isRegular)); }, menu: (actions, params) => { // If it's not a QR then show the default options diff --git a/stylesheets/_global.scss b/stylesheets/_global.scss index f275fa9f2..93c5989f1 100644 --- a/stylesheets/_global.scss +++ b/stylesheets/_global.scss @@ -862,7 +862,6 @@ $loading-height: 16px; } .qr-dialog { - .content { width: 300px !important; max-width: none !important; diff --git a/ts/components/MainHeader.tsx b/ts/components/MainHeader.tsx index 90a9b543f..8f099dfd3 100644 --- a/ts/components/MainHeader.tsx +++ b/ts/components/MainHeader.tsx @@ -333,7 +333,7 @@ export class MainHeader extends React.Component { onClick: () => { trigger('showQRDialog'); }, - } + }, ]; const passItem = (type: string) => ({ From 58b0c5ef39eb4dfe3714dd69f6e5e0000fa9f25c Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 2 Sep 2019 15:40:38 +1000 Subject: [PATCH 5/5] Removed a line --- js/views/qr_dialog_view.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/views/qr_dialog_view.js b/js/views/qr_dialog_view.js index a55d1f99c..c365166c7 100644 --- a/js/views/qr_dialog_view.js +++ b/js/views/qr_dialog_view.js @@ -1,7 +1,5 @@ /* global Whisper, i18n, QRCode */ -/* eslint-disable more/no-then */ - // eslint-disable-next-line func-names (function() { 'use strict';