Merge branch 'theme_switching' into theming

pull/2521/head
William Grant 3 years ago
commit f505427bee

@ -150,6 +150,11 @@ window.readyForUpdates = () => {
ipc.send('ready-for-updates');
};
ipc.on('get-primary-color-setting', () => {
const primaryColor = window.Events.getPrimaryColorSetting();
ipc.send('get-success-primary-color-setting', primaryColor);
});
ipc.on('get-theme-setting', () => {
const theme = window.Events.getThemeSetting();
ipc.send('get-success-theme-setting', theme);

@ -108,18 +108,18 @@
// button {
// float: right;
// margin-inline-start: 10px;
// background-color: var(--color-session-green-color);
// background-color: var(--primary-color);
// border-radius: 100px;
// padding: 5px 15px;
// border: 1px solid var(--color-session-green-color);
// border: 1px solid var(--primary-color);
// color: white;
// outline: none;
// user-select: none;
// &:hover,
// &:disabled {
// background-color: var(--color-session-green-color)-dark;
// border-color: var(--color-session-green-color)-dark;
// background-color: var(--primary-color)-dark;
// border-color: var(--primary-color)-dark;
// }
// &:disabled {

@ -597,7 +597,7 @@
height: 36px;
width: 36px;
@include color-svg('../images/play.svg', var(--color-session-green-color));
@include color-svg('../images/play.svg', var(--primary-color));
}
.module-media-grid-item__icon-video {
@ -826,7 +826,7 @@
height: 36px;
width: 36px;
@include color-svg('../images/play.svg', var(--color-session-green-color));
@include color-svg('../images/play.svg', var(--primary-color));
}
.module-image__text-container {

@ -54,19 +54,19 @@
}
.module-quote__icon-container__icon--file {
@include color-svg('../images/file.svg', var(--color-session-green-color));
@include color-svg('../images/file.svg', var(--primary-color));
}
.module-quote__icon-container__icon--image {
@include color-svg('../images/image.svg', var(--color-session-green-color));
@include color-svg('../images/image.svg', var(--primary-color));
}
.module-quote__icon-container__icon--microphone {
@include color-svg('../images/microphone.svg', var(--color-session-green-color));
@include color-svg('../images/microphone.svg', var(--primary-color));
}
.module-quote__icon-container__icon--play {
@include color-svg('../images/play.svg', var(--color-session-green-color));
@include color-svg('../images/play.svg', var(--primary-color));
}
.module-quote__icon-container__icon--movie {
@include color-svg('../images/movie.svg', var(--color-session-green-color));
@include color-svg('../images/movie.svg', var(--primary-color));
}
.module-quote__generic-file__text {
@ -207,19 +207,19 @@
height: 24px;
&--file {
@include color-svg('../images/file.svg', var(--color-session-green-color));
@include color-svg('../images/file.svg', var(--primary-color));
}
&--image {
@include color-svg('../images/image.svg', var(--color-session-green-color));
@include color-svg('../images/image.svg', var(--primary-color));
}
&--microphone {
@include color-svg('../images/microphone.svg', var(--color-session-green-color));
@include color-svg('../images/microphone.svg', var(--primary-color));
}
&--play {
@include color-svg('../images/play.svg', var(--color-session-green-color));
@include color-svg('../images/play.svg', var(--primary-color));
}
&--movie {
@include color-svg('../images/movie.svg', var(--color-session-green-color));
@include color-svg('../images/movie.svg', var(--primary-color));
}
}
@ -278,7 +278,7 @@
}
}
$session-highlight-message-shadow: 0px 0px 10px 1px var(--color-session-green-color);
$session-highlight-message-shadow: 0px 0px 10px 1px var(--primary-color);
@keyframes remove-box-shadow {
0% {

@ -327,9 +327,9 @@ label {
}
&__text-highlight {
@include text-highlight(var(--color-session-green-color));
@include text-highlight(var(--primary-color));
color: black;
color: var(--black-color);
font-family: monospace;
font-style: normal;

@ -446,7 +446,7 @@ $rhap_font-family: inherit !default;
height: 15px;
top: -5px;
margin-left: -10px;
background: var(--color-session-green-color);
background: var(--primary-color);
box-shadow: none;
box-shadow: rgba($rhap_theme-color, 0.5) 0 0 5px;
}

@ -25,16 +25,16 @@
-ms-touch-action: none;
touch-action: none;
box-sizing: border-box;
-webkit-tap-highlight-color: var(--color-transparent-color);
-webkit-tap-highlight-color: var(--transparent-color);
}
.rc-slider * {
box-sizing: border-box;
-webkit-tap-highlight-color: var(--color-transparent-color);
-webkit-tap-highlight-color: var(--transparent-color);
}
.rc-slider-rail {
position: absolute;
width: 100%;
background: var(--color-clickable-hovered);
background: var(--scroll-bar-fill-color);
height: 8px;
border-radius: 6px;
@ -51,26 +51,25 @@
margin-left: -2.3px;
cursor: grab;
border-radius: 4px;
/* TODO What should this be? */
background-color: var(--color-session-green-color);
background-color: var(--zoom-bar-selector-color);
-ms-touch-action: pan-x;
touch-action: pan-x;
}
.rc-slider-handle:focus {
border-color: var(--color-session-green-color);
box-shadow: 0 0 0 5px rgba(var(--color-white-color-rgb), 0.2);
border-color: var(--zoom-bar-selector-color);
box-shadow: none;
outline: none;
}
.rc-slider-handle-click-focused:focus {
border-color: rgba(var(--color-white-color-rgb), 0.2);
border-color: var(--zoom-bar-selector-color);
box-shadow: unset;
}
.rc-slider-handle:hover {
border-color: var(--color-session-green-color);
border-color: var(--zoom-bar-selector-color);
}
.rc-slider-handle:active {
border-color: var(--color-session-green-color);
box-shadow: 0 0 5px rgba(var(--color-white-color-rgb), 0.2);
border-color: var(--zoom-bar-selector-color);
box-shadow: none;
cursor: -webkit-grabbing;
cursor: grabbing;
}
@ -87,10 +86,10 @@
vertical-align: middle;
text-align: center;
cursor: pointer;
color: var(--color-light-gray-color);
color: var(--text-secondary-color);
}
.rc-slider-mark-text-active {
color: var(--color-gray-color);
color: var(--text-primary-color);
}
.rc-slider-step {
position: absolute;
@ -105,7 +104,7 @@
margin-left: -4px;
width: 3px;
height: 6px;
background: var(--color-clickable-hovered);
background: var(--zoom-bar-interval-color);
cursor: pointer;
border-radius: 2px;
@ -118,20 +117,20 @@
margin-right: -2px;
}
.rc-slider-dot-active {
border-color: var(--color-light-blue-color);
border-color: var(--primary-color);
}
.rc-slider-dot-reverse {
margin-left: 0;
margin-right: -4px;
}
.rc-slider-disabled {
background-color: var(--color-lighter-gray-color);
background-color: var(--scroll-bar-fill-color);
}
.rc-slider-disabled .rc-slider-handle,
.rc-slider-disabled .rc-slider-dot {
border-color: var(--color-light-gray-color);
border-color: var(--zoom-bar-interval-color);
box-shadow: none;
background-color: var(--color-white-color);
background-color: var(--zoom-bar-interval-color);
cursor: not-allowed;
}
.rc-slider-disabled .rc-slider-mark-text,
@ -229,11 +228,11 @@
top: -9999px;
visibility: visible;
box-sizing: border-box;
-webkit-tap-highlight-color: var(--color-transparent-color);
-webkit-tap-highlight-color: var(--transparent-color);
}
.rc-slider-tooltip * {
box-sizing: border-box;
-webkit-tap-highlight-color: var(--color-transparent-color);
-webkit-tap-highlight-color: var(--transparent-color);
}
.rc-slider-tooltip-hidden {
display: none;
@ -247,12 +246,12 @@
height: 24px;
font-size: 12px;
line-height: 1;
color: var(--color-white-color);
color: var(--text-primary-color);
text-align: center;
text-decoration: none;
background-color: var(--color-gray-color);
background-color: var(--background-primary-color);
border-radius: 6px;
box-shadow: 0 0 4px var(--color-lighter-gray-color);
box-shadow: none;
}
.rc-slider-tooltip-arrow {
position: absolute;
@ -266,5 +265,5 @@
left: 50%;
margin-left: -4px;
border-width: 4px 4px 0;
border-top-color: var(--color-gray-color);
border-top-color: var(--background-primary-color);
}

@ -162,7 +162,7 @@
}
.module-message__video-overlay__play-icon {
@include color-svg('../images/play.svg', var(--color-session-green-color));
@include color-svg('../images/play.svg', var(--primary-color));
}
.module-message__broken-video-screenshot {
@ -223,7 +223,7 @@
}
.module-media-gallery__tab--active {
border-bottom: 2px solid var(--color-session-green-color);
border-bottom: 2px solid var(--primary-color);
}
// Module: Document List Item
@ -269,7 +269,7 @@
// .module-conversation-list-item__unread-count {
// color: var(--color-white-color);
// background-color: var(--color-session-green-color);
// background-color: var(--primary-color);
// box-shadow: 0px 0px 0px 1px var(--color-darkest-gray-color);
// }

@ -19,6 +19,7 @@ import { initialSearchState } from '../state/ducks/search';
import { initialSectionState } from '../state/ducks/section';
import { getEmptyStagedAttachmentsState } from '../state/ducks/stagedAttachments';
import { initialThemeState } from '../state/ducks/theme';
import { initialPrimaryColorState } from '../state/ducks/primaryColor';
import { TimerOptionsArray } from '../state/ducks/timerOptions';
import { initialUserConfigState } from '../state/ducks/userConfig';
import { StateType } from '../state/reducer';
@ -107,6 +108,7 @@ export class SessionInboxView extends React.Component<any, State> {
defaultRooms: initialDefaultRoomState,
search: initialSearchState,
theme: initialThemeState,
primaryColor: initialPrimaryColorState,
onionPaths: initialOnionPathState,
modals: initialModalState,
userConfig: initialUserConfigState,

@ -92,10 +92,10 @@ const StyledButton = styled.div<{
&:not(.disabled) {
&:hover {
color: ${props => `var(--button-${props.buttonType}-text-hover-color)`};
${props =>
props.buttonType &&
`background-color: var(--button-${props.buttonType}-background-hover-color);`};
${props => props.color && `color: var(--button-${props.buttonType}-text-color);`}
${props =>
props.buttonType === SessionButtonType.Outline &&
'outline: none; border: 1px solid var(--button-outline-border-hover-color);'};

@ -9,8 +9,9 @@ import { getTheme } from '../../state/selectors/theme';
import { noop } from 'lodash';
import { loadEmojiPanelI18n } from '../../util/i18n';
import { FixedBaseEmoji, FixedPickerProps } from '../../types/Reaction';
import { ThemeStateType } from '../../themes/colors.js';
export const StyledEmojiPanel = styled.div<{ isModal: boolean; theme: 'light' | 'dark' }>`
export const StyledEmojiPanel = styled.div<{ isModal: boolean; theme: ThemeStateType }>`
padding: var(--margins-lg);
z-index: 5;
opacity: 0;
@ -40,14 +41,20 @@ export const StyledEmojiPanel = styled.div<{ isModal: boolean; theme: 'light' |
${props => {
switch (props.theme) {
case 'dark':
case 'ocean-dark':
// TODO Theming
return ``;
case 'ocean-light':
// TODO Theming
return ``;
case 'classic-dark':
return `
--background-rgb: 27, 27, 27; // var(--color-cell-background)
--rgb-background: 27, 27, 27;
--rgb-color: 255, 255, 255; // var(--color-text)
--rgb-input: 27, 27, 27;
`;
case 'light':
case 'classic-light':
default:
return `
--background-rgb: 249, 249, 249; // var(--color-cell-background)
@ -96,6 +103,7 @@ const pickerProps: FixedPickerProps = {
export const SessionEmojiPanel = forwardRef<HTMLDivElement, Props>((props: Props, ref) => {
const { onEmojiClicked, show, isModal = false, onKeyDown } = props;
const theme = useSelector(getTheme);
const emojiPanelTheme = theme.includes('light') ? 'light' : 'dark';
const pickerRef = ref as MutableRefObject<HTMLDivElement>;
useEffect(() => {
@ -112,7 +120,7 @@ export const SessionEmojiPanel = forwardRef<HTMLDivElement, Props>((props: Props
data,
ref,
i18n,
theme,
theme: emojiPanelTheme,
onEmojiSelect: onEmojiClicked,
onKeyDown,
...pickerProps,

@ -96,7 +96,7 @@ const generateContactsString = async (
};
const Contacts = (contacts: Array<string>, count: number) => {
const darkMode = useSelector(getTheme) === 'dark';
const darkMode = useSelector(getTheme).includes('dark');
if (!Boolean(contacts?.length > 0)) {
return;

@ -67,7 +67,7 @@ export const BanOrUnBanUserDialog = (props: {
const { i18n } = window;
const isBan = banType === 'ban';
const dispatch = useDispatch();
const darkMode = useSelector(getTheme) === 'dark';
const darkMode = useSelector(getTheme).includes('dark');
const convo = getConversationController().get(conversationId);
const inputRef = useRef(null);

@ -20,7 +20,7 @@ export const AddModeratorsDialog = (props: Props) => {
const { conversationId } = props;
const dispatch = useDispatch();
const darkMode = useSelector(getTheme) === 'dark';
const darkMode = useSelector(getTheme).includes('dark');
const convo = getConversationController().get(conversationId);
const [inputBoxValue, setInputBoxValue] = useState('');

@ -54,7 +54,7 @@ export const ReactClearAllModal = (props: Props): ReactElement => {
const [clearingInProgress, setClearingInProgress] = useState(false);
const dispatch = useDispatch();
const darkMode = useSelector(getTheme) === 'dark';
const darkMode = useSelector(getTheme).includes('dark');
const msgProps = useMessageReactsPropsById(messageId);
if (!msgProps) {

@ -52,6 +52,7 @@ export type SessionIconType =
| 'search'
| 'shield'
| 'star'
| 'sun'
| 'stopwatch'
| 'qr'
| 'users'
@ -404,6 +405,12 @@ export const icons = {
viewBox: '0 0 512 512',
ratio: 1,
},
sun: {
path:
'M16.6209 7.62069C11.8081 7.62069 7.89156 11.5372 7.89156 16.35C7.89156 21.1628 11.8081 25.0793 16.6209 25.0793C21.4337 25.0793 25.3502 21.1628 25.3502 16.35C25.3502 11.5372 21.4337 7.62069 16.6209 7.62069ZM16.6209 22.5852C13.1768 22.5852 10.3856 19.794 10.3856 16.35C10.3856 12.906 13.1768 10.1148 16.6209 10.1148C20.0649 10.1148 22.8561 12.906 22.8561 16.35C22.8561 19.794 20.0649 22.5852 16.6209 22.5852ZM16.6209 5.1266C17.3093 5.1266 17.8679 4.568 17.8679 3.87956V1.38547C17.8679 0.697025 17.3093 0.138428 16.6209 0.138428C15.9324 0.138428 15.3738 0.697025 15.3738 1.38547V3.87956C15.3738 4.568 15.9324 5.1266 16.6209 5.1266ZM16.6209 27.5734C15.9324 27.5734 15.3738 28.132 15.3738 28.8204V31.3145C15.3738 32.0029 15.9324 32.5615 16.6209 32.5615C17.3093 32.5615 17.8679 32.0029 17.8679 31.3145V28.8204C17.8679 28.132 17.3093 27.5734 16.6209 27.5734ZM26.3196 8.4131L28.083 6.64971C28.5701 6.16258 28.5701 5.37344 28.083 4.88631C27.5959 4.39918 26.8067 4.39918 26.3196 4.88631L24.5562 6.64971C24.0691 7.13683 24.0691 7.92598 24.5562 8.4131C25.0433 8.90023 25.8325 8.90023 26.3196 8.4131ZM6.92214 24.2869L5.15874 26.0503C4.67162 26.5374 4.67162 27.3265 5.15874 27.8137C5.64587 28.3008 6.43501 28.3008 6.92214 27.8137L8.68554 26.0503C9.17266 25.5616 9.17266 24.774 8.68554 24.2869C8.19849 23.7997 7.40927 23.7981 6.92214 24.2869ZM5.39747 16.35C5.39747 15.6615 4.83888 15.1029 4.15043 15.1029H1.65634C0.967899 15.1029 0.409302 15.6615 0.409302 16.35C0.409302 17.0384 0.967899 17.597 1.65634 17.597H4.15043C4.83888 17.597 5.39747 17.0384 5.39747 16.35ZM31.5854 15.1029H29.0913C28.4028 15.1029 27.8442 15.6615 27.8442 16.35C27.8442 17.0384 28.4028 17.597 29.0913 17.597H31.5854C32.2738 17.597 32.8324 17.0384 32.8324 16.35C32.8324 15.6615 32.2738 15.1029 31.5854 15.1029ZM6.9205 8.4131C7.40771 8.90023 8.19685 8.90023 8.6839 8.4131C9.1711 7.92598 9.1711 7.13683 8.6839 6.64971L6.9205 4.88631C6.43338 4.39918 5.64431 4.39918 5.15711 4.88631C4.66998 5.37344 4.66998 6.16258 5.15711 6.64971L6.9205 8.4131ZM26.3212 24.2852C25.8325 23.7981 25.0449 23.7981 24.5578 24.2852C24.0706 24.7724 24.0691 25.5615 24.5578 26.0486L26.3212 27.812C26.8083 28.2992 27.5974 28.2992 28.0845 27.812C28.5717 27.3249 28.5717 26.5358 28.0845 26.0486L26.3212 24.2852Z',
viewBox: '0 0 33 33',
ratio: 1,
},
qr: {
path:
'M0 0v170h170V0H0zm130 130H40V40h90v90z M65 65h40v40H65zM342 0v170h170V0H342zm130 130h-90V40h90v90z M407 65h40v40h-40zM0 342v170h170V342H0zm130 130H40v-90h90v90z M65 407h40v40H65zM40 197h40v40H40zM120 277v-40H80v40h39v40h40v-40zM280 77h40v40h-40zM200 40h40v77h-40zM240 0h40v40h-40zM240 117v40h-40v40h80v-80zM280 355v-39h-40v-79h-40v80h40v39h40v39h80v-40z M280 197h40v80h-40zM472 236v-39h-73v40h-39v40h40v39h112v-80h-40zm0 40h-72v-39h72v39zM472 355h40v80h-40zM320 277h40v40h-40zM360 395h40v40h-40zM400 355h40v40h-40zM400 435v77h40v-37h32v-40zM200 356h40v76h-40zM320 472v-40h-80v80h40v-40h39v40h40v-40zM120 197h80v40h-80zM0 237h40v80H0z',

@ -50,6 +50,9 @@ import { UserUtils } from '../../session/utils';
import { getLatestReleaseFromFileServer } from '../../session/apis/file_server_api/FileServerApi';
import { switchThemeTo } from '../../session/utils/Theme';
import { ThemeStateType } from '../../themes/colors';
import { getTheme } from '../../state/selectors/theme';
import { switchPrimaryColor } from '../../themes/switchPrimaryColor';
const Section = (props: { type: SectionType }) => {
const ourNumber = useSelector(getOurNumber);
@ -57,6 +60,7 @@ const Section = (props: { type: SectionType }) => {
const dispatch = useDispatch();
const { type } = props;
const theme = useSelector(getTheme);
const focusedSection = useSelector(getFocusedSection);
const isSelected = focusedSection === props.type;
@ -64,10 +68,11 @@ const Section = (props: { type: SectionType }) => {
/* tslint:disable:no-void-expression */
if (type === SectionType.Profile) {
dispatch(editProfileModal({}));
} else if (type === SectionType.Moon) {
// TODO Theming Toggle current theme light and dark mode with new system
const currentTheme = window.Events.getThemeSetting();
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
} else if (type === SectionType.ColorMode) {
const currentTheme = String(window.Events.getThemeSetting());
const newTheme = (currentTheme.includes('light')
? currentTheme.replace('light', 'dark')
: currentTheme.replace('dark', 'light')) as ThemeStateType;
await switchThemeTo(newTheme, dispatch);
} else if (type === SectionType.PathIndicator) {
@ -126,11 +131,12 @@ const Section = (props: { type: SectionType }) => {
id={'onion-path-indicator-led-id'}
/>
);
case SectionType.ColorMode:
default:
return (
<SessionIconButton
iconSize="medium"
iconType={'moon'}
iconType={theme.includes('light') ? 'sun' : 'moon'}
dataTestId="theme-section"
notificationCount={unreadToShow}
onClick={handleClick}
@ -148,6 +154,9 @@ const cleanUpMediasInterval = DURATION.MINUTES * 60;
const fetchReleaseFromFileServerInterval = 1000 * 60; // try to fetch the latest release from the fileserver every minute
const setupTheme = async () => {
const primaryColor = window.Events.getPrimaryColorSetting();
await switchPrimaryColor(primaryColor, window?.inboxStore?.dispatch || null);
const theme = window.Events.getThemeSetting();
await switchThemeTo(theme, window?.inboxStore?.dispatch || null);
};
@ -295,7 +304,7 @@ export const ActionsPanel = () => {
<SessionToastContainer />
<Section type={SectionType.PathIndicator} />
<Section type={SectionType.Moon} />
<Section type={SectionType.ColorMode} />
</LeftPaneSectionContainer>
</>
);

@ -1,34 +1,31 @@
import React, { useState } from 'react';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { switchThemeTo } from '../../session/utils/Theme';
import {
darkColorReceivedMessageBg,
darkColorSentMessageBg,
getPrimaryColors,
lightColorReceivedMessageBg,
lightColorSentMessageBg,
OceanBlueDark,
OceanBlueLight,
PrimaryColorIds,
} from '../../themes/SessionTheme';
import { ThemeStateType } from '../../state/ducks/theme';
import { getTheme } from '../../state/selectors/theme';
import { SessionRadio, SessionRadioPrimaryColors } from '../basic/SessionRadio';
import { SpacerLG, SpacerMD } from '../basic/Text';
import { StyledDescriptionSettingsItem, StyledTitleSettingsItem } from './SessionSettingListItem';
import { getPrimaryColors, THEMES, ThemeStateType } from '../../themes/colors';
import { switchPrimaryColor } from '../../themes/switchPrimaryColor';
import { getPrimaryColor } from '../../state/selectors/primaryColor';
// tslint:disable: use-simple-attributes
const StyledSwitcherContainer = styled.div`
font-size: var(--font-size-md);
padding: var(--margins-lg);
background: var(--color-cell-background);
margin-bottom: var(--margins-lg);
background: var(--settings-tab-background-color);
color: var(--settings-tab-text-color);
border-top: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
`;
const ThemeContainer = styled.button`
background: var(--color-conversation-list);
border: 1px solid var(--color-clickable-hovered);
background: var(--background-secondary-color);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: var(--margins-sm);
display: flex;
@ -40,7 +37,7 @@ const ThemeContainer = styled.button`
transition: var(--default-duration);
:hover {
background: var(--color-clickable-hovered);
background: var(--settings-tab-background-hover-color);
}
`;
@ -59,8 +56,8 @@ type ThemeType = {
type StyleSessionSwitcher = {
background: string;
border: string;
receivedBg: string;
sentBg: string;
receivedBackground: string;
sentBackground: string;
};
const StyledPreview = styled.svg`
@ -75,11 +72,11 @@ const ThemePreview = (props: { style: StyleSessionSwitcher }) => {
d="M7.5.9h64.6c3.6 0 6.5 2.9 6.5 6.5v56.9c0 3.6-2.9 6.5-6.5 6.5H7.5c-3.6 0-6.5-2.9-6.5-6.5V7.4C1 3.9 3.9.9 7.5.9z"
/>
<path
fill={props.style.receivedBg}
fill={props.style.receivedBackground}
d="M8.7 27.9c0-3.2 2.6-5.7 5.7-5.7h30.4c3.2 0 5.7 2.6 5.7 5.7 0 3.2-2.6 5.7-5.7 5.7H14.4c-3.1.1-5.7-2.5-5.7-5.7z"
/>
<path
fill={props.style.sentBg}
fill={props.style.sentBackground}
d="M32.6 42.2c0-3.2 2.6-5.7 5.7-5.7h27c3.2 0 5.7 2.6 5.7 5.7 0 3.2-2.6 5.7-5.7 5.7h-27c-3.1 0-5.7-2.5-5.7-5.7z"
/>
</StyledPreview>
@ -89,43 +86,43 @@ const ThemePreview = (props: { style: StyleSessionSwitcher }) => {
const Themes = () => {
const themes: Array<ThemeType> = [
{
id: 'dark',
id: 'classic-dark',
title: window.i18n('classicDarkThemeTitle'),
style: {
background: '#000000',
border: '#414141',
receivedBg: darkColorReceivedMessageBg,
sentBg: darkColorSentMessageBg,
background: THEMES.CLASSIC_DARK.COLOR0,
border: THEMES.CLASSIC_DARK.COLOR3,
receivedBackground: THEMES.CLASSIC_DARK.COLOR2,
sentBackground: THEMES.CLASSIC_DARK.PRIMARY,
},
},
{
id: 'light',
id: 'classic-light',
title: window.i18n('classicLightThemeTitle'),
style: {
background: '#ffffff',
border: '#414141',
receivedBg: lightColorReceivedMessageBg,
sentBg: lightColorSentMessageBg,
background: THEMES.CLASSIC_LIGHT.COLOR6,
border: THEMES.CLASSIC_LIGHT.COLOR3,
receivedBackground: THEMES.CLASSIC_LIGHT.COLOR4,
sentBackground: THEMES.CLASSIC_LIGHT.PRIMARY,
},
},
{
id: 'ocean-dark',
title: window.i18n('oceanDarkThemeTitle'),
style: {
background: OceanBlueDark.background,
border: OceanBlueDark.border,
receivedBg: OceanBlueDark.received,
sentBg: OceanBlueDark.sent,
background: THEMES.OCEAN_DARK.COLOR2,
border: THEMES.OCEAN_DARK.COLOR4,
receivedBackground: THEMES.OCEAN_DARK.COLOR4,
sentBackground: THEMES.OCEAN_DARK.PRIMARY,
},
},
{
id: 'ocean-light',
title: window.i18n('oceanLightThemeTitle'),
style: {
background: OceanBlueLight.background,
border: OceanBlueLight.border,
receivedBg: OceanBlueLight.received,
sentBg: OceanBlueLight.sent,
background: THEMES.OCEAN_LIGHT.COLOR7!,
border: THEMES.OCEAN_LIGHT.COLOR3,
receivedBackground: THEMES.OCEAN_LIGHT.COLOR1,
sentBackground: THEMES.OCEAN_LIGHT.PRIMARY,
},
},
];
@ -135,32 +132,33 @@ const Themes = () => {
return (
<>
{themes.map(theme => {
function onSelectTheme() {
void switchThemeTo(theme.id, dispatch);
}
return (
<ThemeContainer key={theme.id} onClick={onSelectTheme}>
<ThemePreview style={theme.style} />
<SpacerLG />
<StyledTitleSettingsItem>{theme.title}</StyledTitleSettingsItem>
<SessionRadio
active={selectedTheme === theme.id}
label={''}
value={theme.id}
inputName={'theme-switcher'}
/>
</ThemeContainer>
);
})}
{themes.map(theme => (
<ThemeContainer
key={theme.id}
onClick={() => {
// TODO Change to switchTheme function
void switchThemeTo(theme.id, dispatch);
}}
>
<ThemePreview style={theme.style} />
<SpacerLG />
<StyledTitleSettingsItem>{theme.title}</StyledTitleSettingsItem>
<SessionRadio
active={selectedTheme === theme.id}
label={''}
value={theme.id}
inputName={'theme-switcher'}
/>
</ThemeContainer>
))}
</>
);
};
export const SettingsThemeSwitcher = () => {
//TODO Theming
const [selectedAccent, setSelectedAccent] = useState<PrimaryColorIds | undefined>(undefined);
const selectedPrimaryColor = useSelector(getPrimaryColor);
const dispatch = useDispatch();
return (
<StyledSwitcherContainer>
@ -176,13 +174,13 @@ export const SettingsThemeSwitcher = () => {
return (
<SessionRadioPrimaryColors
key={item.id}
active={item.id === selectedAccent}
active={item.id === selectedPrimaryColor}
value={item.id}
inputName="primary-colors"
ariaLabel={item.ariaLabel}
color={item.color}
onClick={() => {
setSelectedAccent(item.id);
switchPrimaryColor(item.id, dispatch);
}}
/>
);

@ -641,6 +641,8 @@ async function showDebugLogWindow() {
return;
}
// TODO Theming - Use on debug and about pages
const primaryColor = await getPrimaryColorFromMainWindow();
const theme = await getThemeFromMainWindow();
const size = mainWindow.getSize();
const options = {
@ -667,6 +669,7 @@ async function showDebugLogWindow() {
captureClicks(debugLogWindow);
// TODO Theming - Check if it needs the priary color
await debugLogWindow.loadURL(prepareURL([getAppRootPath(), 'debug_log.html'], { theme }));
debugLogWindow.on('closed', () => {
@ -1099,6 +1102,15 @@ ipc.on('set-auto-update-setting', async (_event, enabled) => {
}
});
async function getPrimaryColorFromMainWindow() {
return new Promise(resolve => {
ipc.once('get-success-primary-color-setting', (_event, value) => {
resolve(value);
});
mainWindow?.webContents.send('get-primary-color-setting');
});
}
async function getThemeFromMainWindow() {
return new Promise(resolve => {
ipc.once('get-success-theme-setting', (_event, value) => {

@ -95,13 +95,15 @@ function mapOldThemeToNew(theme: string) {
switch (theme) {
case 'dark':
case 'light':
return theme;
return `classic-${theme}`;
case 'android-dark':
return 'dark';
return 'classic-dark';
case 'android':
case 'ios':
case '':
return 'classic-light';
default:
return 'light';
return theme;
}
}
@ -125,7 +127,11 @@ Storage.onready(async () => {
// These make key operations available to IPC handlers created in preload.js
window.Events = {
getThemeSetting: () => Storage.get('theme-setting', 'light'),
getPrimaryColorSetting: () => Storage.get('primary-color-setting', 'green'),
setPrimaryColorSetting: async (value: any) => {
await Storage.put('primary-color-setting', value);
},
getThemeSetting: () => Storage.get('theme-setting', 'classic-light'),
setThemeSetting: async (value: any) => {
await Storage.put('theme-setting', value);
},

@ -1,27 +1,37 @@
import { Dispatch } from 'redux';
import { applyTheme, ThemeStateType } from '../../state/ducks/theme';
import { applyTheme } from '../../state/ducks/theme';
import { ThemeStateType } from '../../themes/colors';
import { switchHtmlToDarkTheme, switchHtmlToLightTheme } from '../../themes/SessionTheme';
import { switchTheme } from '../../themes/switchTheme';
export async function switchThemeTo(theme: ThemeStateType, dispatch: Dispatch | null) {
await window.setTheme(theme);
// for now, do not switch to ocean light nor dark theme as the SessionTheme associated with them is not complete
let newTheme: ThemeStateType | null = null;
switch (theme) {
case 'dark':
case 'classic-dark':
switchHtmlToDarkTheme();
newTheme = 'dark';
newTheme = 'classic-dark';
break;
case 'light':
case 'classic-light':
switchHtmlToLightTheme();
newTheme = 'light';
newTheme = 'classic-light';
break;
case 'ocean-dark':
switchHtmlToDarkTheme();
newTheme = 'ocean-dark';
break;
case 'ocean-light':
switchHtmlToLightTheme();
newTheme = 'ocean-light';
break;
default:
window.log.warn('Unsupported theme: ', theme);
}
switchTheme(theme);
if (newTheme) {
dispatch?.(applyTheme(newTheme));
}

@ -6,6 +6,7 @@ import { actions as user } from './ducks/user';
import { actions as sections } from './ducks/section';
import { actions as theme } from './ducks/theme';
import { actions as modalDialog } from './ducks/modalDialog';
import { actions as primaryColor } from './ducks/primaryColor';
export function mapDispatchToProps(dispatch: Dispatch): Object {
return {
@ -17,6 +18,7 @@ export function mapDispatchToProps(dispatch: Dispatch): Object {
...theme,
...sections,
...modalDialog,
...primaryColor,
},
dispatch
),

@ -3,6 +3,7 @@ import * as conversationDucks from './conversations';
import * as defaultRoomDucks from './defaultRooms';
import * as DialogsDucks from './modalDialog';
import * as OnionDucks from './onion';
import * as PrimaryColorDucks from './primaryColor';
import * as SearchDucks from './search';
import * as SectionDucks from './section';
import * as StagedAttachmentDucks from './stagedAttachments';
@ -15,6 +16,7 @@ export {
CallDucks,
DialogsDucks,
OnionDucks,
PrimaryColorDucks,
SearchDucks,
SectionDucks,
StagedAttachmentDucks,

@ -0,0 +1,34 @@
import { PrimaryColorStateType } from '../../themes/colors';
export const APPLY_PRIMARY_COLOR = 'APPLY_PRIMARY_COLOR';
export const applyPrimaryColor = (color: PrimaryColorStateType) => {
return {
type: APPLY_PRIMARY_COLOR,
payload: color,
};
};
export const initialPrimaryColorState: PrimaryColorStateType = 'green';
export const reducer = (
state: any = initialPrimaryColorState,
{
type,
payload,
}: {
type: string;
payload: PrimaryColorStateType;
}
): PrimaryColorStateType => {
switch (type) {
case APPLY_PRIMARY_COLOR:
return payload;
default:
return state;
}
};
export const actions = {
applyPrimaryColor,
};

@ -10,7 +10,7 @@ export enum SectionType {
Profile,
Message,
Settings,
Moon,
ColorMode,
PathIndicator,
}

@ -1,7 +1,6 @@
export const APPLY_THEME = 'APPLY_THEME';
import { ThemeStateType } from '../../themes/colors';
// TODO Theming - should be classic-light and classic-dark
export type ThemeStateType = 'light' | 'dark' | 'ocean-light' | 'ocean-dark';
export const APPLY_THEME = 'APPLY_THEME';
export const applyTheme = (theme: ThemeStateType) => {
return {
@ -10,7 +9,7 @@ export const applyTheme = (theme: ThemeStateType) => {
};
};
export const initialThemeState: ThemeStateType = 'light';
export const initialThemeState: ThemeStateType = 'classic-light';
export const reducer = (
state: any = initialThemeState,

@ -3,7 +3,8 @@ import { combineReducers } from 'redux';
import { reducer as search, SearchStateType } from './ducks/search';
import { ConversationsStateType, reducer as conversations } from './ducks/conversations';
import { reducer as user, UserStateType } from './ducks/user';
import { reducer as theme, ThemeStateType } from './ducks/theme';
import { reducer as theme } from './ducks/theme';
import { reducer as primaryColor } from './ducks/primaryColor';
import { reducer as section, SectionStateType } from './ducks/section';
import { defaultRoomReducer as defaultRooms, DefaultRoomsState } from './ducks/defaultRooms';
import { callReducer as call, CallStateType } from './ducks/call';
@ -16,12 +17,14 @@ import {
reducer as stagedAttachments,
StagedAttachmentsStateType,
} from './ducks/stagedAttachments';
import { PrimaryColorStateType, ThemeStateType } from '../themes/colors';
export type StateType = {
search: SearchStateType;
user: UserStateType;
conversations: ConversationsStateType;
theme: ThemeStateType;
primaryColor: PrimaryColorStateType;
section: SectionStateType;
defaultRooms: DefaultRoomsState;
onionPaths: OnionState;
@ -37,6 +40,7 @@ export const reducers = {
conversations,
user,
theme,
primaryColor,
section,
defaultRooms,
onionPaths,

@ -2,6 +2,7 @@ import * as CallSelectors from './call';
import * as ConversationSelectors from './conversations';
import * as ModalSelectors from './modal';
import * as OnionsSelectors from './onions';
import * as PrimaryColorSelectors from './primaryColor';
import * as SearchSelectors from './search';
import * as SectionSelectors from './section';
import * as StagedAttachmentSelectors from './stagedAttachments';
@ -15,6 +16,7 @@ export {
ConversationSelectors,
ModalSelectors,
OnionsSelectors,
PrimaryColorSelectors,
SearchSelectors,
SectionSelectors,
StagedAttachmentSelectors,

@ -0,0 +1,4 @@
import { PrimaryColorStateType } from '../../themes/colors';
import { StateType } from '../reducer';
export const getPrimaryColor = (state: StateType): PrimaryColorStateType => state.primaryColor;

@ -1,4 +1,4 @@
import { ThemeStateType } from '../../themes/colors';
import { StateType } from '../reducer';
import { ThemeStateType } from '../ducks/theme';
export const getTheme = (state: StateType): ThemeStateType => state.theme;

@ -347,7 +347,7 @@ export const switchHtmlToLightTheme = () => {
);
};
// default to light theme
// default to classic light theme
export const SessionGlobalStyles = createGlobalStyle`
html {
/* Old Theme Variables */
@ -487,7 +487,7 @@ export const SessionGlobalStyles = createGlobalStyle`
/* Text Box */
/* Also used for inputs specifically password box input */
--text-box-background-color: var(--background-primary-color);
--text-box-text-control-color: ${THEMES.CLASSIC_LIGHT.COLOR1};
--text-box-text-control-color: var(--text-secondary-color);
--text-box-text-user-color: var(--text-primary-color);
--text-box-border-color: ${THEMES.CLASSIC_LIGHT.COLOR2};
@ -542,7 +542,7 @@ export const SessionGlobalStyles = createGlobalStyle`
--button-solid-shadow-color: rgba(${hexColorToRGB(THEMES.CLASSIC_LIGHT.COLOR0)}, 0.25);
/* Simple */
/* TODO Theming - Should this be different? */
--button-simple-text-color: var(--text-primary-color);
--button-simple-disabled-color: var(--text-primary-color);
/* Icons */
@ -616,10 +616,12 @@ export const SessionGlobalStyles = createGlobalStyle`
/* TODO Theming - Should Pills have their own colors? */
/* Modals / Toasts */
/* Modals */
--modal-background-color: ${THEMES.CLASSIC_LIGHT.COLOR6};
--modal-text-color: var(--text-primary-color);
--modal-text-danger-color: var(--danger-color);
/* Toasts */
--toast-progress-color: rgba(${hexColorToRGB(THEMES.CLASSIC_LIGHT.COLOR0)}, 0.1);
/* Right Panel Items */
@ -642,45 +644,3 @@ export const SessionTheme = ({ children }: { children: any }) => (
{children}
</>
);
/**
* Just putting those new theme values used in the settings to avoid having conflicts for now.
*
*/
// TODO Theming need to improve this somehow
type SettingsThemeSwitcherColor = {
background: string;
border: string;
sent: string;
received: string;
};
export const OceanBlueDark: SettingsThemeSwitcherColor = {
background: '#242735',
border: '#3D4A5E',
sent: '#57C9FA',
received: '#3D4A5D',
};
export const OceanBlueLight: SettingsThemeSwitcherColor = {
background: '#ECFAFB',
border: '#5CAACC',
sent: '#57C9FA',
received: '#B3EDF2',
};
export type PrimaryColorIds = 'green' | 'blue' | 'yellow' | 'pink' | 'purple' | 'orange' | 'red';
type PrimaryColorType = { id: PrimaryColorIds; ariaLabel: string; color: string };
export const getPrimaryColors = (): Array<PrimaryColorType> => {
return [
{ id: 'green', ariaLabel: window.i18n('primaryColorGreen'), color: COLORS.PRIMARY.GREEN },
{ id: 'blue', ariaLabel: window.i18n('primaryColorBlue'), color: COLORS.PRIMARY.BLUE },
{ id: 'yellow', ariaLabel: window.i18n('primaryColorYellow'), color: COLORS.PRIMARY.YELLOW },
{ id: 'pink', ariaLabel: window.i18n('primaryColorPink'), color: COLORS.PRIMARY.PINK },
{ id: 'purple', ariaLabel: window.i18n('primaryColorPurple'), color: COLORS.PRIMARY.PURPLE },
{ id: 'orange', ariaLabel: window.i18n('primaryColorOrange'), color: COLORS.PRIMARY.ORANGE },
{ id: 'red', ariaLabel: window.i18n('primaryColorRed'), color: COLORS.PRIMARY.RED },
];
};

@ -76,7 +76,32 @@ const COLORS: Colors = {
BLACK: black,
};
export type PrimaryColorStateType =
| 'green'
| 'blue'
| 'yellow'
| 'pink'
| 'purple'
| 'orange'
| 'red';
type PrimaryColorType = { id: PrimaryColorStateType; ariaLabel: string; color: string };
export const getPrimaryColors = (): Array<PrimaryColorType> => {
return [
{ id: 'green', ariaLabel: window.i18n('primaryColorGreen'), color: COLORS.PRIMARY.GREEN },
{ id: 'blue', ariaLabel: window.i18n('primaryColorBlue'), color: COLORS.PRIMARY.BLUE },
{ id: 'yellow', ariaLabel: window.i18n('primaryColorYellow'), color: COLORS.PRIMARY.YELLOW },
{ id: 'pink', ariaLabel: window.i18n('primaryColorPink'), color: COLORS.PRIMARY.PINK },
{ id: 'purple', ariaLabel: window.i18n('primaryColorPurple'), color: COLORS.PRIMARY.PURPLE },
{ id: 'orange', ariaLabel: window.i18n('primaryColorOrange'), color: COLORS.PRIMARY.ORANGE },
{ id: 'red', ariaLabel: window.i18n('primaryColorRed'), color: COLORS.PRIMARY.RED },
];
};
// Themes
export type ThemeStateType = 'classic-light' | 'classic-dark' | 'ocean-light' | 'ocean-dark'; // used for redux state
type ThemeNames = 'CLASSIC_LIGHT' | 'CLASSIC_DARK' | 'OCEAN_LIGHT' | 'OCEAN_DARK';
type ThemeColors = {
PRIMARY: string;
@ -88,11 +113,12 @@ type ThemeColors = {
COLOR4: string;
COLOR5: string;
COLOR6: string;
COLOR7?: string; // Only used with Ocean Light
};
type Themes = Record<ThemeNames, ThemeColors>;
// Classic Light
const classicLightPrimary = '#31F196';
const classicLightPrimary = primaryGreen;
const classicLightDanger = dangerDark;
const classicLight0 = '#000000';
const classicLight1 = '#6D6D6D';
@ -103,7 +129,7 @@ const classicLight5 = '#F9F9F9';
const classicLight6 = '#FFFFFF';
// Classic Dark
const classicDarkPrimary = '#31F196';
const classicDarkPrimary = primaryGreen;
const classicDarkDanger = dangerLight;
const classicDark0 = '#000000';
const classicDark1 = '#1B1B1B';
@ -114,26 +140,27 @@ const classicDark5 = '#A1A2A1';
const classicDark6 = '#FFFFFF';
// Ocean Light
const oceanLightPrimary = '#57C9FA';
const oceanLightDanger = dangerDark;
const oceanLightPrimary = primaryBlue;
const oceanLightDanger = dangerLight;
const oceanLight0 = '#000000';
const oceanLight1 = '#1A1C28';
const oceanLight2 = '#252735';
const oceanLight3 = '#2B2D40';
const oceanLight4 = '#3D4A5D';
const oceanLight5 = '#A6A9CE';
const oceanLight6 = '#FFFFFF';
const oceanLight1 = '#19345D';
const oceanLight2 = '#6A6E90';
const oceanLight3 = '#5CAACC';
const oceanLight4 = '#B3EDF2';
const oceanLight5 = '#E7F3F4';
const oceanLight6 = '#ECFAFB';
const oceanLight7 = '#FCFFFF';
// Ocean Dark
const oceanDarkPrimary = '#57C9FA';
const oceanDarkDanger = dangerLight;
const oceanDark0 = '#19345D';
const oceanDark1 = '#6A6E90';
const oceanDark2 = '#5CAACC';
const oceanDark3 = '#B3EDF2';
const oceanDark4 = '#E7F3F4';
const oceanDark5 = '#ECFAFB';
const oceanDark6 = '#FCFFFF';
const oceanDarkPrimary = primaryBlue;
const oceanDarkDanger = dangerDark;
const oceanDark0 = '#000000';
const oceanDark1 = '#1A1C28';
const oceanDark2 = '#252735';
const oceanDark3 = '#2B2D40';
const oceanDark4 = '#3D4A5D';
const oceanDark5 = '#A6A9CE';
const oceanDark6 = '#FFFFFF';
const THEMES: Themes = {
CLASSIC_LIGHT: {
@ -168,6 +195,7 @@ const THEMES: Themes = {
COLOR4: oceanLight4,
COLOR5: oceanLight5,
COLOR6: oceanLight6,
COLOR7: oceanLight7,
},
OCEAN_DARK: {
PRIMARY: oceanDarkPrimary,

@ -0,0 +1,13 @@
import { Dispatch } from 'redux';
import { applyPrimaryColor } from '../state/ducks/primaryColor';
import { COLORS, PrimaryColorStateType } from './colors';
export async function switchPrimaryColor(color: PrimaryColorStateType, dispatch: Dispatch | null) {
await window.Events.setPrimaryColorSetting(color);
document.documentElement.style.setProperty(
'--primary-color',
(COLORS.PRIMARY as any)[`${color.toUpperCase()}`]
);
dispatch?.(applyPrimaryColor(color));
}

File diff suppressed because it is too large Load Diff

@ -58,6 +58,7 @@ export interface NativeEmojiData {
export interface FixedPickerProps {
autoFocus?: boolean | undefined;
title?: string | undefined;
// TODO Theming - Add Ocean Colors
theme?: 'auto' | 'light' | 'dark' | undefined;
perLine?: number | undefined;
stickySearch?: boolean | undefined;

Loading…
Cancel
Save