From e5dc1f485bf6f3b026831c2b83187a5c0b248a9d Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 11 Jun 2021 01:19:11 +0300 Subject: [PATCH] Middle Column: Custom background should be memorized related to a theme (#1042) --- src/components/common/UiLoader.tsx | 15 +++-- src/components/left/main/LeftMainHeader.tsx | 11 +--- .../settings/SettingsGeneralBackground.tsx | 63 ++++++++++++------- .../SettingsGeneralBackgroundColor.tsx | 40 +++++++----- .../left/settings/WallpaperTile.tsx | 12 ++-- src/components/middle/MiddleColumn.scss | 32 +++++----- src/components/middle/MiddleColumn.tsx | 26 +++++--- src/config.ts | 1 + src/global/cache.ts | 7 ++- src/global/initial.ts | 16 ++++- src/global/types.ts | 5 +- src/hooks/useCustomBackground.ts | 22 ++++--- src/modules/actions/ui/settings.ts | 10 ++- src/modules/reducers/settings.ts | 22 ++++++- src/types/index.ts | 13 ++-- 15 files changed, 196 insertions(+), 99 deletions(-) diff --git a/src/components/common/UiLoader.tsx b/src/components/common/UiLoader.tsx index f42cd80f..da035045 100644 --- a/src/components/common/UiLoader.tsx +++ b/src/components/common/UiLoader.tsx @@ -30,7 +30,7 @@ type OwnProps = { type StateProps = Pick & { hasCustomBackground?: boolean; - isCustomBackgroundColor: boolean; + hasCustomBackgroundColor: boolean; isRightColumnShown?: boolean; }; @@ -80,7 +80,7 @@ const UiLoader: FC = ({ page, children, hasCustomBackground, - isCustomBackgroundColor, + hasCustomBackgroundColor, isRightColumnShown, setIsUiReady, }) => { @@ -134,8 +134,8 @@ const UiLoader: FC = ({
@@ -152,10 +152,13 @@ const UiLoader: FC = ({ export default withGlobal( (global): StateProps => { + const { theme } = global.settings.byKey; + const { background, backgroundColor } = global.settings.themes[theme] || {}; + return { uiReadyState: global.uiReadyState, - hasCustomBackground: Boolean(global.settings.byKey.customBackground), - isCustomBackgroundColor: Boolean((global.settings.byKey.customBackground || '').match(/^#[a-f\d]{6,8}$/i)), + hasCustomBackground: Boolean(background), + hasCustomBackgroundColor: Boolean(backgroundColor), isRightColumnShown: selectIsRightColumnShown(global), }; }, diff --git a/src/components/left/main/LeftMainHeader.tsx b/src/components/left/main/LeftMainHeader.tsx index 526d2ef0..22167384 100644 --- a/src/components/left/main/LeftMainHeader.tsx +++ b/src/components/left/main/LeftMainHeader.tsx @@ -7,9 +7,7 @@ import { GlobalActions } from '../../../global/types'; import { LeftColumnContent, ISettings } from '../../../types'; import { ApiChat } from '../../../api/types'; -import { - APP_INFO, DEFAULT_PATTERN_COLOR, FEEDBACK_URL, DARK_THEME_BG_COLOR, DARK_THEME_PATTERN_COLOR, -} from '../../../config'; +import { APP_INFO, FEEDBACK_URL } from '../../../config'; import { IS_MOBILE_SCREEN } from '../../../util/environment'; import buildClassName from '../../../util/buildClassName'; import { pick } from '../../../util/iteratees'; @@ -128,13 +126,8 @@ const LeftMainHeader: FC = ({ const handleDarkModeToggle = useCallback((e: React.SyntheticEvent) => { e.stopPropagation(); const newTheme = theme === 'light' ? 'dark' : 'light'; - const isNewThemeDark = newTheme === 'dark'; - setSettingOption({ - theme: newTheme, - customBackground: isNewThemeDark ? DARK_THEME_BG_COLOR : undefined, - patternColor: isNewThemeDark ? DARK_THEME_PATTERN_COLOR : DEFAULT_PATTERN_COLOR, - }); + setSettingOption({ theme: newTheme }); switchTheme(newTheme, animationLevel > 0); }, [animationLevel, setSettingOption, theme]); diff --git a/src/components/left/settings/SettingsGeneralBackground.tsx b/src/components/left/settings/SettingsGeneralBackground.tsx index 5b08687b..ed6b7216 100644 --- a/src/components/left/settings/SettingsGeneralBackground.tsx +++ b/src/components/left/settings/SettingsGeneralBackground.tsx @@ -1,17 +1,17 @@ import React, { - FC, memo, useEffect, useCallback, + FC, memo, useEffect, useCallback, useRef, } from '../../../lib/teact/teact'; import { withGlobal } from '../../../lib/teact/teactn'; import { GlobalActions } from '../../../global/types'; -import { SettingsScreens, UPLOADING_WALLPAPER_SLUG } from '../../../types'; +import { SettingsScreens, ThemeKey, UPLOADING_WALLPAPER_SLUG } from '../../../types'; import { ApiWallpaper } from '../../../api/types'; -import { DEFAULT_PATTERN_COLOR } from '../../../config'; +import { DARK_THEME_PATTERN_COLOR, DEFAULT_PATTERN_COLOR } from '../../../config'; import { pick } from '../../../util/iteratees'; import { throttle } from '../../../util/schedulers'; import { openSystemFilesDialog } from '../../../util/systemFilesDialog'; -import { getAverageColor, getPatternColor } from '../../../util/colors'; +import { getAverageColor, getPatternColor, rgb2hex } from '../../../util/colors'; import useLang from '../../../hooks/useLang'; import ListItem from '../../ui/ListItem'; @@ -26,12 +26,15 @@ type OwnProps = { }; type StateProps = { - customBackground?: string; - isBackgroundBlurred?: boolean; + background?: string; + isBlurred?: boolean; loadedWallpapers?: ApiWallpaper[]; + theme: ThemeKey; }; -type DispatchProps = Pick; +type DispatchProps = Pick; const SUPPORTED_TYPES = 'image/jpeg'; @@ -39,13 +42,16 @@ const runThrottled = throttle((cb) => cb(), 60000, true); const SettingsGeneralBackground: FC = ({ onScreenSelect, - customBackground, - isBackgroundBlurred, + background, + isBlurred, loadedWallpapers, - setSettingOption, + theme, loadWallpapers, uploadWallpaper, + setThemeSettings, }) => { + const themeRef = useRef(); + themeRef.current = theme; // Due to the parent Transition, this component never gets unmounted, // that's why we use throttled API call on every update. useEffect(() => { @@ -71,23 +77,31 @@ const SettingsGeneralBackground: FC = ({ }, [onScreenSelect]); const handleResetToDefault = useCallback(() => { - setSettingOption({ customBackground: undefined, patternColor: DEFAULT_PATTERN_COLOR }); - }, [setSettingOption]); + setThemeSettings({ + theme, + background: undefined, + backgroundColor: undefined, + isBlurred: true, + patternColor: theme === 'dark' ? DARK_THEME_PATTERN_COLOR : DEFAULT_PATTERN_COLOR, + }); + }, [setThemeSettings, theme]); const handleWallPaperSelect = useCallback((slug: string) => { - setSettingOption({ customBackground: slug }); + setThemeSettings({ theme: themeRef.current, background: slug }); const currentWallpaper = loadedWallpapers && loadedWallpapers.find((wallpaper) => wallpaper.slug === slug); if (currentWallpaper && currentWallpaper.document.thumbnail) { getAverageColor(currentWallpaper.document.thumbnail.dataUri) .then((color) => { - setSettingOption({ patternColor: getPatternColor(color) }); + const patternColor = getPatternColor(color); + const rgbColor = `#${rgb2hex(color)}`; + setThemeSettings({ theme: themeRef.current, backgroundColor: rgbColor, patternColor }); }); } - }, [loadedWallpapers, setSettingOption]); + }, [loadedWallpapers, setThemeSettings]); const handleWallPaperBlurChange = useCallback((e: React.ChangeEvent) => { - setSettingOption({ isBackgroundBlurred: e.target.checked }); - }, [setSettingOption]); + setThemeSettings({ theme: themeRef.current, isBlurred: e.target.checked }); + }, [setThemeSettings]); const lang = useLang(); @@ -119,7 +133,7 @@ const SettingsGeneralBackground: FC = ({
@@ -129,7 +143,8 @@ const SettingsGeneralBackground: FC = ({ {loadedWallpapers.map((wallpaper) => ( ))} @@ -143,16 +158,18 @@ const SettingsGeneralBackground: FC = ({ export default memo(withGlobal( (global): StateProps => { - const { isBackgroundBlurred, customBackground } = global.settings.byKey; + const { theme } = global.settings.byKey; + const { background, isBlurred } = global.settings.themes[theme] || {}; const { loadedWallpapers } = global.settings; return { - customBackground, - isBackgroundBlurred, + background, + isBlurred, loadedWallpapers, + theme, }; }, (setGlobal, actions): DispatchProps => pick(actions, [ - 'setSettingOption', 'loadWallpapers', 'uploadWallpaper', + 'loadWallpapers', 'uploadWallpaper', 'setThemeSettings', ]), )(SettingsGeneralBackground)); diff --git a/src/components/left/settings/SettingsGeneralBackgroundColor.tsx b/src/components/left/settings/SettingsGeneralBackgroundColor.tsx index 2f34fc15..e5d3ff34 100644 --- a/src/components/left/settings/SettingsGeneralBackgroundColor.tsx +++ b/src/components/left/settings/SettingsGeneralBackgroundColor.tsx @@ -5,7 +5,7 @@ import React, { import { withGlobal } from '../../../lib/teact/teactn'; import { GlobalActions } from '../../../global/types'; -import { SettingsScreens } from '../../../types'; +import { SettingsScreens, ThemeKey } from '../../../types'; import { pick } from '../../../util/iteratees'; import { @@ -24,10 +24,11 @@ type OwnProps = { }; type StateProps = { - customBackground?: string; + backgroundColor?: string; + theme: ThemeKey; }; -type DispatchProps = Pick; +type DispatchProps = Pick; interface CanvasRects { colorRect: { @@ -49,9 +50,12 @@ const PREDEFINED_COLORS = [ ]; const SettingsGeneralBackground: FC = ({ - customBackground, - setSettingOption, + theme, + backgroundColor, + setThemeSettings, }) => { + const themeRef = useRef(); + themeRef.current = theme; // eslint-disable-next-line no-null/no-null const containerRef = useRef(null); // eslint-disable-next-line no-null/no-null @@ -60,7 +64,7 @@ const SettingsGeneralBackground: FC = ({ const huePickerRef = useRef(null); const isFirstRunRef = useRef(true); - const [hsb, setHsb] = useState(getInitialHsb(customBackground)); + const [hsb, setHsb] = useState(getInitialHsb(backgroundColor)); // Cache for drag handlers const hsbRef = useRef(hsb); useEffect(() => { @@ -139,13 +143,16 @@ const SettingsGeneralBackground: FC = ({ setHexInput(color); if (!isFirstRunRef.current) { - setSettingOption({ - customBackground: color, - patternColor: getPatternColor(rgb), + const patternColor = getPatternColor(rgb); + setThemeSettings({ + theme: themeRef.current, + background: undefined, + backgroundColor: color, + patternColor, }); } isFirstRunRef.current = false; - }, [hsb, setSettingOption]); + }, [hsb, setThemeSettings]); // Redraw color picker when hue changes useEffect(() => { @@ -226,9 +233,9 @@ const SettingsGeneralBackground: FC = ({ ); }; -function getInitialHsb(customBackground?: string) { - return customBackground && customBackground.startsWith('#') - ? rgb2hsb(hex2rgb(customBackground.replace('#', ''))) +function getInitialHsb(backgroundColor?: string) { + return backgroundColor && backgroundColor.startsWith('#') + ? rgb2hsb(hex2rgb(backgroundColor.replace('#', ''))) : DEFAULT_HSB; } @@ -329,9 +336,12 @@ function drawHue(canvas: HTMLCanvasElement) { export default memo(withGlobal( (global): StateProps => { + const { theme } = global.settings.byKey; + const { backgroundColor } = global.settings.themes[theme] || {}; return { - customBackground: global.settings.byKey.customBackground, + backgroundColor, + theme, }; }, - (setGlobal, actions): DispatchProps => pick(actions, ['setSettingOption']), + (setGlobal, actions): DispatchProps => pick(actions, ['setThemeSettings']), )(SettingsGeneralBackground)); diff --git a/src/components/left/settings/WallpaperTile.tsx b/src/components/left/settings/WallpaperTile.tsx index d517a98d..fafabebb 100644 --- a/src/components/left/settings/WallpaperTile.tsx +++ b/src/components/left/settings/WallpaperTile.tsx @@ -1,8 +1,8 @@ import React, { - FC, memo, useCallback, useEffect, useState, + FC, memo, useCallback, useEffect, useState, useRef, } from '../../../lib/teact/teact'; import { ApiWallpaper } from '../../../api/types'; -import { UPLOADING_WALLPAPER_SLUG } from '../../../types'; +import { ThemeKey, UPLOADING_WALLPAPER_SLUG } from '../../../types'; import { CUSTOM_BG_CACHE_NAME } from '../../../config'; import * as cacheApi from '../../../util/cacheApi'; @@ -21,6 +21,7 @@ import './WallpaperTile.scss'; type OwnProps = { wallpaper: ApiWallpaper; + theme: ThemeKey; isSelected: boolean; onClick: (slug: string) => void; }; @@ -29,11 +30,11 @@ const ANIMATION_DURATION = 300; const WallpaperTile: FC = ({ wallpaper, + theme, isSelected, onClick, }) => { const { slug, document } = wallpaper; - const localMediaHash = `wallpaper${document.id!}`; const localBlobUrl = document.previewBlobUrl; const previewBlobUrl = useMedia(`${localMediaHash}?size=m`); @@ -56,11 +57,14 @@ const WallpaperTile: FC = ({ wasDownloadDisabled, 'slow', ); + // To prevent triggering of the effect for useCallback + const cacheKeyRef = useRef(); + cacheKeyRef.current = theme; const handleSelect = useCallback(() => { (async () => { const blob = await fetchBlob(fullMedia!); - await cacheApi.save(CUSTOM_BG_CACHE_NAME, CUSTOM_BG_CACHE_NAME, blob); + await cacheApi.save(CUSTOM_BG_CACHE_NAME, cacheKeyRef.current!, blob); onClick(slug); })(); }, [fullMedia, onClick, slug]); diff --git a/src/components/middle/MiddleColumn.scss b/src/components/middle/MiddleColumn.scss index e9ee46bc..e9d01a97 100644 --- a/src/components/middle/MiddleColumn.scss +++ b/src/components/middle/MiddleColumn.scss @@ -16,11 +16,18 @@ left: 0; bottom: 0; right: 0; - background-color: #A2AF8E; + background-color: var(--theme-background-color); } &::after { - background-image: url('../../assets/chat-bg.jpg'); + .theme-light & { + background-image: url('../../assets/chat-bg.jpg'); + + @media (max-width: 600px) { + background-image: url('../../assets/chat-bg-mobile.jpg'); + } + } + background-position: center; background-repeat: no-repeat; background-size: cover; @@ -32,10 +39,15 @@ body.animation-level-0 & { transition: none; } + } - @media (max-width: 600px) { - background-image: url('../../assets/chat-bg-mobile.jpg'); - } + .custom-bg-color > &::before { + filter: blur(0); + transform: scale(1.1); + } + + .custom-bg-color:not(.custom-bg-image) > &::after { + opacity: 0; } .custom-bg-image > &::after { @@ -44,20 +56,10 @@ transform: scale(1.1); } - .custom-bg-color > &::before { - background-color: var(--custom-background) !important; - filter: blur(0); - transform: scale(1.1); - } - .custom-bg-image.blurred > &::after { filter: blur(12px); } - .custom-bg-color > &::after { - opacity: 0; - } - @media screen and (min-width: 1276px) { body.animation-level-2 &::before, body.animation-level-2 &::after { diff --git a/src/components/middle/MiddleColumn.tsx b/src/components/middle/MiddleColumn.tsx index db7fd541..93dd1d89 100644 --- a/src/components/middle/MiddleColumn.tsx +++ b/src/components/middle/MiddleColumn.tsx @@ -5,6 +5,7 @@ import { withGlobal } from '../../lib/teact/teactn'; import { MAIN_THREAD_ID } from '../../api/types'; import { GlobalActions, MessageListType } from '../../global/types'; +import { ThemeKey } from '../../types'; import { MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN, @@ -15,6 +16,8 @@ import { CONTENT_TYPES_FOR_QUICK_UPLOAD, ANIMATION_LEVEL_MAX, ANIMATION_END_DELAY, + DARK_THEME_BG_COLOR, + LIGHT_THEME_BG_COLOR, } from '../../config'; import { IS_MOBILE_SCREEN, IS_TOUCH_ENV, MASK_IMAGE_DISABLED } from '../../util/environment'; import { DropAreaState } from './composer/DropArea'; @@ -59,9 +62,10 @@ type StateProps = { messageSendingRestrictionReason?: string; hasPinnedOrAudioMessage?: boolean; pinnedMessagesCount?: number; + theme: ThemeKey; customBackground?: string; + backgroundColor?: string; patternColor?: string; - isCustomBackgroundColor?: boolean; isRightColumnShown?: boolean; isBackgroundBlurred?: boolean; isMobileSearchActive?: boolean; @@ -88,8 +92,9 @@ const MiddleColumn: FC = ({ hasPinnedOrAudioMessage, pinnedMessagesCount, customBackground, + theme, + backgroundColor, patternColor, - isCustomBackgroundColor, isRightColumnShown, isBackgroundBlurred, isMobileSearchActive, @@ -173,12 +178,12 @@ const MiddleColumn: FC = ({ openChat({ id: chatId }); }, [unpinAllMessages, openChat, closeUnpinModal, chatId]); - const customBackgroundValue = useCustomBackground(customBackground); + const customBackgroundValue = useCustomBackground(theme, customBackground); const className = buildClassName( renderingHasTools && 'has-header-tools', - customBackground && !isCustomBackgroundColor && 'custom-bg-image', - customBackground && isCustomBackgroundColor && 'custom-bg-color', + customBackground && 'custom-bg-image', + backgroundColor && 'custom-bg-color', customBackground && isBackgroundBlurred && 'blurred', MASK_IMAGE_DISABLED ? 'mask-image-disabled' : 'mask-image-enabled', ); @@ -219,6 +224,8 @@ const MiddleColumn: FC = ({ --composer-translate-x: ${composerTranslateX}px; --toolbar-translate-x: ${toolbarTranslateX}px; --pattern-color: ${patternColor}; + --theme-background-color: + ${backgroundColor || (theme === 'dark' ? DARK_THEME_BG_COLOR : LIGHT_THEME_BG_COLOR)}; `} >
= ({ export default memo(withGlobal( (global): StateProps => { - const { isBackgroundBlurred, customBackground, patternColor } = global.settings.byKey; + const { theme } = global.settings.byKey; + const { + isBlurred: isBackgroundBlurred, background: customBackground, backgroundColor, patternColor, + } = global.settings.themes[theme] || {}; - const isCustomBackgroundColor = Boolean((customBackground || '').match(/^#[a-f\d]{6,8}$/i)); const currentMessageList = selectCurrentMessageList(global); const { chats: { listIds } } = global; const state: StateProps = { + theme, customBackground, + backgroundColor, patternColor, - isCustomBackgroundColor, isRightColumnShown: selectIsRightColumnShown(global), isBackgroundBlurred, isMobileSearchActive: Boolean(IS_MOBILE_SCREEN && selectCurrentTextSearch(global)), diff --git a/src/config.ts b/src/config.ts index d38d3197..ad1fd39f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -127,6 +127,7 @@ export const DEFAULT_LANG_PACK = 'android'; export const LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos']; export const TIPS_USERNAME = 'TelegramTips'; export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time'; +export const LIGHT_THEME_BG_COLOR = '#A2AF8E'; export const DARK_THEME_BG_COLOR = '#0F0F0F'; export const DARK_THEME_PATTERN_COLOR = '#0a0a0a8c'; export const DEFAULT_PATTERN_COLOR = 'rgba(90, 110, 70, 0.6)'; diff --git a/src/global/cache.ts b/src/global/cache.ts index 89e44ab6..573c2405 100644 --- a/src/global/cache.ts +++ b/src/global/cache.ts @@ -77,6 +77,10 @@ function readCache(initialState: GlobalState) { ...initialState.settings.byKey, ...cached.settings.byKey, }; + cached.settings.themes = { + ...initialState.settings.themes, + ...cached.settings.themes, + }; } return { @@ -204,10 +208,11 @@ function reduceMessages(global: GlobalState): GlobalState['messages'] { } function reduceSettings(global: GlobalState): GlobalState['settings'] { - const { byKey } = global.settings; + const { byKey, themes } = global.settings; return { byKey, + themes, privacy: {}, notifyExceptions: {}, }; diff --git a/src/global/initial.ts b/src/global/initial.ts index 5b008dcc..9e518419 100644 --- a/src/global/initial.ts +++ b/src/global/initial.ts @@ -1,6 +1,8 @@ import { GlobalState } from './types'; -import { ANIMATION_LEVEL_DEFAULT, DEFAULT_MESSAGE_TEXT_SIZE_PX, DEFAULT_PATTERN_COLOR } from '../config'; +import { + ANIMATION_LEVEL_DEFAULT, DARK_THEME_PATTERN_COLOR, DEFAULT_MESSAGE_TEXT_SIZE_PX, DEFAULT_PATTERN_COLOR, +} from '../config'; export const INITIAL_STATE: GlobalState = { isLeftColumnShown: true, @@ -100,8 +102,6 @@ export const INITIAL_STATE: GlobalState = { settings: { byKey: { messageTextSize: DEFAULT_MESSAGE_TEXT_SIZE_PX, - isBackgroundBlurred: true, - patternColor: DEFAULT_PATTERN_COLOR, animationLevel: ANIMATION_LEVEL_DEFAULT, messageSendKeyCombo: 'enter', theme: 'light', @@ -115,6 +115,16 @@ export const INITIAL_STATE: GlobalState = { shouldLoopStickers: true, language: 'en', }, + themes: { + light: { + isBlurred: true, + patternColor: DEFAULT_PATTERN_COLOR, + }, + dark: { + isBlurred: true, + patternColor: DARK_THEME_PATTERN_COLOR, + }, + }, privacy: {}, notifyExceptions: {}, }, diff --git a/src/global/types.ts b/src/global/types.ts index a6fc2720..86fb7f31 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -34,6 +34,8 @@ import { Receipt, ApiPrivacyKey, ApiPrivacySettings, + ThemeKey, + IThemeSettings, NotifyException, } from '../types'; @@ -365,6 +367,7 @@ export type GlobalState = { settings: { byKey: ISettings; loadedWallpapers?: ApiWallpaper[]; + themes: Partial>; privacy: Partial>; notifyExceptions?: Record; }; @@ -438,7 +441,7 @@ export type ActionTypes = ( 'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations' | 'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' | 'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' | - 'loadNotificationExceptions' | + 'loadNotificationExceptions' | 'setThemeSettings' | // Stickers & GIFs 'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' | 'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' | diff --git a/src/hooks/useCustomBackground.ts b/src/hooks/useCustomBackground.ts index 0848821e..f3e8eb6b 100644 --- a/src/hooks/useCustomBackground.ts +++ b/src/hooks/useCustomBackground.ts @@ -1,8 +1,12 @@ -import { CUSTOM_BG_CACHE_NAME } from '../config'; -import * as cacheApi from '../util/cacheApi'; import { useEffect, useState } from '../lib/teact/teact'; -export default (settingValue?: string) => { +import { ThemeKey } from '../types'; + +import { CUSTOM_BG_CACHE_NAME } from '../config'; +import * as cacheApi from '../util/cacheApi'; +import { preloadImage } from '../util/files'; + +export default (theme: ThemeKey, settingValue?: string) => { const [value, setValue] = useState(settingValue); useEffect(() => { @@ -13,12 +17,16 @@ export default (settingValue?: string) => { if (settingValue.startsWith('#')) { setValue(settingValue); } else { - cacheApi.fetch(CUSTOM_BG_CACHE_NAME, CUSTOM_BG_CACHE_NAME, cacheApi.Type.Blob) + cacheApi.fetch(CUSTOM_BG_CACHE_NAME, theme, cacheApi.Type.Blob) .then((blob) => { - setValue(`url(${URL.createObjectURL(blob)}`); + const url = URL.createObjectURL(blob); + preloadImage(url) + .then(() => { + setValue(`url(${url})`); + }); }); } - }, [settingValue]); + }, [settingValue, theme]); - return value; + return settingValue ? value : undefined; }; diff --git a/src/modules/actions/ui/settings.ts b/src/modules/actions/ui/settings.ts index 328e7978..862cf938 100644 --- a/src/modules/actions/ui/settings.ts +++ b/src/modules/actions/ui/settings.ts @@ -1,7 +1,13 @@ import { addReducer } from '../../../lib/teact/teactn'; -import { ISettings } from '../../../types'; -import { replaceSettings } from '../../reducers'; +import { ISettings, IThemeSettings, ThemeKey } from '../../../types'; +import { replaceSettings, replaceThemeSettings } from '../../reducers'; addReducer('setSettingOption', (global, actions, payload?: Partial) => { return replaceSettings(global, payload); }); + +addReducer('setThemeSettings', (global, actions, payload: { theme: ThemeKey } & Partial) => { + const { theme, ...settings } = payload; + + return replaceThemeSettings(global, theme, settings); +}); diff --git a/src/modules/reducers/settings.ts b/src/modules/reducers/settings.ts index 82e13e8a..86f6f76e 100644 --- a/src/modules/reducers/settings.ts +++ b/src/modules/reducers/settings.ts @@ -1,5 +1,7 @@ import { GlobalState } from '../../global/types'; -import { ISettings, NotifyException } from '../../types'; +import { + ISettings, IThemeSettings, ThemeKey, NotifyException, +} from '../../types'; export function replaceSettings(global: GlobalState, newSettings?: Partial): GlobalState { return { @@ -14,6 +16,24 @@ export function replaceSettings(global: GlobalState, newSettings?: Partial, +): GlobalState { + return { + ...global, + settings: { + ...global.settings, + themes: { + ...global.settings.themes, + [theme]: { + ...(global.settings.themes[theme] || {}), + ...newSettings, + }, + }, + }, + }; +} + export function addNotifyException( global: GlobalState, id: number, notifyException: NotifyException, ): GlobalState { diff --git a/src/types/index.ts b/src/types/index.ts index cc64ebaa..f8ec7779 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -20,6 +20,14 @@ export interface IAlbum { mainMessage: ApiMessage; } +export type ThemeKey = 'light' | 'dark'; +export interface IThemeSettings { + background?: string; + backgroundColor?: string; + patternColor?: string; + isBlurred?: boolean; +} + export type NotifySettings = { hasPrivateChatsNotifications?: boolean; hasPrivateChatsMessagePreview?: boolean; @@ -31,13 +39,10 @@ export type NotifySettings = { }; export interface ISettings extends NotifySettings, Record { + theme: ThemeKey; messageTextSize: number; - customBackground?: string; - patternColor?: string; - isBackgroundBlurred?: boolean; animationLevel: 0 | 1 | 2; messageSendKeyCombo: 'enter' | 'ctrl-enter'; - theme: 'light' | 'dark'; shouldAutoDownloadMediaFromContacts: boolean; shouldAutoDownloadMediaInPrivateChats: boolean; shouldAutoDownloadMediaInGroups: boolean;