From 8074756dc2682c77f939b7c4c128884612d1b3bf Mon Sep 17 00:00:00 2001 From: Vincent Date: Fri, 3 Jan 2020 11:48:55 +1100 Subject: [PATCH] Infinte duration toasts --- _locales/en/messages.json | 5 +- js/background.js | 5 +- js/models/messages.js | 5 +- js/modules/signal.js | 4 +- js/permissions_popup_start.js | 8 +-- js/views/conversation_view.js | 17 ++---- js/views/inbox_view.js | 3 +- js/views/key_verification_view.js | 6 +- js/views/session_confirm_view.js | 7 +-- js/views/session_toast_view.js | 9 ++- js/views/whisper_view.js | 5 +- package_bak.json | 57 +++++++++++-------- stylesheets/_session.scss | 4 +- ts/components/AddServerDialog.tsx | 56 +++++++++---------- ts/components/session/SessionConfirm.tsx | 70 +++++++++--------------- ts/components/session/SessionModal.tsx | 10 ++-- ts/components/session/SessionSpinner.tsx | 23 +++++--- 17 files changed, 142 insertions(+), 152 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index bce73fc7e..afefeff60 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -395,6 +395,9 @@ "description": "When there are multiple previously-verified group members with safety number changes, a banner will be shown. The list of contacts with safety number changes is shown, and this text introduces that list." }, + "changedSinceVerifiedTitle": { + "message": "Safety Number Changed" + }, "changedSinceVerifiedMultiple": { "message": "Your safety numbers with multiple group members have changed since you last verified. This could mean that someone is trying to intercept your communication or that they have simply reinstalled Signal.", @@ -2024,7 +2027,7 @@ }, "banUser": { - "message": "Ban user", + "message": "Ban User", "description": "Ban user from public chat by public key." }, diff --git a/js/background.js b/js/background.js index acec57704..ca64dca4d 100644 --- a/js/background.js +++ b/js/background.js @@ -802,8 +802,6 @@ appView.openConversation(groupId, {}); }; - - window.confirmationDialog = params => { const confirmDialog = new Whisper.SessionConfirmView({ el: $('#session-confirm-container'), @@ -816,7 +814,7 @@ hideCancel: params.hideCancel || false, }); confirmDialog.render(); - } + }; window.generateID = () => Math.random() @@ -834,6 +832,7 @@ id: options.id || window.generateID(), description: options.description || '', type: options.type || '', + shouldFade: options.shouldFade, }; // Give all toasts an ID. User may define. diff --git a/js/models/messages.js b/js/models/messages.js index 8cfd7133d..e1abafad2 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1030,9 +1030,10 @@ }, banUser() { - window.Whisper.events.trigger('showConfirmationDialog', { + window.confirmationDialog({ + title: i18n('banUser'), message: i18n('banUserConfirm'), - onOk: async () => { + resolve: async () => { const source = this.get('source'); const conversation = this.getConversation(); diff --git a/js/modules/signal.js b/js/modules/signal.js index 0a023fffe..47b6c5543 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -61,7 +61,9 @@ const { const { SessionToast } = require('../../ts/components/session/SessionToast'); const { SessionToggle } = require('../../ts/components/session/SessionToggle'); const { SessionModal } = require('../../ts/components/session/SessionModal'); -const { SessionConfirm } = require('../../ts/components/session/SessionConfirm'); +const { + SessionConfirm, +} = require('../../ts/components/session/SessionConfirm'); const { SessionDropdown, } = require('../../ts/components/session/SessionDropdown'); diff --git a/js/permissions_popup_start.js b/js/permissions_popup_start.js index 6dc10461a..69fe851d7 100644 --- a/js/permissions_popup_start.js +++ b/js/permissions_popup_start.js @@ -1,4 +1,4 @@ -/* global $, Whisper, i18n */ +/* global $, i18n */ $(document).on('keyup', e => { 'use strict'; @@ -8,7 +8,7 @@ $(document).on('keyup', e => { } }); -const dialogParams = { +window.confirmationDialog({ title: i18n('audioPermissionNeeded'), okText: i18n('allowAccess'), resolve: () => { @@ -18,6 +18,4 @@ const dialogParams = { window.closePermissionsPopup(); }, onClose: window.closePermissionsPopup, -}; -window.confirmationDialog(dialogParams); - +}); diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js index 8d9a7d7fe..17e15899b 100644 --- a/js/views/conversation_view.js +++ b/js/views/conversation_view.js @@ -1308,7 +1308,7 @@ }, forceSend({ contact, message }) { - const dialog = new Whisper.ConfirmationDialogView({ + window.confirmationDialog({ message: i18n('identityKeyErrorOnSend', [ contact.getTitle(), contact.getTitle(), @@ -1328,11 +1328,7 @@ message.resend(contact.id); }, - }); - - this.$el.prepend(dialog.el); - dialog.focusCancel(); }, showSafetyNumber(providedModel) { @@ -1439,14 +1435,11 @@ return; } - const dialog = new Whisper.ConfirmationDialogView({ + window.confirmationDialog({ message: warningMessage, okText: i18n('delete'), resolve: doDelete, }); - - this.$el.prepend(dialog.el); - dialog.focusCancel(); }, deleteMessage(message) { @@ -1670,7 +1663,8 @@ } } - const dialog = new Whisper.ConfirmationDialogView({ + window.confirmationDialog({ + title: i18n('changedSinceVerifiedTitle'), message, okText: i18n('sendAnyway'), resolve: () => { @@ -1680,9 +1674,6 @@ this.focusMessageFieldAndClearDisabled(); }, }); - - this.$el.prepend(dialog.el); - dialog.focusCancel(); }, stripQuery(text, cursorPos) { diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index 8353f5a9a..777af7523 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -54,13 +54,12 @@ toast.render(); }, showConfirmationDialog({ title, message, onOk, onCancel }) { - const dialog = new Whisper.ConfirmationDialogView({ + window.confirmationDialog({ title, message, resolve: onOk, reject: onCancel, }); - this.el.append(dialog.el); }, }); diff --git a/js/views/key_verification_view.js b/js/views/key_verification_view.js index 64a7e87fc..af4965cce 100644 --- a/js/views/key_verification_view.js +++ b/js/views/key_verification_view.js @@ -61,16 +61,14 @@ onSafetyNumberChanged() { this.model.getProfiles().then(this.loadKeys.bind(this)); - const dialog = new Whisper.ConfirmationDialogView({ + window.confirmationDialog({ + title: i18n('changedSinceVerifiedTitle'), message: i18n('changedRightAfterVerify', [ this.model.getTitle(), this.model.getTitle(), ]), hideCancel: true, }); - - dialog.$el.insertBefore(this.el); - dialog.focusCancel(); }, toggleVerified() { this.$('button.verify').attr('disabled', true); diff --git a/js/views/session_confirm_view.js b/js/views/session_confirm_view.js index 4b943e225..4fc0335c8 100644 --- a/js/views/session_confirm_view.js +++ b/js/views/session_confirm_view.js @@ -35,14 +35,14 @@ ok() { this.$('.session-confirm-wrapper').remove(); - if (this.props.resolve){ - this.props.resolve() + if (this.props.resolve) { + this.props.resolve(); } }, cancel() { this.$('.session-confirm-wrapper').remove(); if (this.props.reject) { - this.props.reject() + this.props.reject(); } }, onKeyup(event) { @@ -50,6 +50,5 @@ this.cancel(); } }, - }); })(); diff --git a/js/views/session_toast_view.js b/js/views/session_toast_view.js index 3579a7f69..460862717 100644 --- a/js/views/session_toast_view.js +++ b/js/views/session_toast_view.js @@ -32,13 +32,18 @@ this.props.id = options.id; this.props.description = options.description || ''; this.props.type = options.type || ''; + this.props.shouldFade = options.shouldFade !== false; this.toastView.update(this.props); this.showToast(); - clearTimeout(this.timer); - this.timer = setTimeout(this.fadeToast.bind(this), 4000); + if (this.timer) { + clearTimeout(this.timer); + } + if (this.props.shouldFade) { + this.timer = setTimeout(this.fadeToast.bind(this), 4000); + } }, showToast() { diff --git a/js/views/whisper_view.js b/js/views/whisper_view.js index 4ac7c6f7e..121277475 100644 --- a/js/views/whisper_view.js +++ b/js/views/whisper_view.js @@ -53,13 +53,12 @@ }, confirm(message, okText) { return new Promise((resolve, reject) => { - const dialog = new Whisper.ConfirmationDialogView({ - message, + window.confirmationDialog({ + title: message, okText, resolve, reject, }); - this.$el.append(dialog.el); }); }, }, diff --git a/package_bak.json b/package_bak.json index a2305a59a..ded7bb613 100644 --- a/package_bak.json +++ b/package_bak.json @@ -11,49 +11,63 @@ }, "main": "main.js", "scripts": { - "postinstall": "electron-builder install-app-deps && rimraf node_modules/dtrace-provider", + "postinstall": + "electron-builder install-app-deps && rimraf node_modules/dtrace-provider", "start": "electron .", "start-multi": "NODE_APP_INSTANCE=1 electron .", "start-multi2": "NODE_APP_INSTANCE=2 electron .", - "start-prod": "NODE_ENV=production NODE_APP_INSTANCE=devprod LOKI_DEV=1 electron .", - "start-prod-multi": "NODE_ENV=production NODE_APP_INSTANCE=devprod1 LOKI_DEV=1 electron .", + "start-prod": + "NODE_ENV=production NODE_APP_INSTANCE=devprod LOKI_DEV=1 electron .", + "start-prod-multi": + "NODE_ENV=production NODE_APP_INSTANCE=devprod1 LOKI_DEV=1 electron .", "grunt": "grunt", - "icon-gen": "electron-icon-maker --input=images/icon_1024.png --output=./build", + "icon-gen": + "electron-icon-maker --input=images/icon_1024.png --output=./build", "generate": "yarn icon-gen && yarn grunt", "build": "electron-builder --config.extraMetadata.environment=$SIGNAL_ENV", - "build-release": "export SIGNAL_ENV=production && npm run build -- --config.directories.output=release", + "build-release": + "export SIGNAL_ENV=production && npm run build -- --config.directories.output=release", "sign-release": "node ts/updater/generateSignature.js", - "build-module-protobuf": "pbjs --target static-module --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js", - "clean-module-protobuf": "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js", + "build-module-protobuf": + "pbjs --target static-module --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js", + "clean-module-protobuf": + "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js", "build-protobuf": "yarn build-module-protobuf", "clean-protobuf": "yarn clean-module-protobuf", "prepare-beta-build": "node prepare_beta_build.js", "prepare-import-build": "node prepare_import_build.js", - "publish-to-apt": "NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh", + "publish-to-apt": + "NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh", "test": "yarn test-node && yarn test-electron", "test-view": "NODE_ENV=test yarn run start", "test-lib-view": "NODE_ENV=test-lib yarn run start", "test-loki-view": "NODE_ENV=test-loki yarn run start", "test-electron": "yarn grunt test", - "test-node": "mocha --recursive --exit test/app test/modules ts/test libloki/test/node", - "test-node-coverage": "nyc --reporter=lcov --reporter=text mocha --recursive test/app test/modules ts/test libloki/test/node", - "test-node-coverage-html": "nyc --reporter=lcov --reporter=html mocha --recursive test/app test/modules ts/test libloki/test/node", + "test-node": + "mocha --recursive --exit test/app test/modules ts/test libloki/test/node", + "test-node-coverage": + "nyc --reporter=lcov --reporter=text mocha --recursive test/app test/modules ts/test libloki/test/node", + "test-node-coverage-html": + "nyc --reporter=lcov --reporter=html mocha --recursive test/app test/modules ts/test libloki/test/node", "eslint": "eslint .", "lint": "yarn format --list-different && yarn lint-windows", "dev-lint": "yarn format --list-different; yarn lint-windows", "lint-windows": "yarn eslint && yarn tslint", "lint-deps": "node ts/util/lint/linter.js", "tslint": "tslint --format stylish --project .", - "format": "prettier --write \"*.{css,js,json,md,scss,ts,tsx}\" \"./**/*.{css,js,json,md,scss,ts,tsx}\"", + "format": + "prettier --write \"*.{css,js,json,md,scss,ts,tsx}\" \"./**/*.{css,js,json,md,scss,ts,tsx}\"", "transpile": "tsc", "clean-transpile": "rimraf ts/**/*.js && rimraf ts/*.js", "open-coverage": "open coverage/lcov-report/index.html", "styleguide": "styleguidist server", "pow-metrics": "node metrics_app.js localhost 9000", - "ready": "yarn clean-transpile && yarn grunt && yarn lint && yarn test-node && yarn test-electron && yarn lint-deps" + "ready": + "yarn clean-transpile && yarn grunt && yarn lint && yarn test-node && yarn test-electron && yarn lint-deps" }, "dependencies": { - "@journeyapps/sqlcipher": "https://github.com/scottnonnenberg-signal/node-sqlcipher.git#2e28733b61640556b0272a3bfc78b0357daf71e6", + "@journeyapps/sqlcipher": + "https://github.com/scottnonnenberg-signal/node-sqlcipher.git#2e28733b61640556b0272a3bfc78b0357daf71e6", "@sindresorhus/is": "0.8.0", "@types/dompurify": "^2.0.0", "backbone": "1.3.3", @@ -72,7 +86,8 @@ "emoji-datasource": "4.0.0", "emoji-datasource-apple": "4.0.0", "emoji-js": "3.4.0", - "emoji-panel": "https://github.com/scottnonnenberg-signal/emoji-panel.git#v0.5.5", + "emoji-panel": + "https://github.com/scottnonnenberg-signal/emoji-panel.git#v0.5.5", "filesize": "3.6.1", "firstline": "1.2.1", "form-data": "2.3.2", @@ -205,9 +220,7 @@ "artifactName": "${name}-mac-${version}.${ext}", "category": "public.app-category.social-networking", "icon": "build/icons/mac/icon.icns", - "target": [ - "dmg" - ], + "target": ["dmg"], "bundleVersion": "1", "hardenedRuntime": true, "gatekeeperAssess": false, @@ -228,9 +241,7 @@ "url": "https://updates.signal.org/desktop" } ], - "target": [ - "nsis" - ] + "target": ["nsis"] }, "nsis": { "deleteAppDataOnUninstall": true @@ -241,9 +252,7 @@ "StartupWMClass": "Loki Messenger" }, "asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries", - "target": [ - "deb" - ], + "target": ["deb"], "icon": "build/icons/png" }, "deb": { diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 928731112..228286ead 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -739,14 +739,12 @@ label { margin-left: 75px; } - - .session-loader { display: inline-block; position: relative; width: 80px; height: 80px; - + div { position: absolute; top: 33px; diff --git a/ts/components/AddServerDialog.tsx b/ts/components/AddServerDialog.tsx index c3e24c41e..8be8d4c51 100644 --- a/ts/components/AddServerDialog.tsx +++ b/ts/components/AddServerDialog.tsx @@ -37,7 +37,6 @@ export class AddServerDialog extends React.Component { this.closeDialog = this.closeDialog.bind(this); this.onKeyUp = this.onKeyUp.bind(this); - } public render() { @@ -77,8 +76,8 @@ export class AddServerDialog extends React.Component { {this.state.view === 'connecting' ? ( <>
-
- +
+
@@ -108,18 +107,18 @@ export class AddServerDialog extends React.Component { } if (view === 'connecting') { - - // TODO: Make this not hard coded const channelId = 1; - const serverUrl = String($('.session-modal #server-url').val()).toLowerCase(); + const serverUrl = String( + $('.session-modal #server-url').val() + ).toLowerCase(); this.setState({ error: null, serverUrl: serverUrl, - }) + }); - if (serverUrl.length == 0){ + if (serverUrl.length == 0) { this.setState({ error: i18n('noServerUrl'), view: 'default', @@ -134,23 +133,22 @@ export class AddServerDialog extends React.Component { connecting: true, }); - const connectionResult = this.attemptConnection(serverUrl, channelId); // Give 5s maximum for promise to revole. Else, throw error. const max_connection_duration = 5000; const connectionTimeout = setTimeout(() => { - if (!this.state.success){ - this.showView('default'); - - this.setState({ - connecting: false, - success: false, - error: i18n('connectToServerFail'), - }); + if (!this.state.success) { + this.showView('default'); - return; - } + this.setState({ + connecting: false, + success: false, + error: i18n('connectToServerFail'), + }); + + return; + } }, max_connection_duration); connectionResult @@ -160,7 +158,7 @@ export class AddServerDialog extends React.Component { if (this.state.connecting) { this.setState({ success: true, - }) + }); window.pushToast({ title: i18n('connectToServerSuccess'), id: 'connectToServerSuccess', @@ -169,9 +167,9 @@ export class AddServerDialog extends React.Component { this.closeDialog(); } }) - .catch((error) => { + .catch(error => { clearTimeout(connectionTimeout); - + this.showView('default'); this.setState({ connecting: false, @@ -207,7 +205,7 @@ export class AddServerDialog extends React.Component { private onKeyUp(event: any) { switch (event.key) { case 'Enter': - if (this.state.view == 'default'){ + if (this.state.view == 'default') { this.showView('connecting'); } break; @@ -226,18 +224,20 @@ export class AddServerDialog extends React.Component { private async attemptConnection(serverUrl: string, channelId: number) { const { i18n } = this.props; - + const rawServerUrl = serverUrl .replace(/^https?:\/\//i, '') .replace(/[/\\]+$/i, ''); const sslServerUrl = `https://${rawServerUrl}`; const conversationId = `publicChat:${channelId}@${rawServerUrl}`; - const conversationExists = window.ConversationController.get(conversationId); + const conversationExists = window.ConversationController.get( + conversationId + ); if (conversationExists) { - // We are already a member of this public chat + // We are already a member of this public chat return new Promise((resolve, reject) => { - if (false){ + if (false) { resolve(); } reject(i18n('publicChatExists')); @@ -250,7 +250,7 @@ export class AddServerDialog extends React.Component { if (!serverAPI) { // Url incorrect or server not compatible return new Promise((resolve, reject) => { - if (false){ + if (false) { resolve(); } reject(i18n('connectToServerFail')); diff --git a/ts/components/session/SessionConfirm.tsx b/ts/components/session/SessionConfirm.tsx index e563ad6fa..6c554f297 100644 --- a/ts/components/session/SessionConfirm.tsx +++ b/ts/components/session/SessionConfirm.tsx @@ -7,8 +7,8 @@ interface Props { title: string; onOk?: any; onClose?: any; - onClickOk: any, - onClickClose: any, + onClickOk: any; + onClickClose: any; okText?: string; cancelText?: string; hideCancel: boolean; @@ -18,59 +18,43 @@ export class SessionConfirm extends React.Component { public static defaultProps = { title: '', hideCancel: false, - } + }; constructor(props: any) { super(props); } public render() { - const { title, - message, - onClickOk, - onClickClose, - hideCancel, - } = this.props; + const { title, message, onClickOk, onClickClose, hideCancel } = this.props; const okText = this.props.okText || window.i18n('ok'); const cancelText = this.props.cancelText || window.i18n('cancel'); - const showHeader = !! this.props.title; + const showHeader = !!this.props.title; return ( - null} - onOk={() => null} - showExitIcon={false} - showHeader={showHeader} - > - { showHeader ? null : ( -
+ null} + onOk={() => null} + showExitIcon={false} + showHeader={showHeader} + > + {showHeader ? null :
} + +
+ {message} +
+ +
+ +
+ + + {hideCancel ? null : ( + )} - -
- - {message} - -
- -
- -
- - - { hideCancel ? null : ( - - )} -
- +
+ ); } - } diff --git a/ts/components/session/SessionModal.tsx b/ts/components/session/SessionModal.tsx index 4181e49d4..b77d0aba3 100644 --- a/ts/components/session/SessionModal.tsx +++ b/ts/components/session/SessionModal.tsx @@ -19,12 +19,12 @@ interface State { isVisible: boolean; } -export class SessionModal extends React.PureComponent { +export class SessionModal extends React.PureComponent { public static defaultProps = { showExitIcon: true, showHeader: true, }; - + constructor(props: any) { super(props); this.state = { @@ -43,7 +43,7 @@ export class SessionModal extends React.PureComponent { return isVisible ? (
- { showHeader ? ( + {showHeader ? ( <>
@@ -53,7 +53,7 @@ export class SessionModal extends React.PureComponent { iconSize={SessionIconSize.Small} onClick={this.close} /> - ) : null } + ) : null}
{title}
@@ -71,7 +71,7 @@ export class SessionModal extends React.PureComponent {
- ) : null } + ) : null}
{this.props.children}
diff --git a/ts/components/session/SessionSpinner.tsx b/ts/components/session/SessionSpinner.tsx index 7c41d0cf0..dd33e0688 100644 --- a/ts/components/session/SessionSpinner.tsx +++ b/ts/components/session/SessionSpinner.tsx @@ -1,14 +1,14 @@ import React from 'react'; interface Props { - loading: boolean; + loading: boolean; } export class SessionSpinner extends React.Component { public static defaultProps = { loading: true, - } - + }; + constructor(props: any) { super(props); } @@ -17,11 +17,16 @@ export class SessionSpinner extends React.Component { const { loading } = this.props; return ( - <> - { loading ? ( -
- ) : null } - + <> + {loading ? ( +
+
+
+
+
+
+ ) : null} + ); } -} \ No newline at end of file +}