settings toggling abstraction

This commit is contained in:
Vincent 2020-01-15 12:26:14 +11:00
parent b97c9ec8e4
commit b0658ba7ed
10 changed files with 245 additions and 119 deletions

View File

@ -1317,23 +1317,30 @@
"message": "Permissions",
"description": "Header for permissions section of settings"
},
"mediaPermissionsDescription": {
"message": "Allow access to camera and microphone",
"description": "Description of the media permission description"
},
"general": {
"message": "General",
"description": "Header for general options on the settings screen"
},
"linkPreviews": {
"linkPreviewsTitle": {
"message": "Link Previews",
"description":
"Option to control creation and send of link previews in setting screen"
},
"linkPreviewsSettingDescription": {
"linkPreviewDescription": {
"message": "Enable link previews",
"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": {
"message": "Enable spell check of text entered in message composition box",
"description": "Description of the media permission description"
@ -1399,7 +1406,7 @@
"description": "Warning for the time to live setting"
},
"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"
},
"disableNotifications": {
@ -1836,12 +1843,22 @@
"message": "Dark",
"description": "Label text for dark theme"
},
"themeToggleTitle" : {
"message": "Light Mode"
},
"themeToggleDescription" : {
"message": "Choose the theme best suited to you"
},
"noteToSelf": {
"message": "Note to Self",
"description": "Name for the conversation with your own phone number"
},
"hideMenuBar": {
"message": "Hide menu bar",
"hideMenuBarTitle": {
"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"
},
"startConversation": {
@ -2481,7 +2498,7 @@
"message": "Decline"
},
"generalSettingsTitle": {
"message": "Generals"
"message": "General"
},
"generalSettingsDescription": {
"message": "General settings and configuration"
@ -2492,11 +2509,17 @@
"accountSettingsDescription": {
"message": "Manage your account"
},
"permissionSettingsTitle": {
"message": "Permissions"
},
"permissionSettingsDescription": {
"message": "Set Session's permissions"
},
"privacySettingsTitle": {
"message": "Privacy"
},
"privacySettingsDescription": {
"message": "Privacy description"
"message": "Manage your privacy settings"
},
"notificationSettingsTitle": {
"message": "Notifications"

View File

@ -911,6 +911,20 @@
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) => {
pubkeys.forEach(async pubkey => {
const convo = await ConversationController.getOrCreateAndWait(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,11 @@ import React from 'react';
import { SettingsHeader } from './SessionSettingsHeader';
import { SessionSettingListItem } from './SessionSettingListItem';
export enum SessionSettingCategory {
General = 'general',
Account = 'account',
Privacy = 'privacy',
Permissions = 'permissions',
Notifications = 'notifications',
Devices = 'devices',
}
@ -42,54 +42,86 @@ export class SettingsView extends React.Component<SettingsViewProps> {
const localSettings = [
{
id: 'theme-setting',
title: 'Light Mode',
title: window.i18n('themeToggleTitle'),
description: 'Choose the theme best suited to you',
hidden: true,
comparisonValue: 'light',
type: SessionSettingType.Options,
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
setFn: window.toggleTheme,
childProps: {},
content: {},
},
{
id: 'hide-menu-bar',
title: 'Hide Menu Bar',
description: 'Toggle system menu bar visibi',
title: window.i18n('hideMenuBarTitle'),
description: window.i18n('hideMenuBarDescription'),
hidden: !Settings.isHideMenuBarSupported(),
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
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',
title: 'Notifications',
description: 'When messages arive, display notifications that reveal:',
title: window.i18n('notificationSettingsDialog'),
type: SessionSettingType.Options,
category: SessionSettingCategory.Notifications,
setFn: () => window.setSettingValue(this.getNotificationPreference()),
childProps: {
options: [
{
id: 'default',
desc: 'Both sender name and message',
},
{
id: 'name',
desc: 'Only sender name',
},
{
id: 'count',
desc: 'Neither name nor messsage',
},
{
id: 'off',
desc: 'Disable notificationss',
},
],
activeIndex: 0
setFn: () => this.setOptionsSetting('notification-setting'),
content: {
options: {
group: 'notification-setting',
initalItem: window.getSettingValue('notification-setting'),
items: [{
label: window.i18n('nameAndMessage'),
value: 'message'
},{
label: window.i18n('nameOnly'),
value: 'name'
},{
label: window.i18n('noNameOrMessage'),
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: {},
},
];
return (
@ -103,14 +135,13 @@ export class SettingsView extends React.Component<SettingsViewProps> {
{renderSettings && !(setting.hidden) && (
<SessionSettingListItem
title={setting.title}
description={setting.description}
description={setting.description || ''}
type={setting.type}
value={ window.getSettingValue(setting.id, setting.comparisonValue || null) }
onClick={() => {
this.updateSetting(setting);
}}
buttonText={setting.childProps.buttonText || undefined}
buttonColor={setting.childProps.buttonColor || undefined}
content={setting.content || undefined}
/>
)}
</div>
@ -134,27 +165,25 @@ export class SettingsView extends React.Component<SettingsViewProps> {
}
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,
// execute it instead of automatically updating settings
if (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(){
const value = window.getSettingValue('notification-setting');
return value || 'default';
public setOptionsSetting(settingID: string){
const selectedValue = $(`#${settingID} .session-radio input:checked`).val();
window.setSettingValue(settingID, selectedValue);
}
}

3
ts/global.d.ts vendored
View File

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