From 4fe82d28d975c268f1d9b0865d6871c9c0eb2094 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 22 Jan 2020 15:57:58 +1100 Subject: [PATCH 01/11] Version info --- preload.js | 7 +++++ stylesheets/_session.scss | 17 +++++++++++- ts/components/EditProfileDialog.tsx | 7 +++-- .../session/settings/SessionSettings.tsx | 26 ++++++++++++++----- ts/global.d.ts | 2 ++ 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/preload.js b/preload.js index 074afd14c..84478fe43 100644 --- a/preload.js +++ b/preload.js @@ -59,6 +59,13 @@ window.isBeforeVersion = (toCheck, baseVersion) => { } }; +window.versionInfo = { + environment: window.getEnvironment(), + version: window.getVersion(), + commitHash: window.getCommitHash(), + appInstance: window.getAppInstance(), +}; + // temporary clearnet fix process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; window.getSelfSignedCert = () => { diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 01ac68502..b64ba3f2c 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -1130,6 +1130,22 @@ label { } } + &-view { + flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + &__version-info { + display: flex; + justify-content: space-between; + opacity: 0.4; + padding: $session-margin-sm $session-margin-md; + background-color: $session-shade-5; + font-size: $session-font-xs; + } + &__password-lock { display: flex; align-items: center; @@ -1272,7 +1288,6 @@ label { background-color: $session-color-white; border-color: $session-color-white; } - } .user-details-dialog { .session-id-editable { diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index e213bc2bd..0d9a43d66 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -157,15 +157,14 @@ export class EditProfileDialog extends React.Component {
{ - this.setState({ mode: 'qr' }); - }} > { + this.setState({ mode: 'qr' }); + }} />
diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index dd96a1d74..f7ca1d6d6 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -220,13 +220,25 @@ export class SettingsView extends React.Component { showLinkDeviceButton={!shouldRenderPasswordLock} category={category} /> - {shouldRenderPasswordLock ? ( - this.renderPasswordLock() - ) : ( -
- {this.renderSettingInCategory()} -
- )} +
+ {shouldRenderPasswordLock ? ( + this.renderPasswordLock() + ) : ( +
+ {this.renderSettingInCategory()} +
+ )} + {this.renderSessionInfo()} +
+ + ); + } + + public renderSessionInfo(): JSX.Element { + return ( +
+ v{window.versionInfo.version} + {window.versionInfo.commitHash}
); } diff --git a/ts/global.d.ts b/ts/global.d.ts index d1f16e980..997a55148 100644 --- a/ts/global.d.ts +++ b/ts/global.d.ts @@ -1,4 +1,6 @@ interface Window { + versionInfo: any; + Events: any; deleteAllData: any; getAccountManager: any; From 56b1bcac019746cc097fa1c8c6ca2b48f113d80d Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 22 Jan 2020 17:17:15 +1100 Subject: [PATCH 02/11] Partial copy updates --- _locales/en/messages.json | 44 ++++++++++++---------- preload.js | 2 +- stylesheets/_session.scss | 11 +++++- ts/components/EditProfileDialog.tsx | 22 +++++++---- ts/components/session/RegistrationTabs.tsx | 4 +- 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 60b5ddc0c..ecb6f561a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -774,7 +774,7 @@ "description": "Shown to separate the types of search results" }, "messagesHeader": { - "message": "Messages", + "message": "Sessions", "description": "Shown to separate the types of search results" }, "settingsHeader": { @@ -961,6 +961,9 @@ "close": { "message": "Close" }, + "continue": { + "message": "Continue" + }, "pairNewDevice": { "message": "Pair New Device" }, @@ -1070,7 +1073,7 @@ "description": "Label for the time a message was received" }, "sendMessage": { - "message": "Send a message", + "message": " Type your message", "description": "Placeholder text in the message entry field" }, "secondaryDeviceDefaultFR": { @@ -2476,54 +2479,57 @@ "message": "Sign In" }, "yourUniqueSessionID": { - "message": "Your Unique Session ID" + "message": "Say hello to your Session ID" }, "allUsersAreRandomly...": { "message": - "All users are randomly generated a set of numbers that act as their unique Session ID. Share your Session ID in order to chat with your friends!" + "Your Session ID is the unique address people can use to contact you on Session. Your Session ID is totally private, anonymous, and has no connection to your real identity." }, "getStarted": { "message": "Get started" }, "generateSessionID": { - "message": "Generate Session ID" + "message": "Create Session ID" }, "mnemonicSeed": { "message": "Mnemonic Seed" }, "enterSeed": { - "message": "Enter Seed" + "message": "Enter Recovery Phrase" }, "displayName": { "message": "Display Name" }, "enterDisplayName": { - "message": "Enter Display Name / Alias" + "message": "Enter a display name" }, "optionalPassword": { - "message": "Optional Password" + "message": "Verify Password" }, "enterOptionalPassword": { - "message": "Enter Optional Password" + "message": "Enter password (optional)" }, "verifyPassword": { "message": "Verify Password" }, "devicePairingHeader": { "message": - "Open the Session Messenger App on your primary device and select Device Pairing from the main menu. Then, enter your Session ID below to sign in." + "Open Session on your other device and navigate to the Linked Devices section in your user account screen. Select Link a Device to prepare your other device for pairing, then enter your Session ID below to link this device to your Session ID." }, "enterSessionIDHere": { - "message": "Enter your Session ID here" + "message": "Enter other device’s Session ID here" }, "continueYourSession": { - "message": "Continue Your Session" + "message": "Link Device" + }, + "restoreSessionID": { + "message": "Restore Session ID" }, "restoreUsingSeed": { - "message": "Restore Using Seed" + "message": "Restore From Recovery Phrase" }, "linkDeviceToExistingAccount": { - "message": "Link Device To Existing Account" + "message": "Link Device to Existing Session ID" }, "or": { "message": "or" @@ -2536,13 +2542,13 @@ "message": "Begin
your
Session." }, "welcomeToYourSession": { - "message": "Welcome to your Session!" + "message": "Welcome to your Session" }, "completeSignUp": { "message": "Complete Sign Up" }, "compose": { - "message": "Compose" + "message": "New Session" }, "searchForAKeyPhrase": { "message": "Search for a key phrase or contact" @@ -2554,11 +2560,11 @@ "message": "Enter Session ID" }, "pasteSessionIDRecipient": { - "message": "Paste Session ID of recipient" + "message": "Enter a Session ID" }, "usersCanShareTheir...": { "message": - "Users can share their Session ID by going into their account settings and clicking \"Share Public Key\"." + "Users can share their Session ID from their account settings, or by sharing their QR code." }, "searchByIDOrDisplayName": { "message": "Search by ID # or Display Name" @@ -2579,7 +2585,7 @@ "message": "Create Group" }, "yourPublicKey": { - "message": "Your Public Key" + "message": "Your Session ID" }, "accept": { "message": "Accept" diff --git a/preload.js b/preload.js index 84478fe43..341d08f3c 100644 --- a/preload.js +++ b/preload.js @@ -504,7 +504,7 @@ window.SMALL_GROUP_SIZE_LIMIT = 10; window.lokiFeatureFlags = { multiDeviceUnpairing: true, - privateGroupChats: false, + privateGroupChats: true, }; // eslint-disable-next-line no-extend-native,func-names diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index b64ba3f2c..8ee6dc6d5 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -1140,10 +1140,19 @@ label { &__version-info { display: flex; justify-content: space-between; - opacity: 0.4; + padding: $session-margin-sm $session-margin-md; background-color: $session-shade-5; font-size: $session-font-xs; + + span{ + opacity: 0.4; + transition: $session-transition-duration; + + &:hover { + opacity: 1; + } + } } &__password-lock { diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index 0d9a43d66..8a8c47cca 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -140,10 +140,7 @@ export class EditProfileDialog extends React.Component { className="image-upload-section" role="button" onClick={() => { - const el = this.inputEl.current; - if (el) { - el.click(); - } + this.setState({mode: 'edit'}, this.fireInputEvent); }} > { onChange={this.onFileSelected} /> -
+
{ ); } + private fireInputEvent() { + const el = this.inputEl.current; + if (el) { + el.click(); + } + } + private renderDefaultView() { return ( <> @@ -273,7 +275,9 @@ export class EditProfileDialog extends React.Component { private onKeyUp(event: any) { switch (event.key) { case 'Enter': - this.onClickOK(); + if (this.state.mode === 'edit'){ + this.onClickOK(); + } break; case 'Esc': case 'Escape': @@ -297,6 +301,8 @@ export class EditProfileDialog extends React.Component { const newName = this.state.profileName.trim(); if (newName === '') { + this.setState({mode: 'default'}); + return; } diff --git a/ts/components/session/RegistrationTabs.tsx b/ts/components/session/RegistrationTabs.tsx index 1602bcfbe..4824de3b5 100644 --- a/ts/components/session/RegistrationTabs.tsx +++ b/ts/components/session/RegistrationTabs.tsx @@ -299,7 +299,7 @@ export class RegistrationTabs extends React.Component<{}, State> { }} buttonType={SessionButtonType.Brand} buttonColor={SessionButtonColor.Green} - text={window.i18n('completeSignUp')} + text={window.i18n('getStarted')} disabled={!enableCompleteSignUp} />
@@ -337,7 +337,7 @@ export class RegistrationTabs extends React.Component<{}, State> { if (signUpMode !== SignUpMode.Default) { buttonType = SessionButtonType.Brand; buttonColor = SessionButtonColor.Green; - buttonText = window.i18n('getStarted'); + buttonText = window.i18n('continue'); } else { buttonType = SessionButtonType.BrandOutline; buttonColor = SessionButtonColor.Green; From 3dd18a0c9ccbe508ac8db96663d3a8abae21b64e Mon Sep 17 00:00:00 2001 From: Vincent Date: Fri, 24 Jan 2020 12:26:15 +1100 Subject: [PATCH 03/11] Profile picture upload, fixes and copy --- _locales/en/messages.json | 19 ++- background.html | 36 ----- js/background.js | 6 +- js/models/conversations.js | 7 +- js/views/edit_profile_dialog_view.js | 11 +- js/views/inbox_view.js | 3 +- stylesheets/_mentions.scss | 6 +- stylesheets/_session.scss | 10 +- ts/components/EditProfileDialog.tsx | 54 ++++--- ts/components/conversation/MemberList.tsx | 5 +- ts/components/session/ActionsPanel.tsx | 182 ++++++++++++---------- ts/global.d.ts | 3 + 12 files changed, 176 insertions(+), 166 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index ecb6f561a..b13f8cb7e 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1182,7 +1182,8 @@ "description": "Warning for account deletion in settings view" }, "deleteAccountWarningSub": { - "message": "This is completely irreversible and will leave no trace.", + "message": + "Delete all history, including all messages, sessions, and contacts. Once deleted, these cannot be restored.", "description": "Warning for account deletion in settings view" }, "deleteContact": { @@ -1355,7 +1356,8 @@ "Option to control creation and send of link previews in setting screen" }, "linkPreviewDescription": { - "message": "Enable link previews", + "message": + "Link previews supported for Imgur, Instagram, Pinterest, Reddit, and YouTube.", "description": "Description shown for the Link Preview option " }, "mediaPermissionsTitle": { @@ -1442,17 +1444,17 @@ "description": "Label for disabling notifications" }, "nameAndMessage": { - "message": "Both sender name and message", + "message": "Name and content", "description": "Label for setting notifications to display name and message text" }, "noNameOrMessage": { - "message": "Neither name nor message", + "message": "No name or content", "description": "Label for setting notifications to display no name and no message text" }, "nameOnly": { - "message": "Only sender name", + "message": "Name Only", "description": "Label for setting notifications to display sender name only" }, "newMessage": { @@ -2132,6 +2134,10 @@ "message": "Copied public key", "description": "A toast message telling the user that the key was copied" }, + "copiedChatId": { + "message": "Copied chat ID", + "description": "A toast message telling the user that the key was copied" + }, "copyMessage": { "message": "Copy message text", "description": @@ -2175,7 +2181,8 @@ "description": "Prompt for user to set account password in settings view" }, "setAccountPasswordDescription": { - "message": "Secure your account and public key with a password", + "message": + "Require password to unlock Session’s screen.You can still receive message notifications while Screen Lock is enabled. Loki Messenger’s notification settings allow you to customize information that is displayed", "description": "Description for set account password setting view" }, "changeAccountPasswordTitle": { diff --git a/background.html b/background.html index 3a4f7e988..429fa65b7 100644 --- a/background.html +++ b/background.html @@ -192,42 +192,6 @@
- - - + + -
diff --git a/password_preload.js b/password_preload.js index 8d8a5b7de..1144878ea 100644 --- a/password_preload.js +++ b/password_preload.js @@ -8,6 +8,9 @@ const config = url.parse(window.location.toString(), true).query; const { locale } = config; const localeMessages = ipcRenderer.sendSync('locale-data'); +window.React = require('react'); +window.ReactDOM = require('react-dom'); + window.theme = config.theme; window.i18n = i18n.setup(locale, localeMessages); @@ -17,6 +20,9 @@ window.getAppInstance = () => config.appInstance; // So far we're only using this for Signal.Types const Signal = require('./js/modules/signal'); +const electron = require('electron'); + +const ipc = electron.ipcRenderer; window.Signal = Signal.setup({ Attachments: null, @@ -24,12 +30,32 @@ window.Signal = Signal.setup({ getRegionCode: () => null, }); +window.Signal.Logs = require('./js/modules/logs'); + +window.CONSTANTS = { + MAX_LOGIN_TRIES: 3, + MAX_PASSWORD_LENGTH: 32, + MAX_USERNAME_LENGTH: 20, +}; + window.passwordUtil = require('./app/password_util'); +window.Signal.Logs = require('./js/modules/logs'); window.resetDatabase = () => { window.log.info('reset database'); ipcRenderer.send('resetDatabase'); }; + +window.restart = () => { + window.log.info('restart'); + ipc.send('restart'); +}; + +window.clearLocalData = async () => { + window.resetDatabase(); + window.restart(); +}; + window.onLogin = passPhrase => new Promise((resolve, reject) => { ipcRenderer.once('password-window-login-response', (event, error) => { diff --git a/preload.js b/preload.js index 338143a47..2445648c0 100644 --- a/preload.js +++ b/preload.js @@ -60,8 +60,9 @@ window.isBeforeVersion = (toCheck, baseVersion) => { }; window.CONSTANTS = { - maxPasswordLength: 32, - maxUsernameLength: 20, + MAX_LOGIN_TRIES: 3, + MAX_PASSWORD_LENGTH: 32, + MAX_USERNAME_LENGTH: 20, }; window.versionInfo = { @@ -134,6 +135,11 @@ window.restart = () => { ipc.send('restart'); }; +window.resetDatabase = () => { + window.log.info('reset database'); + ipc.send('resetDatabase'); +}; + // Events for updating block number states across different windows. // In this case we need these to update the blocked number // collection on the main window from the settings window. diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 9bf8a4372..2fee6682c 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -225,6 +225,7 @@ $session_message-container-border-radius: 5px; } .button-group > div { + display: inline-flex; margin-left: 5px; margin-right: 5px; } @@ -258,6 +259,10 @@ $session_message-container-border-radius: 5px; &.brand { color: $session-color-white; + &:hover { + filter: brightness(90%); + } + &.green, &.white, &.primary, @@ -1438,3 +1443,89 @@ input { } } } + +.clear-data, +.password-prompt { + &-wrapper { + display: flex; + justify-content: center; + align-items: center; + + background-color: $session-color-black; + + width: 100%; + height: 100%; + + padding: 3 * $session-margin-lg; + } + + &-error-section { + width: 100%; + color: $session-color-white; + margin: -$session-margin-sm 0px 2 * $session-margin-lg 0px; + + .session-label { + &.primary { + background-color: rgba($session-color-primary, 0.3); + } + padding: $session-margin-xs $session-margin-sm; + font-size: $session-font-xs; + text-align: center; + } + } + + &-container { + font-family: 'SF Pro Text'; + color: $session-color-white; + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + + width: 600px; + min-width: 420px; + padding: 3 * $session-margin-lg 2 * $session-margin-lg; + box-sizing: border-box; + background-color: $session-shade-4; + border: 1px solid $session-shade-8; + border-radius: 2px; + + .warning-info-area, + .password-info-area { + display: inline-flex; + justify-content: center; + align-items: center; + + h1 { + color: $session-color-white; + } + svg { + margin-right: $session-margin-lg; + } + } + + p, + input { + margin: $session-margin-lg 0px; + } + + .button-group { + display: inline-flex; + } + + #password-prompt-input { + width: 100%; + color: #fff; + background-color: #2e2e2e; + margin-top: 2 * $session-margin-lg; + padding: $session-margin-xs $session-margin-lg; + outline: none; + border: none; + border-radius: 2px; + text-align: center; + font-size: 24px; + letter-spacing: 5px; + font-family: 'SF Pro Text'; + } + } +} diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index 959601298..555986cdc 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -208,7 +208,7 @@ export class EditProfileDialog extends React.Component { value={this.state.profileName} placeholder={placeholderText} onChange={this.onNameEdited} - maxLength={window.CONSTANTS.maxUsernameLength} + maxLength={window.CONSTANTS.MAX_USERNAME_LENGTH} tabIndex={0} required={true} aria-required={true} @@ -302,7 +302,10 @@ export class EditProfileDialog extends React.Component { private onClickOK() { const newName = this.state.profileName.trim(); - if (newName.length === 0 || newName.length > window.CONSTANTS.maxUsernameLength) { + if ( + newName.length === 0 || + newName.length > window.CONSTANTS.MAX_USERNAME_LENGTH + ) { return; } diff --git a/ts/components/session/ActionsPanel.tsx b/ts/components/session/ActionsPanel.tsx index 073d69d23..cc2601893 100644 --- a/ts/components/session/ActionsPanel.tsx +++ b/ts/components/session/ActionsPanel.tsx @@ -64,7 +64,8 @@ export class ActionsPanel extends React.Component { const handleClick = onSelect ? () => { type === SectionType.Profile - ? this.editProfileHandle() + ? /* tslint:disable-next-line:no-void-expression */ + this.editProfileHandle() : /* tslint:disable-next-line:no-void-expression */ onSelect(type); } diff --git a/ts/components/session/RegistrationTabs.tsx b/ts/components/session/RegistrationTabs.tsx index cd1adc7e7..1f8bc5c31 100644 --- a/ts/components/session/RegistrationTabs.tsx +++ b/ts/components/session/RegistrationTabs.tsx @@ -449,7 +449,7 @@ export class RegistrationTabs extends React.Component<{}, State> { type="text" placeholder={window.i18n('enterDisplayName')} value={this.state.displayName} - maxLength={window.CONSTANTS.maxUsernameLength} + maxLength={window.CONSTANTS.MAX_USERNAME_LENGTH} onValueChanged={(val: string) => { this.onDisplayNameChanged(val); }} @@ -463,7 +463,7 @@ export class RegistrationTabs extends React.Component<{}, State> { error={this.state.passwordErrorString} type="password" placeholder={window.i18n('enterOptionalPassword')} - maxLength={window.CONSTANTS.maxPasswordLength} + maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH} onValueChanged={(val: string) => { this.onPasswordChanged(val); }} @@ -477,7 +477,7 @@ export class RegistrationTabs extends React.Component<{}, State> { error={passwordsDoNotMatch} type="password" placeholder={window.i18n('optionalPassword')} - maxLength={window.CONSTANTS.maxPasswordLength} + maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH} onValueChanged={(val: string) => { this.onPasswordVerifyChanged(val); }} diff --git a/ts/components/session/SessionInput.tsx b/ts/components/session/SessionInput.tsx index ab892a5d0..11432e80a 100644 --- a/ts/components/session/SessionInput.tsx +++ b/ts/components/session/SessionInput.tsx @@ -34,7 +34,14 @@ export class SessionInput extends React.PureComponent { } public render() { - const { placeholder, type, value, maxLength, enableShowHide, error } = this.props; + const { + placeholder, + type, + value, + maxLength, + enableShowHide, + error, + } = this.props; const { forceShow } = this.state; const correctType = forceShow ? 'text' : type; diff --git a/ts/components/session/SessionPasswordModal.tsx b/ts/components/session/SessionPasswordModal.tsx index c939cbfcb..fe626db39 100644 --- a/ts/components/session/SessionPasswordModal.tsx +++ b/ts/components/session/SessionPasswordModal.tsx @@ -58,14 +58,14 @@ export class SessionPasswordModal extends React.Component { type="password" id="password-modal-input" placeholder={placeholders[0]} - maxLength={window.CONSTANTS.maxPasswordLength} + maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH} /> {action !== PasswordAction.Remove && ( )}
@@ -120,7 +120,7 @@ export class SessionPasswordModal extends React.Component { $('#password-modal-input-confirm').val() ); - if (enteredPassword.length === 0 || enteredPasswordConfirm.length === 0){ + if (enteredPassword.length === 0 || enteredPasswordConfirm.length === 0) { return; } diff --git a/ts/components/session/SessionPasswordPrompt.tsx b/ts/components/session/SessionPasswordPrompt.tsx new file mode 100644 index 000000000..a48af57ce --- /dev/null +++ b/ts/components/session/SessionPasswordPrompt.tsx @@ -0,0 +1,196 @@ +import React from 'react'; +import classNames from 'classnames'; + +import { SessionIcon, SessionIconType } from './icon'; +import { + SessionButton, + SessionButtonColor, + SessionButtonType, +} from './SessionButton'; + +interface State { + error: string; + errorCount: number; + clearDataView: boolean; +} + +export class SessionPasswordPrompt extends React.PureComponent<{}, State> { + constructor(props: any) { + super(props); + + this.state = { + error: '', + errorCount: 0, + clearDataView: false, + }; + + this.onKeyUp = this.onKeyUp.bind(this); + this.initLogin = this.initLogin.bind(this); + this.initClearDataView = this.initClearDataView.bind(this); + + window.addEventListener('keyup', this.onKeyUp); + } + + public render() { + const showResetElements = + this.state.errorCount >= window.CONSTANTS.MAX_LOGIN_TRIES; + + const wrapperClass = this.state.clearDataView + ? 'clear-data-wrapper' + : 'password-prompt-wrapper'; + const containerClass = this.state.clearDataView + ? 'clear-data-container' + : 'password-prompt-container'; + const infoAreaClass = this.state.clearDataView + ? 'warning-info-area' + : 'password-info-area'; + const infoTitle = this.state.clearDataView + ? window.i18n('clearDataHeader') + : window.i18n('passwordViewTitle'); + const buttonGroup = this.state.clearDataView + ? this.renderClearDataViewButtons() + : this.renderPasswordViewButtons(); + const featureElement = this.state.clearDataView ? ( +

{window.i18n('clearDataExplanation')}

+ ) : ( + + ); + const infoIcon = this.state.clearDataView ? ( + + ) : ( + + ); + const errorSection = !this.state.clearDataView && ( +
+ {this.state.error && ( + <> + {showResetElements ? ( +
+ {window.i18n('maxPasswordAttempts')} +
+ ) : ( +
{this.state.error}
+ )} + + )} +
+ ); + + return ( +
+
+
+ {infoIcon} + +

{infoTitle}

+
+ + {featureElement} + {errorSection} + {buttonGroup} +
+
+ ); + } + + public async onKeyUp(event: any) { + switch (event.key) { + case 'Enter': + await this.initLogin(); + break; + default: + } + event.preventDefault(); + } + + public async onLogin(passPhrase: string) { + const trimmed = passPhrase ? passPhrase.trim() : passPhrase; + + try { + await window.onLogin(trimmed); + } catch (e) { + // Increment the error counter and show the button if necessary + this.setState({ + errorCount: this.state.errorCount + 1, + }); + + this.setState({ error: e }); + } + } + + private async initLogin() { + const passPhrase = String($('#password-prompt-input').val()); + await this.onLogin(passPhrase); + } + + private initClearDataView() { + this.setState({ + error: '', + errorCount: 0, + clearDataView: true, + }); + } + + private renderPasswordViewButtons(): JSX.Element { + const showResetElements = + this.state.errorCount >= window.CONSTANTS.MAX_LOGIN_TRIES; + + return ( +
+ {showResetElements && ( + <> + + + )} + +
+ ); + } + + private renderClearDataViewButtons(): JSX.Element { + return ( +
+ { + this.setState({ clearDataView: false }); + }} + /> + + +
+ ); + } +} diff --git a/ts/components/session/SessionScrollButton.tsx b/ts/components/session/SessionScrollButton.tsx index 39644e0d6..6c6950611 100644 --- a/ts/components/session/SessionScrollButton.tsx +++ b/ts/components/session/SessionScrollButton.tsx @@ -1,12 +1,8 @@ import React from 'react'; -import { SessionIconButton, SessionIconType, SessionIconSize } from './icon'; +import { SessionIconButton, SessionIconSize, SessionIconType } from './icon'; -interface Props { - count: number; -} - -export class SessionScrollButton extends React.PureComponent { +export class SessionScrollButton extends React.PureComponent { constructor(props: any) { super(props); } diff --git a/ts/components/session/icon/SessionIcon.tsx b/ts/components/session/icon/SessionIcon.tsx index 6f1bb4b0b..de8e7c43c 100644 --- a/ts/components/session/icon/SessionIcon.tsx +++ b/ts/components/session/icon/SessionIcon.tsx @@ -5,7 +5,7 @@ import { icons, SessionIconSize, SessionIconType } from '../icon'; export interface Props { iconType: SessionIconType; - iconSize: SessionIconSize; + iconSize: SessionIconSize | number; iconColor: string; iconPadded: boolean; iconRotation: number; @@ -33,21 +33,25 @@ export class SessionIcon extends React.PureComponent { } = this.props; let iconDimensions; - switch (iconSize) { - case SessionIconSize.Small: - iconDimensions = '15'; - break; - case SessionIconSize.Medium: - iconDimensions = '20'; - break; - case SessionIconSize.Large: - iconDimensions = '25'; - break; - case SessionIconSize.Huge: - iconDimensions = '30'; - break; - default: - iconDimensions = '20'; + if (typeof iconSize === 'number') { + iconDimensions = iconSize; + } else { + switch (iconSize) { + case SessionIconSize.Small: + iconDimensions = '15'; + break; + case SessionIconSize.Medium: + iconDimensions = '20'; + break; + case SessionIconSize.Large: + iconDimensions = '25'; + break; + case SessionIconSize.Huge: + iconDimensions = '30'; + break; + default: + iconDimensions = '20'; + } } const iconDef = icons[iconType]; diff --git a/ts/global.d.ts b/ts/global.d.ts index 0a426177f..dda00f796 100644 --- a/ts/global.d.ts +++ b/ts/global.d.ts @@ -4,6 +4,7 @@ interface Window { Events: any; deleteAllData: any; + clearLocalData: any; getAccountManager: any; mnemonic: any; clipboard: any; @@ -23,6 +24,7 @@ interface Window { // Following function needs to be written in background.js // getMemberList: any; + onLogin: any; setPassword: any; textsecure: any; Session: any; @@ -50,6 +52,8 @@ interface Window { getSettingValue: any; setSettingValue: any; lokiFeatureFlags: any; + + resetDatabase: any; } interface Promise { From f893ef154e972a10112d0a6bfd69b2af4ccce785 Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 28 Jan 2020 16:46:47 +1100 Subject: [PATCH 10/11] touchups --- ts/components/session/SessionPasswordPrompt.tsx | 2 +- ts/components/session/settings/SessionSettings.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ts/components/session/SessionPasswordPrompt.tsx b/ts/components/session/SessionPasswordPrompt.tsx index a48af57ce..4cf06c425 100644 --- a/ts/components/session/SessionPasswordPrompt.tsx +++ b/ts/components/session/SessionPasswordPrompt.tsx @@ -57,8 +57,8 @@ export class SessionPasswordPrompt extends React.PureComponent<{}, State> { id="password-prompt-input" type="password" autoFocus={true} - placeholder=" " defaultValue="" + placeholder={' '} maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH} /> ); diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index 9b3168911..b0623fdef 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -156,6 +156,7 @@ export class SettingsView extends React.Component { id="password-lock-input" defaultValue="" placeholder={' '} + maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH} />
From e73c4e5301762f97169c85eaea23165dc8c7ec80 Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 28 Jan 2020 16:51:27 +1100 Subject: [PATCH 11/11] Resolving Bilb revisions --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index ca1001bb6..ac5ae93f8 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -2673,7 +2673,7 @@ "message": "Enter Open Group URL" }, "channelUrlPlaceholder": { - "message": "https://myopengroup.lokinet.org" + "message": "https://chat.lokinet.org" }, "addChannelDescription": { "message": "Enter an open group URL."