From b777d0bcd1cfee47301348189af191c169eb7d27 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 11 Oct 2022 11:37:58 +1100 Subject: [PATCH] feat: the primary color is now reset when changing themes refactored theme and primary color switching functions --- ts/components/AboutView.tsx | 6 +- ts/components/DebugLogView.tsx | 6 +- ts/components/SessionPasswordPrompt.tsx | 6 +- ts/components/leftpane/ActionsPanel.tsx | 26 ++++-- .../settings/SettingsThemeSwitcher.tsx | 81 ++++--------------- ts/themes/constants/colors.tsx | 81 ++++++++++++++++--- ts/themes/switchPrimaryColor.tsx | 13 ++- ts/themes/switchTheme.tsx | 37 ++++++--- 8 files changed, 158 insertions(+), 98 deletions(-) diff --git a/ts/components/AboutView.tsx b/ts/components/AboutView.tsx index 6d413c31a..363584729 100644 --- a/ts/components/AboutView.tsx +++ b/ts/components/AboutView.tsx @@ -36,7 +36,11 @@ export const AboutView = () => { useEffect(() => { if ((window as any).theme) { - void switchThemeTo((window as any).theme, null, false); + void switchThemeTo({ + theme: (window as any).theme, + mainWindow: false, + resetPrimaryColor: false, + }); } }, []); diff --git a/ts/components/DebugLogView.tsx b/ts/components/DebugLogView.tsx index dd5110308..377e2137d 100644 --- a/ts/components/DebugLogView.tsx +++ b/ts/components/DebugLogView.tsx @@ -101,7 +101,11 @@ const DebugLogViewAndSave = () => { export const DebugLogView = () => { useEffect(() => { if ((window as any).theme) { - void switchThemeTo((window as any).theme, null, false); + void switchThemeTo({ + theme: (window as any).theme, + mainWindow: false, + resetPrimaryColor: false, + }); } }, []); diff --git a/ts/components/SessionPasswordPrompt.tsx b/ts/components/SessionPasswordPrompt.tsx index bc45e88e6..5c7c44817 100644 --- a/ts/components/SessionPasswordPrompt.tsx +++ b/ts/components/SessionPasswordPrompt.tsx @@ -192,7 +192,11 @@ class SessionPasswordPromptInner extends React.PureComponent<{}, State> { export const SessionPasswordPrompt = () => { useEffect(() => { if ((window as any).theme) { - void switchThemeTo((window as any).theme, null, false); + void switchThemeTo({ + theme: (window as any).theme, + mainWindow: false, + resetPrimaryColor: false, + }); } }, []); diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 478bb44d0..575b015c0 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -49,10 +49,10 @@ import { ipcRenderer } from 'electron'; import { UserUtils } from '../../session/utils'; import { getLatestReleaseFromFileServer } from '../../session/apis/file_server_api/FileServerApi'; -import { switchThemeTo } from '../../session/utils/Theme'; +import { switchThemeTo } from '../../themes/switchTheme'; import { ThemeStateType } from '../../themes/constants/colors'; import { getTheme } from '../../state/selectors/theme'; -import { switchPrimaryColor } from '../../themes/switchPrimaryColor'; +import { switchPrimaryColorTo } from '../../themes/switchPrimaryColor'; const Section = (props: { type: SectionType }) => { const ourNumber = useSelector(getOurNumber); @@ -74,7 +74,12 @@ const Section = (props: { type: SectionType }) => { ? currentTheme.replace('light', 'dark') : currentTheme.replace('dark', 'light')) as ThemeStateType; - await switchThemeTo(newTheme, dispatch); + await switchThemeTo({ + theme: newTheme, + mainWindow: true, + resetPrimaryColor: true, + dispatch, + }); } else if (type === SectionType.PathIndicator) { // Show Path Indicator Modal dispatch(onionPathModal({})); @@ -154,11 +159,18 @@ 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); + // We don't want to reset the primary color on startup + await switchThemeTo({ + theme, + mainWindow: true, + resetPrimaryColor: false, + dispatch: window?.inboxStore?.dispatch || undefined, + }); + + // Set primary color after the theme is loaded so that it's not overwritten + const primaryColor = window.Events.getPrimaryColorSetting(); + await switchPrimaryColorTo(primaryColor, window?.inboxStore?.dispatch || null); }; // Do this only if we created a new Session ID, or if we already received the initial configuration message diff --git a/ts/components/settings/SettingsThemeSwitcher.tsx b/ts/components/settings/SettingsThemeSwitcher.tsx index 27a1e396f..c5549786c 100644 --- a/ts/components/settings/SettingsThemeSwitcher.tsx +++ b/ts/components/settings/SettingsThemeSwitcher.tsx @@ -1,13 +1,17 @@ import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import { switchThemeTo } from '../../session/utils/Theme'; +import { switchThemeTo } from '../../themes/switchTheme'; 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/constants/colors'; -import { switchPrimaryColor } from '../../themes/switchPrimaryColor'; +import { + getPrimaryColors, + getThemeColors, + StyleSessionSwitcher, +} from '../../themes/constants/colors'; +import { switchPrimaryColorTo } from '../../themes/switchPrimaryColor'; import { getPrimaryColor } from '../../state/selectors/primaryColor'; // tslint:disable: use-simple-attributes @@ -47,19 +51,6 @@ const ThemesContainer = styled.div` gap: var(--margins-lg); `; -type ThemeType = { - id: ThemeStateType; - title: string; - style: StyleSessionSwitcher; -}; - -type StyleSessionSwitcher = { - background: string; - border: string; - receivedBackground: string; - sentBackground: string; -}; - const StyledPreview = styled.svg` max-height: 100%; `; @@ -84,49 +75,7 @@ const ThemePreview = (props: { style: StyleSessionSwitcher }) => { }; const Themes = () => { - const themes: Array = [ - { - id: 'classic-dark', - title: window.i18n('classicDarkThemeTitle'), - style: { - background: THEMES.CLASSIC_DARK.COLOR0, - border: THEMES.CLASSIC_DARK.COLOR3, - receivedBackground: THEMES.CLASSIC_DARK.COLOR2, - sentBackground: THEMES.CLASSIC_DARK.PRIMARY, - }, - }, - { - id: 'classic-light', - title: window.i18n('classicLightThemeTitle'), - style: { - 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: 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: THEMES.OCEAN_LIGHT.COLOR7!, - border: THEMES.OCEAN_LIGHT.COLOR3, - receivedBackground: THEMES.OCEAN_LIGHT.COLOR1, - sentBackground: THEMES.OCEAN_LIGHT.PRIMARY, - }, - }, - ]; - + const themes = getThemeColors(); const selectedTheme = useSelector(getTheme); const dispatch = useDispatch(); @@ -135,9 +84,13 @@ const Themes = () => { {themes.map(theme => ( { - // TODO Change to switchTheme function - void switchThemeTo(theme.id, dispatch); + onClick={async () => { + await switchThemeTo({ + theme: theme.id, + mainWindow: true, + resetPrimaryColor: true, + dispatch, + }); }} > @@ -179,8 +132,8 @@ export const SettingsThemeSwitcher = () => { inputName="primary-colors" ariaLabel={item.ariaLabel} color={item.color} - onClick={() => { - switchPrimaryColor(item.id, dispatch); + onClick={async () => { + await switchPrimaryColorTo(item.id, dispatch); }} /> ); diff --git a/ts/themes/constants/colors.tsx b/ts/themes/constants/colors.tsx index af75226e3..fbafa6ebd 100644 --- a/ts/themes/constants/colors.tsx +++ b/ts/themes/constants/colors.tsx @@ -91,22 +91,25 @@ export type PrimaryColorStateType = type PrimaryColorType = { id: PrimaryColorStateType; ariaLabel: string; color: string }; -export const getPrimaryColors = (): Array => { - 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 }, - ]; -}; +export const getPrimaryColors = (): Array => [ + { 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'; + +export function convertThemeStateToName(themeState: string): ThemeNames { + return themeState.replace('-', '_').toUpperCase() as ThemeNames; +} + type ThemeColors = { PRIMARY: string; DANGER: string; @@ -225,4 +228,60 @@ const THEMES: Themes = { }, }; +type ThemeType = { + id: ThemeStateType; + title: string; + style: StyleSessionSwitcher; +}; + +export type StyleSessionSwitcher = { + background: string; + border: string; + receivedBackground: string; + sentBackground: string; +}; + +export const getThemeColors = (): Array => [ + { + id: 'classic-dark', + title: window.i18n('classicDarkThemeTitle'), + style: { + background: THEMES.CLASSIC_DARK.COLOR0, + border: THEMES.CLASSIC_DARK.COLOR3, + receivedBackground: THEMES.CLASSIC_DARK.COLOR2, + sentBackground: THEMES.CLASSIC_DARK.PRIMARY, + }, + }, + { + id: 'classic-light', + title: window.i18n('classicLightThemeTitle'), + style: { + 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: 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: THEMES.OCEAN_LIGHT.COLOR7!, + border: THEMES.OCEAN_LIGHT.COLOR3, + receivedBackground: THEMES.OCEAN_LIGHT.COLOR1, + sentBackground: THEMES.OCEAN_LIGHT.PRIMARY, + }, + }, +]; + export { COLORS, THEMES }; diff --git a/ts/themes/switchPrimaryColor.tsx b/ts/themes/switchPrimaryColor.tsx index 14b0f7aab..5f74004c9 100644 --- a/ts/themes/switchPrimaryColor.tsx +++ b/ts/themes/switchPrimaryColor.tsx @@ -1,8 +1,17 @@ +import { find } from 'lodash'; import { Dispatch } from 'redux'; import { applyPrimaryColor } from '../state/ducks/primaryColor'; -import { COLORS, PrimaryColorStateType } from './constants/colors'; +import { COLORS, getPrimaryColors, PrimaryColorStateType } from './constants/colors'; -export async function switchPrimaryColor(color: PrimaryColorStateType, dispatch: Dispatch | null) { +export function findPrimaryColorId(hexCode: string): PrimaryColorStateType | undefined { + const primaryColors = getPrimaryColors(); + return find(primaryColors, { color: hexCode })?.id; +} + +export async function switchPrimaryColorTo( + color: PrimaryColorStateType, + dispatch: Dispatch | null +) { await window.Events.setPrimaryColorSetting(color); document.documentElement.style.setProperty( diff --git a/ts/themes/switchTheme.tsx b/ts/themes/switchTheme.tsx index 64cbfce66..118ec5df4 100644 --- a/ts/themes/switchTheme.tsx +++ b/ts/themes/switchTheme.tsx @@ -1,19 +1,20 @@ import { Dispatch } from 'redux'; import { applyTheme } from '../state/ducks/theme'; import { classicDark, classicLight, oceanDark, oceanLight } from '.'; -import { ThemeStateType } from './constants/colors'; +import { convertThemeStateToName, THEMES, ThemeStateType } from './constants/colors'; import { switchHtmlToDarkTheme, switchHtmlToLightTheme } from './SessionTheme'; import { loadThemeColors } from './variableColors'; +import { findPrimaryColorId, switchPrimaryColorTo } from './switchPrimaryColor'; -export async function switchThemeTo( - theme: ThemeStateType, - dispatch: Dispatch | null, - mainWindow: boolean = true -) { - if (mainWindow) { - await window.setTheme(theme); - } +type SwitchThemeProps = { + theme: ThemeStateType; + mainWindow: boolean; + resetPrimaryColor: boolean; + dispatch?: Dispatch; +}; +export async function switchThemeTo(props: SwitchThemeProps) { + const { theme, mainWindow = true, resetPrimaryColor = true, dispatch } = props; let newTheme: ThemeStateType | null = null; switch (theme) { @@ -41,7 +42,21 @@ export async function switchThemeTo( window.log.warn('Unsupported theme: ', theme); } - if (dispatch && newTheme) { - dispatch(applyTheme(newTheme)); + if (newTheme) { + if (mainWindow) { + await window.setTheme(theme); + } + + if (dispatch) { + dispatch(applyTheme(newTheme)); + if (resetPrimaryColor) { + const defaultPrimaryColor = findPrimaryColorId( + THEMES[convertThemeStateToName(newTheme)].PRIMARY + ); + if (defaultPrimaryColor) { + await switchPrimaryColorTo(defaultPrimaryColor, dispatch); + } + } + } } }