mergable settingsview

pull/717/head
Vincent 5 years ago
parent b0658ba7ed
commit d217c76647

@ -1843,10 +1843,10 @@
"message": "Dark", "message": "Dark",
"description": "Label text for dark theme" "description": "Label text for dark theme"
}, },
"themeToggleTitle" : { "themeToggleTitle": {
"message": "Light Mode" "message": "Light Mode"
}, },
"themeToggleDescription" : { "themeToggleDescription": {
"message": "Choose the theme best suited to you" "message": "Choose the theme best suited to you"
}, },
"noteToSelf": { "noteToSelf": {

@ -907,23 +907,21 @@
}; };
window.toggleMenuBar = () => { window.toggleMenuBar = () => {
const newValue = ! window.getSettingValue('hide-menu-bar'); const newValue = !window.getSettingValue('hide-menu-bar');
window.Events.setHideMenuBar(newValue); window.Events.setHideMenuBar(newValue);
} };
window.toggleSpellCheck = () => { window.toggleSpellCheck = () => {
const newValue = ! window.getSettingValue('spell-check'); const newValue = !window.getSettingValue('spell-check');
window.Events.setSpellCheck(newValue); window.Events.setSpellCheck(newValue);
} };
window.toggleLinkPreview = () => { window.toggleLinkPreview = () => {
const newValue = ! window.getSettingValue('link-preview-setting'); const newValue = !window.getSettingValue('link-preview-setting');
window.Events.setLinkPreviewSetting(newValue); window.Events.setLinkPreviewSetting(newValue);
} };
window.toggleMediaPermissions= () => {
} window.toggleMediaPermissions = () => {};
window.sendGroupInvitations = (serverInfo, pubkeys) => { window.sendGroupInvitations = (serverInfo, pubkeys) => {
pubkeys.forEach(async pubkey => { pubkeys.forEach(async pubkey => {

@ -185,18 +185,17 @@ ipc.on('remove-dark-overlay', () => {
} }
}); });
window.getSettingValue = (settingID, comparisonValue = null) => { window.getSettingValue = (settingID, comparisonValue = null) => {
// Comparison value allows you to pull boolean values from any type. // Comparison value allows you to pull boolean values from any type.
// Eg. window.getSettingValue('theme', 'light') // Eg. window.getSettingValue('theme', 'light')
// returns 'false' when the value is 'dark'. // returns 'false' when the value is 'dark'.
const settingVal = window.storage.get(settingID); const settingVal = window.storage.get(settingID);
return comparisonValue ? !!settingVal === comparisonValue : settingVal; return comparisonValue ? !!settingVal === comparisonValue : settingVal;
} };
window.setSettingValue = (settingID, value) => { window.setSettingValue = (settingID, value) => {
window.storage.put(settingID, value); window.storage.put(settingID, value);
} };
installGetter('device-name', 'getDeviceName'); installGetter('device-name', 'getDeviceName');

@ -1012,7 +1012,7 @@ label {
@include session-color-subtle($session-color-white); @include session-color-subtle($session-color-white);
} }
&__content{ &__content {
label { label {
@include session-color-subtle($session-color-white); @include session-color-subtle($session-color-white);
} }
@ -1076,7 +1076,6 @@ label {
} }
} }
.session-radio-group fieldset { .session-radio-group fieldset {
border: none; border: none;
margin-left: $session-margin-sm; margin-left: $session-margin-sm;
@ -1088,7 +1087,7 @@ label {
} }
.session-radio { .session-radio {
input[type="radio"] { input[type='radio'] {
border: 0; border: 0;
opacity: 0; opacity: 0;
padding: 0; padding: 0;
@ -1101,11 +1100,11 @@ label {
} }
label:before { label:before {
content: ""; content: '';
display: inline-block; display: inline-block;
width: 0.5em; width: 0.5em;
height: 0.5em; height: 0.5em;
margin-right: 0.80em; margin-right: 0.8em;
border-radius: 100%; border-radius: 100%;
vertical-align: -3px; vertical-align: -3px;
border: 2px solid rgba($session-color-white, 0.6); border: 2px solid rgba($session-color-white, 0.6);
@ -1127,4 +1126,3 @@ label {
transition: all $session-transition-duration ease; transition: all $session-transition-duration ease;
} }
} }

@ -6,23 +6,21 @@ import {
SettingsView, SettingsView,
} from './session/settings/SessionSettings'; } from './session/settings/SessionSettings';
export class MainViewController { export const MainViewController = {
constructor() {} renderMessageView: () => {
static renderMessageView() {
ReactDOM.render(<MessageView />, document.getElementById('main-view')); ReactDOM.render(<MessageView />, document.getElementById('main-view'));
} },
static renderSettingsView(category: SessionSettingCategory) { renderSettingsView: (category: SessionSettingCategory) => {
ReactDOM.render( ReactDOM.render(
<SettingsView category={category} />, <SettingsView category={category} />,
document.getElementById('main-view') document.getElementById('main-view')
); );
} },
} };
export class MessageView extends React.Component { export class MessageView extends React.Component {
render() { public render() {
return ( return (
<div className="conversation-stack"> <div className="conversation-stack">
<div className="conversation placeholder"> <div className="conversation placeholder">

@ -15,15 +15,13 @@ import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
import { SessionSearchInput } from './SessionSearchInput'; import { SessionSearchInput } from './SessionSearchInput';
import { SessionSettingCategory } from './settings/SessionSettings'; import { SessionSettingCategory } from './settings/SessionSettings';
export interface Props {}
export interface State { export interface State {
settingCategory: SessionSettingCategory; settingCategory: SessionSettingCategory;
searchQuery: string; searchQuery: string;
} }
export class LeftPaneSettingSection extends React.Component<Props, State> { export class LeftPaneSettingSection extends React.Component<any, State> {
public constructor(props: Props) { public constructor(props: any) {
super(props); super(props);
this.state = { this.state = {
@ -72,7 +70,8 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
'left-pane-setting-category-list-item', 'left-pane-setting-category-list-item',
item.id === this.state.settingCategory ? 'active' : '' item.id === this.state.settingCategory ? 'active' : ''
)} )}
onClick={() => this.setCategory(item.id)} role="link"
onClick={(): void => this.setCategory(item.id)}
> >
<div> <div>
<strong>{item.title}</strong> <strong>{item.title}</strong>

@ -505,7 +505,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
private renderTermsConditionAgreement() { private renderTermsConditionAgreement() {
// FIXME // FIXME
console.log( window.log.info(
'FIXME: add link to our Terms and Conditions and privacy statement' 'FIXME: add link to our Terms and Conditions and privacy statement'
); );
@ -718,7 +718,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
); );
const onError = async (error: any) => { const onError = async (error: any) => {
window.console.error(error); window.log.error.error(error);
await this.resetRegistration(); await this.resetRegistration();
}; };

@ -47,6 +47,7 @@ export class SessionButton extends React.PureComponent<Props> {
const { buttonType, buttonColor, text, disabled } = this.props; const { buttonType, buttonColor, text, disabled } = this.props;
const buttonTypes = []; const buttonTypes = [];
const onClickFn = disabled ? () => null : this.clickHandler;
buttonTypes.push(buttonType); buttonTypes.push(buttonType);
if (buttonType.includes('-outline')) { if (buttonType.includes('-outline')) {
@ -62,7 +63,7 @@ export class SessionButton extends React.PureComponent<Props> {
disabled && 'disabled' disabled && 'disabled'
)} )}
role="button" role="button"
onClick={disabled ? () => null : this.clickHandler} onClick={onClickFn}
> >
{this.props.children || text} {this.props.children || text}
</div> </div>

@ -46,6 +46,10 @@ export class SessionConfirm extends React.Component<Props> {
const cancelText = this.props.cancelText || window.i18n('cancel'); const cancelText = this.props.cancelText || window.i18n('cancel');
const showHeader = !!this.props.title; const showHeader = !!this.props.title;
const messageSubText = messageSub
? 'session-confirm-main-message'
: 'text-subtle';
return ( return (
<SessionModal <SessionModal
title={title} title={title}
@ -57,13 +61,7 @@ export class SessionConfirm extends React.Component<Props> {
{!showHeader && <div className="spacer-lg" />} {!showHeader && <div className="spacer-lg" />}
<div className="session-modal__centered"> <div className="session-modal__centered">
<span <span className={messageSubText}>{message}</span>
className={
messageSub ? 'session-confirm-main-message' : 'text-subtle'
}
>
{message}
</span>
{messageSub && ( {messageSub && (
<span className="session-confirm-sub-message text-subtle"> <span className="session-confirm-sub-message text-subtle">
{messageSub} {messageSub}

@ -15,7 +15,7 @@ interface State {
export class SessionRadio extends React.PureComponent<Props, State> { export class SessionRadio extends React.PureComponent<Props, State> {
public static defaultProps = { public static defaultProps = {
onClick: () => null, onClick: () => null,
} };
constructor(props: any) { constructor(props: any) {
super(props); super(props);
@ -23,24 +23,24 @@ export class SessionRadio extends React.PureComponent<Props, State> {
this.state = { this.state = {
active: this.props.active, active: this.props.active,
} };
} }
public render() { public render() {
const active = this.state.active; const active = this.state.active;
const { label, group, value } = this.props; const { label, group, value } = this.props;
return ( return (
<div className='session-radio'> <div className="session-radio">
<input <input
type="radio" type="radio"
name={group || ''} name={group || ''}
value={value} value={value}
defaultChecked={ active } defaultChecked={active}
aria-checked={active}
onClick={this.clickHandler} onClick={this.clickHandler}
/> />
<label>{ label } </label> <label>{label} </label>
</div> </div>
); );
} }
@ -53,7 +53,6 @@ export class SessionRadio extends React.PureComponent<Props, State> {
this.setState({ this.setState({
active: !this.state.active, active: !this.state.active,
}); });
} }
} }
} }

@ -24,30 +24,29 @@ export class SessionRadioGroup extends React.PureComponent<Props, State> {
this.state = { this.state = {
activeItem: this.props.initalItem, activeItem: this.props.initalItem,
} };
} }
public render() { public render() {
const { items, group } = this.props; const { items, group } = this.props;
return ( return (
<div <div className="session-radio-group">
className='session-radio-group'
>
<fieldset id={group}> <fieldset id={group}>
{ items.map(item => { {items.map(item => {
return ( const itemIsActive = item.value === this.state.activeItem;
<SessionRadio
key={item.value} return (
label={item.label} <SessionRadio
active={item.value === this.state.activeItem} key={item.value}
value={item.value} label={item.label}
group={group} active={itemIsActive}
onClick={this.clickHandler} value={item.value}
/> group={group}
); onClick={this.clickHandler}
}) />
} );
})}
</fieldset> </fieldset>
</div> </div>
); );

@ -40,6 +40,37 @@ export class SessionSeedModal extends React.Component<Props, State> {
window.addEventListener('keyup', this.onEnter); window.addEventListener('keyup', this.onEnter);
} }
public render() {
const i18n = window.i18n;
this.checkHasPassword();
this.getSeed().ignore();
const { onClose } = this.props;
const { hasPassword, passwordValid } = this.state;
const loading = this.state.loadingPassword || this.state.loadingSeed;
return (
<>
{!loading && (
<SessionModal
title={i18n('showSeed')}
onOk={() => null}
onClose={onClose}
>
<div className="spacer-sm" />
{hasPassword && !passwordValid ? (
<>{this.renderPasswordView()}</>
) : (
<>{this.renderSeedView()}</>
)}
</SessionModal>
)}
</>
);
}
private renderPasswordView() { private renderPasswordView() {
const maxPasswordLen = 64; const maxPasswordLen = 64;
const error = this.state.error; const error = this.state.error;
@ -109,37 +140,6 @@ export class SessionSeedModal extends React.Component<Props, State> {
); );
} }
public render() {
const i18n = window.i18n;
this.checkHasPassword();
this.getSeed().ignore();
const { onClose } = this.props;
const { hasPassword, passwordValid } = this.state;
const loading = this.state.loadingPassword || this.state.loadingSeed;
return (
<>
{!loading && (
<SessionModal
title={i18n('showSeed')}
onOk={() => null}
onClose={onClose}
>
<div className="spacer-sm" />
{hasPassword && !passwordValid ? (
<>{this.renderPasswordView()}</>
) : (
<>{this.renderSeedView()}</>
)}
</SessionModal>
)}
</>
);
}
private confirmPassword() { private confirmPassword() {
const passwordHash = this.state.passwordHash; const passwordHash = this.state.passwordHash;
const passwordValue = $('#seed-input-password').val(); const passwordValue = $('#seed-input-password').val();

@ -20,7 +20,7 @@ interface Props {
export class SessionSettingListItem extends React.Component<Props> { export class SessionSettingListItem extends React.Component<Props> {
public static defaultProps = { public static defaultProps = {
inline: true, inline: true,
} };
public constructor(props: Props) { public constructor(props: Props) {
super(props); super(props);
@ -30,20 +30,17 @@ export class SessionSettingListItem extends React.Component<Props> {
} }
public render(): JSX.Element { public render(): JSX.Element {
const { const { title, description, type, value, content } = this.props;
title,
description,
type,
value,
content,
} = this.props;
const inline = ![SessionSettingType.Options, SessionSettingType.Slider].includes(type); const inline = ![
SessionSettingType.Options,
SessionSettingType.Slider,
].includes(type);
return ( return (
<div className={classNames('session-settings-item', inline && 'inline')}> <div className={classNames('session-settings-item', inline && 'inline')}>
<div className='session-settings-item__info'> <div className="session-settings-item__info">
<div className='session-settings-item__title'>{title}</div> <div className="session-settings-item__title">{title}</div>
{description && ( {description && (
<div className="session-settings-item__description"> <div className="session-settings-item__description">
@ -55,7 +52,10 @@ export class SessionSettingListItem extends React.Component<Props> {
<div className="session-settings-item__content"> <div className="session-settings-item__content">
{type === SessionSettingType.Toggle && ( {type === SessionSettingType.Toggle && (
<div className="session-sessings-item__selection"> <div className="session-sessings-item__selection">
<SessionToggle active={Boolean(value)} onClick={this.handleClick} /> <SessionToggle
active={Boolean(value)}
onClick={this.handleClick}
/>
</div> </div>
)} )}

@ -40,88 +40,90 @@ export class SettingsView extends React.Component<SettingsViewProps> {
// ID corresponds to instalGetter parameters in preload.js // ID corresponds to instalGetter parameters in preload.js
// They are NOT arbitrary; add with caution // They are NOT arbitrary; add with caution
const localSettings = [ const localSettings = [
{ {
id: 'theme-setting', id: 'theme-setting',
title: window.i18n('themeToggleTitle'), title: window.i18n('themeToggleTitle'),
description: 'Choose the theme best suited to you', description: 'Choose the theme best suited to you',
hidden: true, hidden: true,
comparisonValue: 'light', comparisonValue: 'light',
type: SessionSettingType.Toggle, type: SessionSettingType.Toggle,
category: SessionSettingCategory.General, category: SessionSettingCategory.General,
setFn: window.toggleTheme, setFn: window.toggleTheme,
content: {}, content: {},
}, },
{ {
id: 'hide-menu-bar', id: 'hide-menu-bar',
title: window.i18n('hideMenuBarTitle'), title: window.i18n('hideMenuBarTitle'),
description: window.i18n('hideMenuBarDescription'), description: window.i18n('hideMenuBarDescription'),
hidden: !Settings.isHideMenuBarSupported(), hidden: !Settings.isHideMenuBarSupported(),
type: SessionSettingType.Toggle, type: SessionSettingType.Toggle,
category: SessionSettingCategory.General, category: SessionSettingCategory.General,
setFn: window.toggleMenuBar, setFn: window.toggleMenuBar,
content: {}, content: {},
}, },
{ {
id: 'spell-check', id: 'spell-check',
title: window.i18n('spellCheckTitle'), title: window.i18n('spellCheckTitle'),
description: window.i18n('spellCheckDescription'), description: window.i18n('spellCheckDescription'),
hidden: false, hidden: false,
type: SessionSettingType.Toggle, type: SessionSettingType.Toggle,
category: SessionSettingCategory.General, category: SessionSettingCategory.General,
setFn: window.toggleSpellCheck, setFn: window.toggleSpellCheck,
content: {}, content: {},
}, },
{ {
id: 'link-preview-setting', id: 'link-preview-setting',
title: window.i18n('linkPreviewsTitle'), title: window.i18n('linkPreviewsTitle'),
description: window.i18n('linkPreviewDescription'), description: window.i18n('linkPreviewDescription'),
hidden: false, hidden: false,
type: SessionSettingType.Toggle, type: SessionSettingType.Toggle,
category: SessionSettingCategory.General, category: SessionSettingCategory.General,
setFn: window.toggleLinkPreview, setFn: window.toggleLinkPreview,
content: {}, content: {},
}, },
{ {
id: 'notification-setting', id: 'notification-setting',
title: window.i18n('notificationSettingsDialog'), title: window.i18n('notificationSettingsDialog'),
type: SessionSettingType.Options, type: SessionSettingType.Options,
category: SessionSettingCategory.Notifications, category: SessionSettingCategory.Notifications,
setFn: () => this.setOptionsSetting('notification-setting'), setFn: () => this.setOptionsSetting('notification-setting'),
content: { content: {
options: { options: {
group: 'notification-setting', group: 'notification-setting',
initalItem: window.getSettingValue('notification-setting'), initalItem: window.getSettingValue('notification-setting'),
items: [{ items: [
label: window.i18n('nameAndMessage'), {
value: 'message' label: window.i18n('nameAndMessage'),
},{ value: 'message',
label: window.i18n('nameOnly'), },
value: 'name' {
},{ label: window.i18n('nameOnly'),
label: window.i18n('noNameOrMessage'), value: 'name',
value: 'count' },
},{ {
label: window.i18n('disableNotifications'), label: window.i18n('noNameOrMessage'),
value: 'off' value: 'count',
}], },
}, {
}, label: window.i18n('disableNotifications'),
value: 'off',
},
],
},
}, },
{
id: 'media-permissions',
title: window.i18n('mediaPermissionsTitle'),
description: window.i18n('mediaPermissionsDescription'),
hidden: false,
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Permissions,
setFn: window.toggleMediaPermissions,
content: {},
}, },
{
id: 'media-permissions',
title: window.i18n('mediaPermissionsTitle'),
description: window.i18n('mediaPermissionsDescription'),
hidden: false,
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Permissions,
setFn: window.toggleMediaPermissions,
content: {},
},
]; ];
return ( return (
@ -129,21 +131,24 @@ export class SettingsView extends React.Component<SettingsViewProps> {
{localSettings.map(setting => { {localSettings.map(setting => {
const { category } = this.props; const { category } = this.props;
const renderSettings = setting.category === category; const renderSettings = setting.category === category;
const description = setting.description || '';
const comparisonValue = setting.comparisonValue || null;
return ( return (
<div key={setting.id}> <div key={setting.id}>
{renderSettings && !(setting.hidden) && ( {renderSettings &&
<SessionSettingListItem !setting.hidden && (
<SessionSettingListItem
title={setting.title} title={setting.title}
description={setting.description || ''} description={description}
type={setting.type} type={setting.type}
value={ window.getSettingValue(setting.id, setting.comparisonValue || null) } value={window.getSettingValue(setting.id, comparisonValue)}
onClick={() => { onClick={() => {
this.updateSetting(setting); this.updateSetting(setting);
}} }}
content={setting.content || undefined} content={setting.content || undefined}
/> />
)} )}
</div> </div>
); );
})} })}
@ -165,11 +170,10 @@ export class SettingsView extends React.Component<SettingsViewProps> {
} }
public updateSetting(item: any) { public updateSetting(item: any) {
// If there's a custom afterClick function, // If there's a custom afterClick function,
// execute it instead of automatically updating settings // execute it instead of automatically updating settings
if (item.setFn) { if (item.setFn) {
item.setFn(); item.setFn();
} else { } else {
if (item.type === SessionSettingType.Toggle) { if (item.type === SessionSettingType.Toggle) {
// If no custom afterClick function given, alter values in storage here // If no custom afterClick function given, alter values in storage here
@ -178,12 +182,10 @@ export class SettingsView extends React.Component<SettingsViewProps> {
window.setSettingValue(item.id, newValue); window.setSettingValue(item.id, newValue);
} }
} }
} }
public setOptionsSetting(settingID: string){ public setOptionsSetting(settingID: string) {
const selectedValue = $(`#${settingID} .session-radio input:checked`).val(); const selectedValue = $(`#${settingID} .session-radio input:checked`).val();
window.setSettingValue(settingID, selectedValue); window.setSettingValue(settingID, selectedValue);
} }
} }

@ -12,14 +12,14 @@ export class SettingsHeader extends React.Component<SettingsViewProps> {
$('.left-pane-setting-section .session-search-input input').focus(); $('.left-pane-setting-section .session-search-input input').focus();
} }
render() { public render() {
const category = String(this.props.category); const category = String(this.props.category);
const categoryTitlePrefix = category[0].toUpperCase() + category.substr(1); const categoryTitlePrefix = category[0].toUpperCase() + category.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`;
return ( return (
<div className="session-settings-header"> <div className="session-settings-header">

2
ts/global.d.ts vendored

@ -15,6 +15,7 @@ interface Window {
setPassword: any; setPassword: any;
textsecure: any; textsecure: any;
Session: any; Session: any;
log: any;
i18n: any; i18n: any;
friends: any; friends: any;
generateID: any; generateID: any;
@ -31,7 +32,6 @@ interface Window {
toggleMediaPermissions: any; toggleMediaPermissions: any;
getSettingValue: any; getSettingValue: any;
setSettingValue: any; setSettingValue: any;
} }
interface Promise<T> { interface Promise<T> {

Loading…
Cancel
Save