Theme toggle and settings abstraction

pull/717/head
Vincent 5 years ago
parent bbf5f8a9f2
commit 8de2ce9e23

@ -821,7 +821,8 @@
};
window.showSeedDialog = window.owsDesktopApp.appView.showSeedDialog;
window.showAddServerDialog = window.owsDesktopApp.appView.showAddServerDialog;
window.showAddServerDialog =
window.owsDesktopApp.appView.showAddServerDialog;
window.generateID = () =>
Math.random()
@ -874,10 +875,24 @@
};
window.deleteAccount = async () => {
await window.Signal.Data.removeAll();
await window.storage.fetch();
try {
window.log.info('Deleting everything!');
const { Logs } = window.Signal;
await Logs.deleteAll();
alert('YOUR ACCOUNT HAS BEEN DELETED');
await window.Signal.Data.removeAll();
await window.Signal.Data.close();
await window.Signal.Data.removeDB();
await window.Signal.Data.removeOtherData();
} catch (error) {
window.log.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
}
window.restart();
};
window.toggleTheme = () => {

@ -45,7 +45,7 @@
openView(view) {
this.el.innerHTML = '';
this.el.append(view.el);
this.delegateEvents();
this.delegateEvents();
},
openDebugLog() {
this.closeDebugLog();

@ -2,24 +2,21 @@
// eslint-disable-next-line func-names
(function() {
'use strict';
window.Whisper = window.Whisper || {};
Whisper.ConversationLoadingScreen = Whisper.View.extend({
initialize() {
},
render() {
this.toastView = new Whisper.ReactWrapperView({
className: 'app-loading-wrapper',
Component: window.Signal.Components.ConversationLoadingScreen,
props: this.props,
});
this.$el.append(this.toastView.el);
},
});
})();
'use strict';
window.Whisper = window.Whisper || {};
Whisper.ConversationLoadingScreen = Whisper.View.extend({
initialize() {},
render() {
this.toastView = new Whisper.ReactWrapperView({
className: 'app-loading-wrapper',
Component: window.Signal.Components.ConversationLoadingScreen,
props: this.props,
});
this.$el.append(this.toastView.el);
},
});
})();

@ -143,7 +143,6 @@
this.loadingScreen.render();
this.loadingScreen.$el.prependTo(this.$('.discussion-container'));
this.window = options.window;
this.fileInput = new Whisper.FileInputView({
el: this.$('.attachment-list'),

@ -23,32 +23,39 @@
open(conversation) {
const id = `conversation-${conversation.cid}`;
const container = $('#main-view .conversation-stack');
// Has been opened since app sart, but not focussed
const conversationExists = container.children(`#${id}`).length > 0;
// Is focussed
const conversationOpened = container.children().first().id === id
const conversationOpened = container.children().first().id === id;
// To limit the size of the DOM for speed
const maxNumConversations = 10;
const numConversations = container.children().not('.conversation.placeholder').length;
const numConversations = container
.children()
.not('.conversation.placeholder').length;
const shouldTrimConversations = numConversations > maxNumConversations;
if (shouldTrimConversations){
if (shouldTrimConversations) {
// Removes conversation which has been hidden the longest
container.children()[numConversations - 1].remove();
}
if (conversationExists) {
// User opened conversation, move it to top of stack, rather than re-rendering
const conversations = container.children().not('.conversation.placeholder');
container.children(`#${id}`).first().insertBefore(conversations.first());
const conversations = container
.children()
.not('.conversation.placeholder');
container
.children(`#${id}`)
.first()
.insertBefore(conversations.first());
conversation.trigger('opened');
return;
}
if (! conversationOpened) {
if (!conversationOpened) {
this.$el
.first()
.find('video, audio')
@ -68,7 +75,6 @@
}
container.prepend($el);
}
conversation.trigger('opened');
},
@ -102,7 +108,6 @@
message: i18n('loading'),
},
});
Whisper.InboxView = Whisper.View.extend({
templateName: 'two-column',

@ -185,6 +185,32 @@ ipc.on('remove-dark-overlay', () => {
}
});
window.getSettingValue = settingID => {
console.log("EXECUTED");
console.log("EXECUTED");
console.log("EXECUTED");
console.log("EXECUTED");
const theme = window.storage.get('theme-setting', 'dark');
console.log(`THEME: ${theme}`);
console.log(`THEME: ${theme}`);
console.log(`THEME: ${theme}`);
console.log(`THEME: ${theme}`);
console.log(`THEME: ${theme}`);
if (settingID === 'theme'){
const theme = window.storage.get('theme-setting', 'dark');
console.log(`THEME: ${theme}`);
}
}
window.setSettingValue = settingID => {
const those = settingID;
return those;
}
installGetter('device-name', 'getDeviceName');
installGetter('theme-setting', 'getThemeSetting');

@ -242,8 +242,8 @@ $session_message-container-border-radius: 5px;
&.green {
border: 2px solid $session-color-green;
background-color: $session-color-green;
&.disabled{
&.disabled {
background-color: rgba($session-color-green, 0.6);
}
@ -253,37 +253,37 @@ $session_message-container-border-radius: 5px;
}
&.white {
background-color: $session-color-white;
&.disabled{
&.disabled {
background-color: rgba($session-color-white, 0.6);
}
}
&.primary {
background-color: $session-color-primary;
&.disabled{
&.disabled {
background-color: rgba($session-color-primary, 0.6);
}
}
&.secondary {
background-color: $session-color-secondary;
&.disabled{
&.disabled {
background-color: rgba($session-color-secondary, 0.6);
}
}
&.success {
background-color: $session-color-success;
&.disabled{
&.disabled {
background-color: rgba($session-color-success, 0.6);
}
}
&.danger {
background-color: $session-color-danger;
&.disabled{
&.disabled {
background-color: rgba($session-color-danger, 0.6);
}
}
&.warning {
background-color: $session-color-warning;
&.disabled{
&.disabled {
background-color: rgba($session-color-warning, 0.6);
}
}
@ -886,7 +886,6 @@ label {
margin-left: 75px;
}
.conversation-loader {
height: 100%;
margin-top: 45vh;
@ -894,7 +893,7 @@ label {
align-items: center;
justify-content: center;
&>div{
& > div {
display: block;
}
}
@ -956,7 +955,6 @@ label {
}
}
.session-settings {
width: 100%;
height: 100vh;
@ -1036,22 +1034,17 @@ label {
transition: $session-transition-duration !important;
}
.network-status-container{
.network-status-container {
}
.discussion-container {
.module-message {
font-family: SFPro;
border-radius: 5px;
}
}
.bottom-bar textarea.send-message {
.bottom-bar textarea.send-message {
height: 60px;
background-color: $session-shade-4;
border: none;
@ -1071,4 +1064,4 @@ label {
&.active textarea {
border: none;
}
}
}

@ -13,7 +13,6 @@ $session-compose-margin: 20px;
@include session-dark-background-hover;
}
}
}
.gutter {
width: 380px !important;
@ -36,7 +35,7 @@ $session-compose-margin: 20px;
color: $session-color-white !important;
background-color: $session-shade-10 !important;
}
position: static !important;
font-weight: 700 !important;
box-shadow: none !important;
@ -71,8 +70,6 @@ $session-compose-margin: 20px;
@at-root .dark-theme #{&} {
color: $session-shade-17;
}
}
&__header__name--with-unread .module-conversation__user__profile-number,
@ -95,7 +92,7 @@ $session-compose-margin: 20px;
@at-root .dark-theme #{&} {
color: $session-shade-17;
}
font-size: 15px;
}
}
@ -112,12 +109,10 @@ $session-compose-margin: 20px;
@at-root .dark-theme #{&} {
color: $session-color-white;
}
}
}
.inbox {
@at-root .light-theme #{&} {
color: $session-color-black;
}
@ -126,7 +121,6 @@ $session-compose-margin: 20px;
}
}
.module-left-pane {
border-right: none !important;
width: 300px;
@ -169,7 +163,7 @@ $session-compose-margin: 20px;
@at-root .dark-theme #{&} {
background-color: $session-shade-3;
}
.session-button {
margin-left: auto;
}
@ -320,7 +314,7 @@ $session-compose-margin: 20px;
&:focus {
outline: none !important;
}
@at-root .light-theme #{&} {
color: $session-color-black;
background: $session-color-white;
@ -403,7 +397,6 @@ $session-compose-margin: 20px;
background: $session-shade-4;
color: $session-color-light-grey;
}
&-selected,
&:hover {
@ -417,7 +410,6 @@ $session-compose-margin: 20px;
color: $session-color-white;
background: $session-shade-8;
}
}
}
}

@ -28,7 +28,6 @@
&__metadata__badge,
&__metadata__date--incoming,
&__metadata__date--outgoing {
@at-root .light-theme #{&} {
@include session-color-subtle($session-color-black);
}
@ -53,7 +52,6 @@
@at-root .dark-theme #{&} {
background-color: $session-shade-11;
}
}
&__container {
@ -65,7 +63,7 @@
.message {
&-highlighted {
border-radius: 0;
@at-root .light-theme #{&} {
background-color: $session-shade-5;
}

@ -97,7 +97,7 @@ $session-compose-margin: 20px;
margin: 30px auto 30px auto;
&:last-child {
margin: auto auto 30px auto;
/* Hide theme icon until light theme is ready */
display: none;
}
@ -208,7 +208,6 @@ $session-compose-margin: 20px;
flex-shrink: 0;
}
}
}
.user-search-dropdown {
@ -438,4 +437,3 @@ $session-compose-margin: 20px;
border: 1px solid $session-color-dark-grey;
}
}

@ -35,7 +35,6 @@ body.dark-theme {
}
.bottom-bar {
form.send {
&.video-attachment {
.outer {

@ -2,14 +2,12 @@ import React from 'react';
import { SessionSpinner } from './session/SessionSpinner';
export class ConversationLoadingScreen extends React.PureComponent {
constructor(props: any) {
super(props);
}
public render() {
return (
<div className="conversation-loader">
<SessionSpinner />

@ -2,148 +2,25 @@ import React from 'react';
import ReactDOM from 'react-dom';
import {
SessionSettingListItem,
SessionSettingType,
} from './session/settings/SessionSettingListItem';
import { SessionSettingCategory } from './session/LeftPaneSettingSection';
import { SessionButtonColor } from './session/SessionButton';
import { SessionIconButton, SessionIconType, SessionIconSize } from './session/icon';
// Grab initial values from database on startup
const localSettings = [
{
id: 'typingIndicators',
title: 'Typing Indicators',
description:
'See and share when messages are being typed. This setting is optional and applies to all conversations.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
value: false,
},
{
id: 'screenLock',
title: 'Screen Lock',
description:
'Unlock Loki Session using your password. Visit notification settings to customise.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
value: true,
},
{
id: 'screenSecurity',
title: 'Screen Security',
description:
'Prevent Loki Session previews from appearing in desktop notifications.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
value: false,
},
{
id: 'linkPreviews',
title: 'Send Link Previews',
description:
'Supported for Imgur, Instagram, Pinterest, Reddit and YouTube.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
value: true,
},
{
id: 'clearConversationHistory',
title: 'Clear Conversation History',
category: SessionSettingCategory.Privacy,
type: SessionSettingType.Button,
value: false,
buttonText: 'Clear',
buttonColor: SessionButtonColor.Danger,
},
{
id: 'changePassword',
title: 'Change Password',
category: SessionSettingCategory.Account,
type: SessionSettingType.Button,
value: false,
buttonText: 'Change',
buttonColor: SessionButtonColor.Primary,
},
{
id: 'removePassword',
title: 'Remove Password',
category: SessionSettingCategory.Account,
type: SessionSettingType.Button,
value: false,
buttonText: 'Remove',
buttonColor: SessionButtonColor.Danger,
},
];
SessionSettingCategory,
SettingsView,
} from './session/settings/SessionSettings';
export class MainViewController {
constructor() {}
public static renderMessageView() {
ReactDOM.render(
<MessageView/>,
document.getElementById('main-view')
);
static renderMessageView() {
ReactDOM.render(<MessageView />, document.getElementById('main-view'));
}
public static renderSettingsView(category: SessionSettingCategory) {
static renderSettingsView(category: SessionSettingCategory) {
ReactDOM.render(
<SettingsView category={category}/>,
<SettingsView category={category} />,
document.getElementById('main-view')
);
}
}
interface SettingsViewProps {
category: SessionSettingCategory
}
export class SettingsView extends React.Component<SettingsViewProps>{
public settingsViewRef: React.RefObject<HTMLDivElement>;
public constructor(props: any) {
super(props);
this.settingsViewRef = React.createRef();
}
render() {
const { category } = this.props;
return (
<div className="session-settings">
<SettingsHeader category={category}/>
<div
ref = {this.settingsViewRef}
className="session-settings-list"
>
{localSettings.map(setting => {
return (
<div key={setting.id}>
{setting.category === category && (
<SessionSettingListItem
title={setting.title}
description={setting.description}
type={setting.type}
value={setting.value}
onClick={() => {
SettingsManager.updateSetting(setting);
}}
buttonText={setting.buttonText || undefined}
buttonColor={setting.buttonColor || undefined}
/>
)}
</div>
);
})}
</div>
</div>
)
}
}
export class MessageView extends React.Component {
render() {
return (
@ -155,6 +32,7 @@ export class MessageView extends React.Component {
<img
src="images/session/brand.svg"
className="session-filter-color-green session-logo-128"
alt="Brand"
/>
<p className="session-logo-text">SESSION</p>
</div>
@ -164,50 +42,3 @@ export class MessageView extends React.Component {
);
}
}
export class SettingsHeader extends React.Component<SettingsViewProps>{
public constructor(props: any) {
super(props);
}
public focusSearch(){
$('.left-pane-setting-section .session-search-input input').focus();
}
render() {
const category = String(this.props.category)
const categoryTitlePrefix = category[0].toUpperCase() + category.substr(1);
// Remove 's' on the end to keep words in singular form
const categoryTitle = categoryTitlePrefix[categoryTitlePrefix.length - 1] === 's'
? categoryTitlePrefix.slice(0, -1) + ' Settings'
: categoryTitlePrefix + ' Settings';
return (
<div className="session-settings-header">
{ categoryTitle }
<SessionIconButton
iconType={SessionIconType.Search}
iconSize={SessionIconSize.Large}
onClick={this.focusSearch}
/>
</div>
);
}
}
export class SettingsManager {
public static updateSetting({ id, type, value }) {
if (type === SessionSettingType.Toggle) {
alert(`You clicked a toggle with ID: ${id}`);
// Manage toggle events
return;
}
alert('you clicked something else');
return;
}
}

@ -17,7 +17,7 @@ import { cleanSearchTerm } from '../../util/cleanSearchTerm';
import { SearchOptions } from '../../types/Search';
import { validateNumber } from '../../types/PhoneNumber';
import { LeftPane, RowRendererParamsType } from '../LeftPane';
import { SessionButton, SessionButtonType, SessionButtonColor } from './SessionButton';
import { SessionButton, SessionButtonType } from './SessionButton';
export interface Props {
searchTerm: string;
@ -146,18 +146,6 @@ export class LeftPaneMessageSection extends React.Component<Props, any> {
return [list];
}
public renderMessagePanelButtons(): JSX.Element {
return (
<div className="module-left-pane__header-buttons">
<SessionButton
text={window.i18n('showAddServer')}
buttonType={SessionButtonType.Square}
onClick={window.showAddServerDialog}
/>
</div>
);
}
public renderHeader(): JSX.Element {
const labels = [window.i18n('messagesHeader')];
@ -193,7 +181,6 @@ export class LeftPaneMessageSection extends React.Component<Props, any> {
public renderConversations() {
return (
<div>
{this.renderMessagePanelButtons()}
<SessionSearchInput
searchString={this.props.searchTerm}
onChange={this.updateSearchBound}

@ -13,14 +13,7 @@ import {
import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
import { SessionSearchInput } from './SessionSearchInput';
export enum SessionSettingCategory {
General = 'general',
Account = 'account',
Privacy = 'privacy',
Notifications = 'notifications',
Devices = 'devices',
}
import { SessionSettingCategory } from './settings/SessionSettings';
export interface Props {}

@ -55,7 +55,12 @@ export class SessionButton extends React.PureComponent<Props> {
return (
<div
className={classNames('session-button', ...buttonTypes, buttonColor, disabled && 'disabled')}
className={classNames(
'session-button',
...buttonTypes,
buttonColor,
disabled && 'disabled'
)}
role="button"
onClick={disabled ? () => null : this.clickHandler}
>

@ -1,22 +1,14 @@
import React from 'react';
import { SessionToggle } from '../SessionToggle';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from '../SessionButton';
export enum SessionSettingType {
Toggle = 'toggle',
Options = 'options',
Button = 'button',
}
import { SessionButton, SessionButtonColor } from '../SessionButton';
import { SessionSettingType } from './SessionSettings';
interface Props {
title: string;
description?: string;
type: SessionSettingType;
value: boolean | string;
value: any;
options?: Array<any>;
onClick?: any;
buttonText?: string;
buttonColor?: SessionButtonColor;
@ -26,6 +18,8 @@ export class SessionSettingListItem extends React.Component<Props> {
public constructor(props: Props) {
super(props);
this.state = {};
this.handleClick = this.handleClick.bind(this);
}
public render(): JSX.Element {
@ -34,7 +28,6 @@ export class SessionSettingListItem extends React.Component<Props> {
description,
type,
value,
onClick,
buttonText,
buttonColor,
} = this.props;
@ -53,7 +46,7 @@ export class SessionSettingListItem extends React.Component<Props> {
{type === SessionSettingType.Toggle && (
<div className="session-sessings-item__selection">
<SessionToggle active={Boolean(value)} onClick={onClick} />
<SessionToggle active={Boolean(value)} onClick={this.handleClick} />
</div>
)}
@ -61,10 +54,14 @@ export class SessionSettingListItem extends React.Component<Props> {
<SessionButton
text={buttonText}
buttonColor={buttonColor}
onClick={onClick}
onClick={this.handleClick}
/>
)}
</div>
);
}
private handleClick() {
this.props.onClick && this.props.onClick();
}
}

@ -0,0 +1,156 @@
import React from 'react';
import { SettingsHeader } from './SessionSettingsHeader';
import { SessionSettingListItem } from './SessionSettingListItem';
import { SessionButtonColor } from '../SessionButton';
export enum SessionSettingCategory {
General = 'general',
Account = 'account',
Privacy = 'privacy',
Notifications = 'notifications',
Devices = 'devices',
}
export enum SessionSettingType {
Toggle = 'toggle',
Options = 'options',
Button = 'button',
}
// Grab initial values from database on startup
const localSettings = [
{
id: 'theme',
title: 'Light Mode',
description: 'Choose the theme best suited to you',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
afterClick: () => window.toggleTheme(),
},
{
id: 'typingIndicators',
title: 'Typing Indicators',
description:
'See and share when messages are being typed. This setting is optional and applies to all conversations.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
},
{
id: 'screenLock',
title: 'Screen Lock',
description:
'Unlock Loki Session using your password. Visit notification settings to customise.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
},
{
id: 'screenSecurity',
title: 'Screen Security',
description:
'Prevent Loki Session previews from appearing in desktop notifications.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
},
{
id: 'linkPreviews',
title: 'Send Link Previews',
description:
'Supported for Imgur, Instagram, Pinterest, Reddit and YouTube.',
type: SessionSettingType.Toggle,
category: SessionSettingCategory.Privacy,
},
{
id: 'clearConversationHistory',
title: 'Clear Conversation History',
category: SessionSettingCategory.Privacy,
type: SessionSettingType.Button,
buttonText: 'Clear',
buttonColor: SessionButtonColor.Danger,
},
{
id: 'changePassword',
title: 'Change Password',
category: SessionSettingCategory.Account,
type: SessionSettingType.Button,
buttonText: 'Change',
buttonColor: SessionButtonColor.Primary,
},
{
id: 'removePassword',
title: 'Remove Password',
category: SessionSettingCategory.Account,
type: SessionSettingType.Button,
buttonText: 'Remove',
buttonColor: SessionButtonColor.Danger,
},
];
export interface SettingsViewProps {
category: SessionSettingCategory;
}
export class SettingsView extends React.Component<SettingsViewProps> {
public settingsViewRef: React.RefObject<HTMLDivElement>;
public constructor(props: any) {
super(props);
this.settingsViewRef = React.createRef();
}
public renderSettingInCategory() {
return (
<>
{localSettings.map(setting => {
const { category } = this.props;
const renderSettings = setting.category === category;
return (
<div key={setting.id}>
{renderSettings && (
<SessionSettingListItem
title={setting.title}
description={setting.description}
type={setting.type}
value={window.getSettingValue(setting.id)}
onClick={() => {
SettingsManager.updateSetting(setting);
}}
buttonText={setting.buttonText || undefined}
buttonColor={setting.buttonColor || undefined}
/>
)}
</div>
);
})}
</>
);
}
public render() {
const { category } = this.props;
return (
<div className="session-settings">
<SettingsHeader category={category} />
<div ref={this.settingsViewRef} className="session-settings-list">
{this.renderSettingInCategory()}
</div>
</div>
);
}
}
export class SettingsManager {
public static updateSetting(item: any) {
if (item.type === SessionSettingType.Toggle) {
//alert(`You clicked a toggle with ID: ${item.id}`);
// Manage toggle events
}
// If there's an onClick function, execute it
item.afterClick && item.afterClick();
return;
}
}

@ -0,0 +1,35 @@
import React from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon';
import { SettingsViewProps } from './SessionSettings';
export class SettingsHeader extends React.Component<SettingsViewProps> {
public constructor(props: any) {
super(props);
}
public focusSearch() {
$('.left-pane-setting-section .session-search-input input').focus();
}
render() {
const category = String(this.props.category);
const categoryTitlePrefix = category[0].toUpperCase() + category.substr(1);
// Remove 's' on the end to keep words in singular form
const categoryTitle =
categoryTitlePrefix[categoryTitlePrefix.length - 1] === 's'
? categoryTitlePrefix.slice(0, -1) + ' Settings'
: categoryTitlePrefix + ' Settings';
return (
<div className="session-settings-header">
{categoryTitle}
<SessionIconButton
iconType={SessionIconType.Search}
iconSize={SessionIconSize.Large}
onClick={this.focusSearch}
/>
</div>
);
}
}

4
ts/global.d.ts vendored

@ -1,7 +1,6 @@
interface Window {
Events: any;
deleteAllData: any;
deleteAccount: any;
getAccountManager: any;
mnemonic: any;
clipboard: any;
@ -25,6 +24,9 @@ interface Window {
showSeedDialog: any;
showAddServerDialog: any;
toggleTheme: any;
deleteAccount: any;
getSettingValue: any;
setSettingValue: any;
}
interface Promise<T> {

Loading…
Cancel
Save