settings toggling abstraction

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

@ -1317,23 +1317,30 @@
"message": "Permissions", "message": "Permissions",
"description": "Header for permissions section of settings" "description": "Header for permissions section of settings"
}, },
"mediaPermissionsDescription": {
"message": "Allow access to camera and microphone",
"description": "Description of the media permission description"
},
"general": { "general": {
"message": "General", "message": "General",
"description": "Header for general options on the settings screen" "description": "Header for general options on the settings screen"
}, },
"linkPreviews": { "linkPreviewsTitle": {
"message": "Link Previews", "message": "Link Previews",
"description": "description":
"Option to control creation and send of link previews in setting screen" "Option to control creation and send of link previews in setting screen"
}, },
"linkPreviewsSettingDescription": { "linkPreviewDescription": {
"message": "Enable link previews", "message": "Enable link previews",
"description": "Description shown for the Link Preview option " "description": "Description shown for the Link Preview option "
}, },
"mediaPermissionsTitle": {
"message": "Microphone and Camera"
},
"mediaPermissionsDescription": {
"message": "Allow access to camera and microphone",
"description": "Description of the media permission description"
},
"spellCheckTitle": {
"message": "Spell Check",
"description": "Description of the media permission description"
},
"spellCheckDescription": { "spellCheckDescription": {
"message": "Enable spell check of text entered in message composition box", "message": "Enable spell check of text entered in message composition box",
"description": "Description of the media permission description" "description": "Description of the media permission description"
@ -1399,7 +1406,7 @@
"description": "Warning for the time to live setting" "description": "Warning for the time to live setting"
}, },
"notificationSettingsDialog": { "notificationSettingsDialog": {
"message": "When messages arrive, display notifications that reveal:", "message": "When messages arrive, display notifications that reveal...",
"description": "Explain the purpose of the notification settings" "description": "Explain the purpose of the notification settings"
}, },
"disableNotifications": { "disableNotifications": {
@ -1836,12 +1843,22 @@
"message": "Dark", "message": "Dark",
"description": "Label text for dark theme" "description": "Label text for dark theme"
}, },
"themeToggleTitle" : {
"message": "Light Mode"
},
"themeToggleDescription" : {
"message": "Choose the theme best suited to you"
},
"noteToSelf": { "noteToSelf": {
"message": "Note to Self", "message": "Note to Self",
"description": "Name for the conversation with your own phone number" "description": "Name for the conversation with your own phone number"
}, },
"hideMenuBar": { "hideMenuBarTitle": {
"message": "Hide menu bar", "message": "Hide Menu Bar",
"description": "Label text for menu bar visibility setting"
},
"hideMenuBarDescription": {
"message": "Toggle system menu bar visibility",
"description": "Label text for menu bar visibility setting" "description": "Label text for menu bar visibility setting"
}, },
"startConversation": { "startConversation": {
@ -2481,7 +2498,7 @@
"message": "Decline" "message": "Decline"
}, },
"generalSettingsTitle": { "generalSettingsTitle": {
"message": "Generals" "message": "General"
}, },
"generalSettingsDescription": { "generalSettingsDescription": {
"message": "General settings and configuration" "message": "General settings and configuration"
@ -2492,11 +2509,17 @@
"accountSettingsDescription": { "accountSettingsDescription": {
"message": "Manage your account" "message": "Manage your account"
}, },
"permissionSettingsTitle": {
"message": "Permissions"
},
"permissionSettingsDescription": {
"message": "Set Session's permissions"
},
"privacySettingsTitle": { "privacySettingsTitle": {
"message": "Privacy" "message": "Privacy"
}, },
"privacySettingsDescription": { "privacySettingsDescription": {
"message": "Privacy description" "message": "Manage your privacy settings"
}, },
"notificationSettingsTitle": { "notificationSettingsTitle": {
"message": "Notifications" "message": "Notifications"

@ -911,6 +911,20 @@
window.Events.setHideMenuBar(newValue); window.Events.setHideMenuBar(newValue);
} }
window.toggleSpellCheck = () => {
const newValue = ! window.getSettingValue('spell-check');
window.Events.setSpellCheck(newValue);
}
window.toggleLinkPreview = () => {
const newValue = ! window.getSettingValue('link-preview-setting');
window.Events.setLinkPreviewSetting(newValue);
}
window.toggleMediaPermissions= () => {
}
window.sendGroupInvitations = (serverInfo, pubkeys) => { window.sendGroupInvitations = (serverInfo, pubkeys) => {
pubkeys.forEach(async pubkey => { pubkeys.forEach(async pubkey => {
const convo = await ConversationController.getOrCreateAndWait( const convo = await ConversationController.getOrCreateAndWait(

@ -249,8 +249,8 @@
spellCheckHeader: i18n('spellCheck'), spellCheckHeader: i18n('spellCheck'),
spellCheckDescription: i18n('spellCheckDescription'), spellCheckDescription: i18n('spellCheckDescription'),
blockedHeader: 'Blocked Users', blockedHeader: 'Blocked Users',
linkPreviews: i18n('linkPreviews'), linkPreviews: i18n('linkPreviewsTitle'),
linkPreviewsSettingDescription: i18n('linkPreviewsSettingDescription'), linkPreviewsSettingDescription: i18n('linkPreviewsDescription'),
}; };
}, },
onClose() { onClose() {

@ -1002,6 +1002,8 @@ label {
&__title { &__title {
line-height: 1.7; line-height: 1.7;
font-size: 16px;
font-weight: bold;
} }
&__description { &__description {
@ -1009,6 +1011,12 @@ label {
font-weight: 100; font-weight: 100;
@include session-color-subtle($session-color-white); @include session-color-subtle($session-color-white);
} }
&__content{
label {
@include session-color-subtle($session-color-white);
}
}
} }
} }
@ -1068,12 +1076,24 @@ label {
} }
} }
.session-radio-group fieldset {
border: none;
margin-left: $session-margin-sm;
margin-top: $session-margin-sm;
.session-radio {
padding: $session-margin-xs 0px;
}
}
.session-radio { .session-radio {
input[type="radio"] { input[type="radio"] {
border: 0; border: 0;
opacity: 0; opacity: 0;
padding: 0; padding: 0;
position: absolute; position: absolute;
cursor: pointer;
} }
label { label {
@ -1085,10 +1105,10 @@ label {
display: inline-block; display: inline-block;
width: 0.5em; width: 0.5em;
height: 0.5em; height: 0.5em;
margin-right: 0.5em; margin-right: 0.80em;
border-radius: 100%; border-radius: 100%;
vertical-align: -3px; vertical-align: -3px;
border: 2px solid $session-color-white; border: 2px solid rgba($session-color-white, 0.6);
padding: 0.2em; padding: 0.2em;
background-color: transparent; background-color: transparent;
background-clip: content-box; background-clip: content-box;
@ -1106,4 +1126,5 @@ label {
label:before { label:before {
transition: all $session-transition-duration ease; transition: all $session-transition-duration ease;
} }
} }

@ -173,26 +173,21 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
title: window.i18n('generalSettingsTitle'), title: window.i18n('generalSettingsTitle'),
description: window.i18n('generalSettingsDescription'), description: window.i18n('generalSettingsDescription'),
}, },
{
id: SessionSettingCategory.Account,
title: window.i18n('accountSettingsTitle'),
description: window.i18n('accountSettingsDescription'),
},
{ {
id: SessionSettingCategory.Privacy, id: SessionSettingCategory.Privacy,
title: window.i18n('privacySettingsTitle'), title: window.i18n('privacySettingsTitle'),
description: window.i18n('privacySettingsDescription'), description: window.i18n('privacySettingsDescription'),
}, },
{
id: SessionSettingCategory.Permissions,
title: window.i18n('permissionSettingsTitle'),
description: window.i18n('permissionSettingsDescription'),
},
{ {
id: SessionSettingCategory.Notifications, id: SessionSettingCategory.Notifications,
title: window.i18n('notificationSettingsTitle'), title: window.i18n('notificationSettingsTitle'),
description: window.i18n('notificationSettingsDescription'), description: window.i18n('notificationSettingsDescription'),
}, },
{
id: SessionSettingCategory.Devices,
title: window.i18n('devicesSettingsTitle'),
description: window.i18n('devicesSettingsDescription'),
},
]; ];
} }

@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
interface Props { interface Props {
label: string; label: string;
value: string;
active: boolean; active: boolean;
group?: string;
onClick: any;
} }
interface State { interface State {
@ -12,6 +13,10 @@ interface State {
} }
export class SessionRadio extends React.PureComponent<Props, State> { export class SessionRadio extends React.PureComponent<Props, State> {
public static defaultProps = {
onClick: () => null,
}
constructor(props: any) { constructor(props: any) {
super(props); super(props);
this.clickHandler = this.clickHandler.bind(this); this.clickHandler = this.clickHandler.bind(this);
@ -23,20 +28,32 @@ export class SessionRadio extends React.PureComponent<Props, State> {
public render() { public render() {
const active = this.state.active; const active = this.state.active;
const { label } = this.props; const { label, group, value } = this.props;
return ( return (
<div className={classNames('session-radio', active && 'checked')}> <div className='session-radio'>
<input type="radio" /> <input
type="radio"
name={group || ''}
value={value}
defaultChecked={ active }
onClick={this.clickHandler}
/>
<label>{ label } </label> <label>{ label } </label>
</div> </div>
); );
} }
private clickHandler() { private clickHandler(e: any) {
this.setState({ if (this.props.onClick) {
active: !this.state.active, e.stopPropagation();
}); this.props.onClick();
this.setState({
active: !this.state.active,
});
}
} }
} }

@ -1,12 +1,16 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import { SessionRadio } from './SessionRadio';
interface Props { interface Props {
activeItem: Number; initalItem: string;
items: Array<any>;
group: string;
onClick?: any;
} }
interface State { interface State {
activeItem: Number; activeItem: string;
} }
export class SessionRadioGroup extends React.PureComponent<Props, State> { export class SessionRadioGroup extends React.PureComponent<Props, State> {
@ -17,23 +21,41 @@ export class SessionRadioGroup extends React.PureComponent<Props, State> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
this.clickHandler = this.clickHandler.bind(this); this.clickHandler = this.clickHandler.bind(this);
this.state = {
activeItem: this.props.initalItem,
}
} }
public render() { public render() {
const { items, group } = this.props;
return ( return (
<div <div
className='session-radio-group' className='session-radio-group'
onClick={this.clickHandler}
> >
<label className="radio-container">Four <fieldset id={group}>
<input type="checkbox"/>> { items.map(item => {
<span className="radio-checkmark"></span> return (
</label> <SessionRadio
key={item.value}
label={item.label}
active={item.value === this.state.activeItem}
value={item.value}
group={group}
onClick={this.clickHandler}
/>
);
})
}
</fieldset>
</div> </div>
); );
} }
private clickHandler(e: any) { private clickHandler() {
return; if (this.props.onClick) {
this.props.onClick();
}
} }
} }

@ -2,10 +2,10 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { SessionToggle } from '../SessionToggle'; import { SessionToggle } from '../SessionToggle';
import { SessionButton, SessionButtonColor } from '../SessionButton'; import { SessionButton } from '../SessionButton';
import { SessionSettingType } from './SessionSettings'; import { SessionSettingType } from './SessionSettings';
import { SessionRadio } from '../SessionRadio'; import { SessionRadioGroup } from '../SessionRadioGroup';
interface Props { interface Props {
title: string; title: string;
@ -14,9 +14,7 @@ interface Props {
value: any; value: any;
options?: Array<any>; options?: Array<any>;
onClick?: any; onClick?: any;
inline?: boolean; content: any;
buttonText?: string;
buttonColor?: SessionButtonColor;
} }
export class SessionSettingListItem extends React.Component<Props> { export class SessionSettingListItem extends React.Component<Props> {
@ -37,15 +35,15 @@ export class SessionSettingListItem extends React.Component<Props> {
description, description,
type, type,
value, value,
inline, content,
buttonText,
buttonColor,
} = this.props; } = this.props;
const inline = ![SessionSettingType.Options, SessionSettingType.Slider].includes(type);
return ( return (
<div className="session-settings-item"> <div className={classNames('session-settings-item', inline && 'inline')}>
<div className="session-settings-item__info"> <div className='session-settings-item__info'>
<div className={classNames('session-settings-item__title', inline && 'inline')}>{title}</div> <div className='session-settings-item__title'>{title}</div>
{description && ( {description && (
<div className="session-settings-item__description"> <div className="session-settings-item__description">
@ -54,26 +52,30 @@ export class SessionSettingListItem extends React.Component<Props> {
)} )}
</div> </div>
{type === SessionSettingType.Toggle && ( <div className="session-settings-item__content">
<div className="session-sessings-item__selection"> {type === SessionSettingType.Toggle && (
<SessionToggle active={Boolean(value)} onClick={this.handleClick} /> <div className="session-sessings-item__selection">
</div> <SessionToggle active={Boolean(value)} onClick={this.handleClick} />
)} </div>
)}
{type === SessionSettingType.Button && ( {type === SessionSettingType.Button && (
<SessionButton <SessionButton
text={buttonText} text={content.buttonText}
buttonColor={buttonColor} buttonColor={content.buttonColor}
onClick={this.handleClick} onClick={this.handleClick}
/> />
)} )}
{type === SessionSettingType.Options && ( {type === SessionSettingType.Options && (
<SessionRadio <SessionRadioGroup
label="Both sender name and message" initalItem={content.options.initalItem}
active={false} group={content.options.group}
/> items={content.options.items}
)} onClick={this.handleClick}
/>
)}
</div>
</div> </div>
); );
} }

@ -3,11 +3,11 @@ import React from 'react';
import { SettingsHeader } from './SessionSettingsHeader'; import { SettingsHeader } from './SessionSettingsHeader';
import { SessionSettingListItem } from './SessionSettingListItem'; import { SessionSettingListItem } from './SessionSettingListItem';
export enum SessionSettingCategory { export enum SessionSettingCategory {
General = 'general', General = 'general',
Account = 'account', Account = 'account',
Privacy = 'privacy', Privacy = 'privacy',
Permissions = 'permissions',
Notifications = 'notifications', Notifications = 'notifications',
Devices = 'devices', Devices = 'devices',
} }
@ -42,54 +42,86 @@ export class SettingsView extends React.Component<SettingsViewProps> {
const localSettings = [ const localSettings = [
{ {
id: 'theme-setting', id: 'theme-setting',
title: 'Light Mode', 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.Options, type: SessionSettingType.Toggle,
category: SessionSettingCategory.General, category: SessionSettingCategory.General,
setFn: window.toggleTheme, setFn: window.toggleTheme,
childProps: {}, content: {},
}, },
{ {
id: 'hide-menu-bar', id: 'hide-menu-bar',
title: 'Hide Menu Bar', title: window.i18n('hideMenuBarTitle'),
description: 'Toggle system menu bar visibi', 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,
childProps: {}, content: {},
},
{
id: 'spell-check',
title: window.i18n('spellCheckTitle'),
description: window.i18n('spellCheckDescription'),
hidden: false,
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
setFn: window.toggleSpellCheck,
content: {},
},
{
id: 'link-preview-setting',
title: window.i18n('linkPreviewsTitle'),
description: window.i18n('linkPreviewDescription'),
hidden: false,
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
setFn: window.toggleLinkPreview,
content: {},
}, },
{ {
id: 'notification-setting', id: 'notification-setting',
title: 'Notifications', title: window.i18n('notificationSettingsDialog'),
description: 'When messages arive, display notifications that reveal:',
type: SessionSettingType.Options, type: SessionSettingType.Options,
category: SessionSettingCategory.Notifications, category: SessionSettingCategory.Notifications,
setFn: () => window.setSettingValue(this.getNotificationPreference()), setFn: () => this.setOptionsSetting('notification-setting'),
childProps: { content: {
options: [ options: {
{ group: 'notification-setting',
id: 'default', initalItem: window.getSettingValue('notification-setting'),
desc: 'Both sender name and message', items: [{
}, label: window.i18n('nameAndMessage'),
{ value: 'message'
id: 'name', },{
desc: 'Only sender name', label: window.i18n('nameOnly'),
}, value: 'name'
{ },{
id: 'count', label: window.i18n('noNameOrMessage'),
desc: 'Neither name nor messsage', value: 'count'
}, },{
{ label: window.i18n('disableNotifications'),
id: 'off', value: 'off'
desc: 'Disable notificationss', }],
}, },
],
activeIndex: 0
}, },
}, },
{
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 (
@ -103,14 +135,13 @@ export class SettingsView extends React.Component<SettingsViewProps> {
{renderSettings && !(setting.hidden) && ( {renderSettings && !(setting.hidden) && (
<SessionSettingListItem <SessionSettingListItem
title={setting.title} title={setting.title}
description={setting.description} description={setting.description || ''}
type={setting.type} type={setting.type}
value={ window.getSettingValue(setting.id, setting.comparisonValue || null) } value={ window.getSettingValue(setting.id, setting.comparisonValue || null) }
onClick={() => { onClick={() => {
this.updateSetting(setting); this.updateSetting(setting);
}} }}
buttonText={setting.childProps.buttonText || undefined} content={setting.content || undefined}
buttonColor={setting.childProps.buttonColor || undefined}
/> />
)} )}
</div> </div>
@ -134,27 +165,25 @@ export class SettingsView extends React.Component<SettingsViewProps> {
} }
public updateSetting(item: any) { public updateSetting(item: any) {
if (item.type === SessionSettingType.Toggle) {
// If no custom afterClick function given, alter values in storage here
if (!item.setFn) {
// Switch to opposite state
const newValue = !window.getSettingValue(item.id);
window.setSettingValue(item.id, newValue);
}
}
// 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 {
if (item.type === SessionSettingType.Toggle) {
// If no custom afterClick function given, alter values in storage here
// Switch to opposite state
const newValue = !window.getSettingValue(item.id);
window.setSettingValue(item.id, newValue);
}
} }
return;
} }
public getNotificationPreference(){ public setOptionsSetting(settingID: string){
const value = window.getSettingValue('notification-setting'); const selectedValue = $(`#${settingID} .session-radio input:checked`).val();
return value || 'default'; window.setSettingValue(settingID, selectedValue);
} }
} }

3
ts/global.d.ts vendored

@ -26,6 +26,9 @@ interface Window {
deleteAccount: any; deleteAccount: any;
toggleTheme: any; toggleTheme: any;
toggleMenuBar: any; toggleMenuBar: any;
toggleSpellCheck: any;
toggleLinkPreview: any;
toggleMediaPermissions: any;
getSettingValue: any; getSettingValue: any;
setSettingValue: any; setSettingValue: any;

Loading…
Cancel
Save