add back link device in settings in a dialog

pull/725/head
Audric Ackermann 5 years ago
parent 29da7c2d53
commit 4d950f859b

@ -979,6 +979,9 @@
"allowPairing": { "allowPairing": {
"message": "Allow Pairing" "message": "Allow Pairing"
}, },
"allowPairingWithDevice": {
"message": "Allow pairing with this device?"
},
"provideDeviceAlias": { "provideDeviceAlias": {
"message": "Please provide an alias for this paired device" "message": "Please provide an alias for this paired device"
}, },
@ -2601,7 +2604,7 @@
"message": "Devices" "message": "Devices"
}, },
"devicesSettingsDescription": { "devicesSettingsDescription": {
"message": "Managed linked devices" "message": "Manage linked devices"
}, },
"mnemonicEmpty": { "mnemonicEmpty": {
"message": "Seed is mandatory" "message": "Seed is mandatory"
@ -2645,5 +2648,20 @@
}, },
"description": { "description": {
"message": "Description" "message": "Description"
},
"filterReceivedRequests": {
"message": "Filter received requests"
},
"secretWords": {
"message": "Secret words:"
},
"pairingDevice": {
"message": "Pairing Device"
},
"gotPairingRequest": {
"message": "Got a pairing request"
},
"devicePairedSuccessfully": {
"message": "Device paired successfully"
} }
} }

@ -216,28 +216,6 @@
showDevicePairingDialog() { showDevicePairingDialog() {
const dialog = new Whisper.DevicePairingDialogView(); const dialog = new Whisper.DevicePairingDialogView();
dialog.on('startReceivingRequests', () => {
Whisper.events.on('devicePairingRequestReceived', pubKey =>
dialog.requestReceived(pubKey)
);
});
dialog.on('stopReceivingRequests', () => {
Whisper.events.off('devicePairingRequestReceived');
});
dialog.on('devicePairingRequestAccepted', (pubKey, cb) =>
Whisper.events.trigger('devicePairingRequestAccepted', pubKey, cb)
);
dialog.on('devicePairingRequestRejected', pubKey =>
Whisper.events.trigger('devicePairingRequestRejected', pubKey)
);
dialog.on('deviceUnpairingRequested', pubKey =>
Whisper.events.trigger('deviceUnpairingRequested', pubKey)
);
dialog.once('close', () => {
Whisper.events.off('devicePairingRequestReceived');
});
this.el.append(dialog.el); this.el.append(dialog.el);
}, },
showDevicePairingWordsDialog() { showDevicePairingWordsDialog() {

@ -576,14 +576,6 @@
h4 { h4 {
margin-top: 8px; margin-top: 8px;
margin-bottom: 16px; margin-bottom: 16px;
white-space: -moz-pre-wrap; /* Mozilla */
white-space: -hp-pre-wrap; /* HP printers */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: pre-wrap; /* CSS 2.1 */
white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
word-wrap: break-word; /* IE */
word-break: break-all;
} }
} }

@ -677,17 +677,13 @@ label {
justify-content: flex-end; justify-content: flex-end;
.session-button { .session-button {
margin-left: $session-margin-sm; margin: $session-margin-xs;
} }
&__center { &__center {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.session-button {
margin: 0 $session-margin-xs;
}
} }
&__text-highlight { &__text-highlight {
@ -915,20 +911,23 @@ label {
&-header { &-header {
display: flex; display: flex;
flex-direction: row;
justify-content: center; justify-content: center;
align-items: center;
background-color: $session-shade-6; background-color: $session-shade-6;
height: $main-view-header-height; height: $main-view-header-height;
line-height: $main-view-header-height;
font-weight: bold;
font-size: 18px;
&-title {
line-height: $main-view-header-height;
font-weight: bold;
font-size: 18px;
text-align: center;
flex-grow: 1;
}
.session-button,
.session-icon-button { .session-icon-button {
display: flex; margin-right: $session-margin-lg;
justify-content: center;
position: absolute;
right: $session-margin-lg;
align-items: center;
height: $main-view-header-height;
} }
} }

@ -248,3 +248,7 @@
color: $session-color-light-grey; color: $session-color-light-grey;
font-size: 13px; font-size: 13px;
} }
.registration-content-centered {
text-align: center;
}

@ -1,30 +1,22 @@
import React from 'react'; import React, { ChangeEvent } from 'react';
import { QRCode } from 'react-qr-svg'; import { QRCode } from 'react-qr-svg';
import { SessionModal } from './session/SessionModal'; import { SessionModal } from './session/SessionModal';
import { SessionButton } from './session/SessionButton'; import { SessionButton } from './session/SessionButton';
import { SessionSpinner } from './session/SessionSpinner';
interface Props { interface Props {
i18n: any;
onClose: any; onClose: any;
pubKeyToUnpair: string | null;
pubKey: string | null;
} }
interface State { interface State {
currentPubKey: string | null; currentPubKey: string | null;
accepted: boolean; accepted: boolean;
isListening: boolean;
success: boolean;
loading: boolean;
view:
| 'default'
| 'waitingForRequest'
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair';
pubKeyRequests: Array<any>; pubKeyRequests: Array<any>;
data: Array<any>; currentView: 'filterRequestView' | 'qrcodeView';
errors: any;
loading: boolean;
deviceAlias: string | null;
} }
export class DevicePairingDialog extends React.Component<Props, State> { export class DevicePairingDialog extends React.Component<Props, State> {
@ -33,156 +25,149 @@ export class DevicePairingDialog extends React.Component<Props, State> {
this.closeDialog = this.closeDialog.bind(this); this.closeDialog = this.closeDialog.bind(this);
this.onKeyUp = this.onKeyUp.bind(this); this.onKeyUp = this.onKeyUp.bind(this);
this.startReceivingRequests = this.startReceivingRequests.bind(this);
this.stopReceivingRequests = this.stopReceivingRequests.bind(this); this.stopReceivingRequests = this.stopReceivingRequests.bind(this);
this.startReceivingRequests = this.startReceivingRequests.bind(this);
this.getPubkeyName = this.getPubkeyName.bind(this); this.getPubkeyName = this.getPubkeyName.bind(this);
this.skipDevice = this.skipDevice.bind(this);
this.allowDevice = this.allowDevice.bind(this);
this.validateSecondaryDevice = this.validateSecondaryDevice.bind(this);
this.handleUpdateDeviceAlias = this.handleUpdateDeviceAlias.bind(this);
this.state = { this.state = {
currentPubKey: this.props.pubKey, currentPubKey: null,
accepted: false, accepted: false,
isListening: false, pubKeyRequests: Array(),
success: false, currentView: 'qrcodeView',
loading: true, loading: false,
view: 'default', errors: undefined,
pubKeyRequests: [], deviceAlias: null,
data: [],
}; };
} }
public componentDidMount() { public componentWillMount() {
this.getSecondaryDevices(); this.startReceivingRequests();
} }
public render() { public componentWillUnmount() {
const { i18n } = this.props; this.closeDialog();
}
const waitingForRequest = this.state.view === 'waitingForRequest'; /*
const nothingPaired = this.state.data.length === 0; dialog.on('deviceUnpairingRequested', pubKey =>
Whisper.events.trigger('deviceUnpairingRequested', pubKey)
);*/
public renderFilterRequestsView() {
const { currentPubKey, accepted, deviceAlias } = this.state;
const secretWords = window.mnemonic.pubkey_to_secret_words(currentPubKey);
const deviceAliasPlaceholder = this.getPubkeyName(currentPubKey);
const deviceName = deviceAliasPlaceholder.deviceAlias;
if (accepted) {
return (
<SessionModal
title={window.i18n('provideDeviceAlias')}
onOk={() => null}
onClose={this.closeDialog}
>
<div className="session-modal__centered">
<input onChange={this.handleUpdateDeviceAlias}>{deviceName}</input>
<div className="session-modal__button-group">
<SessionButton
text={window.i18n('ok')}
onClick={this.validateSecondaryDevice}
disabled={!deviceAlias}
/>
</div>
<SessionSpinner loading={this.state.loading} />
</div>
</SessionModal>
);
}
return (
<SessionModal
title={window.i18n('allowPairingWithDevice')}
onOk={() => null}
onClose={this.closeDialog}
>
<div className="session-modal__centered">
<label>{window.i18n('secretWords')}</label>
<div className="text-subtle">{secretWords}</div>
<div className="session-modal__button-group">
<SessionButton
text={window.i18n('skip')}
onClick={this.skipDevice}
/>
<SessionButton
text={window.i18n('allowPairing')}
onClick={this.allowDevice}
/>
</div>
</div>
</SessionModal>
);
}
public renderQrCodeView() {
const theme = window.Events.getThemeSetting(); const theme = window.Events.getThemeSetting();
const requestReceived = this.hasReceivedRequests();
const title = window.i18n('pairingDevice');
// Foreground equivalent to .session-modal background color // Foreground equivalent to .session-modal background color
const bgColor = 'rgba(0, 0, 0, 0)'; const bgColor = 'rgba(0, 0, 0, 0)';
const fgColor = theme === 'dark' ? '#FFFFFF' : '#1B1B1B'; const fgColor = theme === 'dark' ? '#FFFFFF' : '#1B1B1B';
// const renderPairedDevices = this.state.data.map((pubKey: any) => {
// const pubKeyInfo = this.getPubkeyName(pubKey);
// const isFinalItem =
// this.state.data[this.state.data.length - 1] === pubKey;
// return (
// <div key={pubKey}>
// <p>
// {pubKeyInfo.deviceAlias}
// <br />
// <span className="text-subtle">Pairing Secret:</span>{' '}
// {pubKeyInfo.secretWords}
// </p>
// {!isFinalItem ? <hr className="text-soft fullwidth" /> : null}
// </div>
// );
// });
return ( return (
<> <SessionModal title={title} onOk={() => null} onClose={this.closeDialog}>
{!this.state.loading && ( <div className="session-modal__centered">
<SessionModal <h4>{window.i18n('waitingForDeviceToRegister')}</h4>
title={i18n('pairedDevices')} <small className="text-subtle">
onOk={() => null} {window.i18n('pairNewDevicePrompt')}
onClose={this.closeDialog} </small>
> <div className="spacer-lg" />
{waitingForRequest ? (
<div className="session-modal__centered"> <div id="qr">
<h3>{i18n('waitingForDeviceToRegister')}</h3> <QRCode
<small className="text-subtle"> value={window.textsecure.storage.user.getNumber()}
{i18n('pairNewDevicePrompt')} bgColor={bgColor}
</small> fgColor={fgColor}
<div className="spacer-lg" /> level="L"
/>
<div id="qr"> </div>
<QRCode
value={window.textsecure.storage.user.getNumber()} <div className="spacer-lg" />
bgColor={bgColor} <div className="session-modal__button-group__center">
fgColor={fgColor} {!requestReceived ? (
level="L" <SessionButton
/> text={window.i18n('cancel')}
</div> onClick={this.closeDialog}
/>
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('cancel')}
onClick={this.stopReceivingRequests}
/>
</div>
</div>
) : ( ) : (
<> <div className="session-modal__button-group">
{nothingPaired ? ( <SessionButton
<div className="session-modal__centered"> text={window.i18n('filterReceivedRequests')}
<div>{i18n('noPairedDevices')}</div> onClick={this.stopReceivingRequests}
</div> />
) : ( </div>
<div className="session-modal__centered">
{'renderPairedDevices'}
</div>
)}
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('pairNewDevice')}
onClick={this.startReceivingRequests}
/>
</div>
</>
)} )}
</SessionModal> </div>
)} </div>
</> </SessionModal>
); );
} }
private showView( public render() {
view?: const { currentView } = this.state;
| 'default' const renderQrCodeView = currentView === 'qrcodeView';
| 'waitingForRequest' const renderFilterRequestView = currentView === 'filterRequestView';
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair'
) {
if (!view) {
this.setState({
view: 'default',
});
return;
}
if (view === 'waitingForRequest') {
this.setState({
view,
isListening: true,
});
return;
}
this.setState({ view });
}
private getSecondaryDevices() {
const secondaryDevices = window.libloki.storage
.getSecondaryDevicesFor(this.state.currentPubKey)
.then(() => {
this.setState({
data: secondaryDevices,
loading: false,
});
});
}
private startReceivingRequests() { return (
this.showView('waitingForRequest'); <>
{renderQrCodeView && this.renderQrCodeView()}
{renderFilterRequestView && this.renderFilterRequestsView()}
</>
);
} }
private getPubkeyName(pubKey: string | null) { private getPubkeyName(pubKey: string | null) {
@ -197,74 +182,104 @@ export class DevicePairingDialog extends React.Component<Props, State> {
return { deviceAlias, secretWords }; return { deviceAlias, secretWords };
} }
private reset() {
this.setState({
currentPubKey: null,
accepted: false,
pubKeyRequests: Array(),
currentView: 'filterRequestView',
deviceAlias: null,
});
}
private startReceivingRequests() {
this.reset();
window.Whisper.events.on(
'devicePairingRequestReceived',
(pubKey: string) => {
this.requestReceived(pubKey);
}
);
this.setState({ currentView: 'qrcodeView' });
}
private stopReceivingRequests() { private stopReceivingRequests() {
if (this.state.success) { this.setState({ currentView: 'filterRequestView' });
const aliasKey = 'deviceAlias'; window.Whisper.events.off('devicePairingRequestReceived');
const deviceAlias = this.getPubkeyName(this.state.currentPubKey)[ }
aliasKey
];
private requestReceived(secondaryDevicePubKey: string | EventHandlerNonNull) {
// FIFO: push at the front of the array with unshift()
this.state.pubKeyRequests.unshift(secondaryDevicePubKey);
window.pushToast({
title: window.i18n('gotPairingRequest'),
description: `${window.shortenPubkey(
secondaryDevicePubKey
)} ${window.i18n(
'showPairingWordsTitle'
)}: ${window.mnemonic.pubkey_to_secret_words(secondaryDevicePubKey)}`,
});
if (!this.state.currentPubKey) {
this.nextPubKey();
}
}
private allowDevice() {
this.setState({
accepted: true,
});
}
private transmissionCB(errors: any) {
if (!errors) {
this.setState({
errors: null,
});
this.closeDialog();
window.pushToast({
title: window.i18n('devicePairedSuccessfully'),
});
const conv = window.ConversationController.get(this.state.currentPubKey); const conv = window.ConversationController.get(this.state.currentPubKey);
if (conv) { if (conv) {
conv.setNickname(deviceAlias); conv.setNickname(this.state.deviceAlias);
} }
// FIXME display error somewhere
// FIXME display list of linked device
// FIXME do not show linked device in list of contacts
return;
} }
/* this.$('.transmissionStatus').text(errors);
this.$('.requestAcceptedView .ok').show();*/
this.showView(); this.setState({
errors: errors,
});
} }
// private requestReceived(secondaryDevicePubKey: string | EventHandlerNonNull) { private skipDevice() {
// // FIFO: push at the front of the array with unshift() window.Whisper.events.trigger(
// this.state.pubKeyRequests.unshift(secondaryDevicePubKey); 'devicePairingRequestRejected',
// if (!this.state.currentPubKey) { this.state.currentPubKey
// this.nextPubKey(); );
// this.showView('requestReceived'); const hasNext = this.state.pubKeyRequests.length > 0;
// } this.nextPubKey();
// } if (!hasNext) {
this.startReceivingRequests();
// private allowDevice() { }
// this.setState({ this.setState({
// accepted: true, currentView: hasNext ? 'filterRequestView' : 'qrcodeView',
// }); });
// window.Whisper.trigger( }
// 'devicePairingRequestAccepted',
// this.state.currentPubKey, private nextPubKey() {
// (errors: any) => { // FIFO: pop at the back of the array using pop()
// this.transmisssionCB(errors); this.setState({
currentPubKey: this.state.pubKeyRequests.pop(),
// return true; });
// } }
// );
// this.showView();
// }
// private transmisssionCB(errors: any) {
// if (!errors) {
// this.setState({
// success: true,
// });
// } else {
// return;
// }
// }
// private skipDevice() {
// window.Whisper.trigger(
// 'devicePairingRequestRejected',
// this.state.currentPubKey
// );
// this.nextPubKey();
// this.showView();
// }
// private nextPubKey() {
// // FIFO: pop at the back of the array using pop()
// const pubKeyRequests = this.state.pubKeyRequests;
// this.setState({
// currentPubKey: pubKeyRequests.pop(),
// });
// }
private onKeyUp(event: any) { private onKeyUp(event: any) {
switch (event.key) { switch (event.key) {
@ -276,9 +291,42 @@ export class DevicePairingDialog extends React.Component<Props, State> {
} }
} }
private validateSecondaryDevice() {
this.setState({ loading: true });
window.Whisper.events.trigger(
'devicePairingRequestAccepted',
this.state.currentPubKey,
(errors: any) => {
this.transmissionCB(errors);
return true;
}
);
}
private hasReceivedRequests() {
return this.state.currentPubKey || this.state.pubKeyRequests.length > 0;
}
private closeDialog() { private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp); window.removeEventListener('keyup', this.onKeyUp);
this.stopReceivingRequests(); this.stopReceivingRequests();
window.Whisper.events.off('devicePairingRequestReceived');
if (this.state.currentPubKey && !this.state.accepted) {
window.Whisper.events.trigger(
'devicePairingRequestRejected',
this.state.currentPubKey
);
}
this.props.onClose(); this.props.onClose();
} }
private handleUpdateDeviceAlias(value: ChangeEvent<HTMLInputElement>) {
const trimmed = value.target.value.trim();
if (!!trimmed) {
this.setState({ deviceAlias: trimmed });
} else {
this.setState({ deviceAlias: null });
}
}
} }

@ -14,10 +14,12 @@ export const MainViewController = {
}, },
renderSettingsView: (category: SessionSettingCategory) => { renderSettingsView: (category: SessionSettingCategory) => {
ReactDOM.render( if (document.getElementById('main-view')) {
<SettingsView category={category} />, ReactDOM.render(
document.getElementById('main-view') <SettingsView category={category} />,
); document.getElementById('main-view')
);
}
}, },
}; };

@ -274,11 +274,13 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
return ( return (
<div className="left-pane-contact-bottom-buttons"> <div className="left-pane-contact-bottom-buttons">
{showEditButton && <SessionButton {showEditButton && (
text={edit} <SessionButton
buttonType={SessionButtonType.SquareOutline} text={edit}
buttonColor={SessionButtonColor.White} buttonType={SessionButtonType.SquareOutline}
/>} buttonColor={SessionButtonColor.White}
/>
)}
<SessionButton <SessionButton
text={addChannel} text={addChannel}
buttonType={SessionButtonType.SquareOutline} buttonType={SessionButtonType.SquareOutline}

@ -280,11 +280,13 @@ export class LeftPaneContactSection extends React.Component<Props, State> {
return ( return (
<div className="left-pane-contact-bottom-buttons"> <div className="left-pane-contact-bottom-buttons">
{showEditButton && <SessionButton {showEditButton && (
text={edit} <SessionButton
buttonType={SessionButtonType.SquareOutline} text={edit}
buttonColor={SessionButtonColor.White} buttonType={SessionButtonType.SquareOutline}
/>} buttonColor={SessionButtonColor.White}
/>
)}
{selectedTab === 0 ? ( {selectedTab === 0 ? (
<SessionButton <SessionButton
text={addContact} text={addContact}

@ -132,7 +132,7 @@ export class LeftPaneSettingSection extends React.Component<any, State> {
</div> </div>
</div> </div>
</div> </div>
); );
} }
@ -208,6 +208,11 @@ export class LeftPaneSettingSection extends React.Component<any, State> {
description: window.i18n('notificationSettingsDescription'), description: window.i18n('notificationSettingsDescription'),
hidden: false, hidden: false,
}, },
{
id: SessionSettingCategory.Devices,
title: window.i18n('devicesSettingsTitle'),
description: window.i18n('devicesSettingsDescription'),
},
]; ];
} }

@ -10,6 +10,7 @@ import {
import { trigger } from '../../shims/events'; import { trigger } from '../../shims/events';
import { SessionHtmlRenderer } from './SessionHTMLRenderer'; import { SessionHtmlRenderer } from './SessionHTMLRenderer';
import { SessionIdEditable } from './SessionIdEditable'; import { SessionIdEditable } from './SessionIdEditable';
import { SessionSpinner } from './SessionSpinner';
enum SignInMode { enum SignInMode {
Default, Default,
@ -42,6 +43,7 @@ interface State {
primaryDevicePubKey: string; primaryDevicePubKey: string;
mnemonicError: string | undefined; mnemonicError: string | undefined;
displayNameError: string | undefined; displayNameError: string | undefined;
loading: boolean;
} }
const Tab = ({ const Tab = ({
@ -115,6 +117,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
primaryDevicePubKey: '', primaryDevicePubKey: '',
mnemonicError: undefined, mnemonicError: undefined,
displayNameError: undefined, displayNameError: undefined,
loading: false,
}; };
this.accountManager = window.getAccountManager(); this.accountManager = window.getAccountManager();
@ -413,11 +416,12 @@ export class RegistrationTabs extends React.Component<{}, State> {
} }
if (signInMode === SignInMode.LinkingDevice) { if (signInMode === SignInMode.LinkingDevice) {
return ( return (
<div className=""> <div className="registration-content-centered">
<div className="session-signin-device-pairing-header"> <div className="session-signin-device-pairing-header">
{window.i18n('devicePairingHeader')} {window.i18n('devicePairingHeader')}
</div> </div>
{this.renderEnterSessionID(true)} {this.renderEnterSessionID(true)}
<SessionSpinner loading={this.state.loading} />
</div> </div>
); );
} }
@ -734,7 +738,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
if (passwordErrorString || passwordFieldsMatch) { if (passwordErrorString || passwordFieldsMatch) {
window.pushToast({ window.pushToast({
title: window.i18n('invalidPassword'), title: window.i18n('invalidPassword'),
type: 'success', type: 'error',
id: 'invalidPassword', id: 'invalidPassword',
}); });
@ -782,6 +786,9 @@ export class RegistrationTabs extends React.Component<{}, State> {
if (window.textsecure.storage.get('secondaryDeviceStatus') === 'ongoing') { if (window.textsecure.storage.get('secondaryDeviceStatus') === 'ongoing') {
return; return;
} }
this.setState({
loading: true,
});
await this.resetRegistration(); await this.resetRegistration();
window.textsecure.storage.put('secondaryDeviceStatus', 'ongoing'); window.textsecure.storage.put('secondaryDeviceStatus', 'ongoing');
@ -798,7 +805,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
); );
const onError = async (error: any) => { const onError = async (error: any) => {
window.log.error.error(error); window.log.error(error);
await this.resetRegistration(); await this.resetRegistration();
}; };
@ -826,16 +833,26 @@ export class RegistrationTabs extends React.Component<{}, State> {
await this.accountManager.requestPairing(primaryPubKey); await this.accountManager.requestPairing(primaryPubKey);
const pubkey = window.textsecure.storage.user.getNumber(); const pubkey = window.textsecure.storage.user.getNumber();
const words = window.mnemonic.pubkey_to_secret_words(pubkey); const words = window.mnemonic.pubkey_to_secret_words(pubkey);
window.console.log('pubkey_to_secret_words');
window.console.log(`Here is your secret:\n${words}`); window.console.log(`Here is your secret:\n${words}`);
window.pushToast({
title: `Here is your secret: "${words}"`,
id: 'yourSecret',
shouldFade: false,
});
} catch (e) { } catch (e) {
window.console.log(e); window.console.log(e);
//onError(e); //onError(e);
this.setState({
loading: false,
});
} }
} }
private async onSecondaryDeviceRegistered() { private async onSecondaryDeviceRegistered() {
// Ensure the left menu is updated // Ensure the left menu is updated
this.setState({
loading: false,
});
trigger('userChanged', { isSecondaryDevice: true }); trigger('userChanged', { isSecondaryDevice: true });
// will re-run the background initialisation // will re-run the background initialisation
trigger('registration_done'); trigger('registration_done');

@ -6,6 +6,7 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
export const SessionRegistrationView: React.FC = () => ( export const SessionRegistrationView: React.FC = () => (
<div className="session-content"> <div className="session-content">
<div id="session-toast-container" />
<div id="error" className="collapse" /> <div id="error" className="collapse" />
<div className="session-content-close-button"> <div className="session-content-close-button">
<SessionIconButton <SessionIconButton

@ -45,7 +45,14 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
} }
/* tslint:disable-next-line:max-func-body-length */ /* tslint:disable-next-line:max-func-body-length */
public renderSettingInCategory() { public renderSettingInCategory(): JSX.Element {
const { category } = this.props;
if (category === SessionSettingCategory.Devices) {
// special case for linked devices
return this.renderLinkedDevicesCategory();
}
const { Settings } = window.Signal.Types; const { Settings } = window.Signal.Types;
// Grab initial values from database on startup // Grab initial values from database on startup
@ -230,6 +237,7 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
this.updateSetting(setting); this.updateSetting(setting);
}); });
return ( return (
<div key={setting.id}> <div key={setting.id}>
{shouldRenderSettings && {shouldRenderSettings &&
@ -307,4 +315,9 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
}); });
} }
} }
private renderLinkedDevicesCategory(): JSX.Element {
return <div />;
}
} }

@ -1,35 +1,51 @@
import React from 'react'; import React from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon';
import { SettingsViewProps } from './SessionSettings'; import { SessionSettingCategory, SettingsViewProps } from './SessionSettings';
import { SessionButton } from '../SessionButton';
export class SettingsHeader extends React.Component<SettingsViewProps> { export class SettingsHeader extends React.Component<SettingsViewProps> {
public constructor(props: any) { public constructor(props: any) {
super(props); super(props);
this.showAddLinkedDeviceModal = this.showAddLinkedDeviceModal.bind(this);
} }
public focusSearch() { public focusSearch() {
$('.left-pane-setting-section .session-search-input input').focus(); $('.left-pane-setting-section .session-search-input input').focus();
} }
public showAddLinkedDeviceModal() {
window.Whisper.events.trigger('showDevicePairingDialog');
}
public render() { public render() {
const category = String(this.props.category); const { category } = this.props;
const categoryTitlePrefix = category[0].toUpperCase() + category.substr(1); const categoryString = String(category);
const categoryTitlePrefix =
categoryString[0].toUpperCase() + categoryString.substr(1);
// Remove 's' on the end to keep words in singular form // Remove 's' on the end to keep words in singular form
const categoryTitle = const categoryTitle =
categoryTitlePrefix[categoryTitlePrefix.length - 1] === 's' categoryTitlePrefix[categoryTitlePrefix.length - 1] === 's'
? `${categoryTitlePrefix.slice(0, -1)} Settings` ? `${categoryTitlePrefix.slice(0, -1)} Settings`
: `${categoryTitlePrefix} Settings`; : `${categoryTitlePrefix} Settings`;
const showSearch = false; const showSearch = false;
const showAddDevice = category === SessionSettingCategory.Devices;
return ( return (
<div className="session-settings-header"> <div className="session-settings-header">
{categoryTitle} <div className="session-settings-header-title">{categoryTitle}</div>
{showSearch && <SessionIconButton {showSearch && <SessionIconButton
iconType={SessionIconType.Search} iconType={SessionIconType.Search}
iconSize={SessionIconSize.Huge} iconSize={SessionIconSize.Huge}
onClick={this.focusSearch} onClick={this.focusSearch}
/>} />
}
{showAddDevice && (
<SessionButton
text={window.i18n('linkNewDevice')}
onClick={this.showAddLinkedDeviceModal}
/>
)}
</div> </div>
); );
} }

Loading…
Cancel
Save