Middle Column: Custom background should be memorized related to a theme (#1042)

This commit is contained in:
Alexander Zinchuk 2021-06-11 01:19:11 +03:00
parent b2242f7fe4
commit e5dc1f485b
15 changed files with 196 additions and 99 deletions

View File

@ -30,7 +30,7 @@ type OwnProps = {
type StateProps = Pick<GlobalState, 'uiReadyState'> & {
hasCustomBackground?: boolean;
isCustomBackgroundColor: boolean;
hasCustomBackgroundColor: boolean;
isRightColumnShown?: boolean;
};
@ -80,7 +80,7 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
page,
children,
hasCustomBackground,
isCustomBackgroundColor,
hasCustomBackgroundColor,
isRightColumnShown,
setIsUiReady,
}) => {
@ -134,8 +134,8 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
<div
className={buildClassName(
'middle',
hasCustomBackground && !isCustomBackgroundColor && 'custom-bg-image',
hasCustomBackground && isCustomBackgroundColor && 'custom-bg-color',
hasCustomBackground && 'custom-bg-image',
hasCustomBackgroundColor && 'custom-bg-color',
isRightColumnShown && 'with-right-column',
)}
/>
@ -152,10 +152,13 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
export default withGlobal<OwnProps>(
(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),
};
},

View File

@ -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<OwnProps & StateProps & DispatchProps> = ({
const handleDarkModeToggle = useCallback((e: React.SyntheticEvent<HTMLDivElement>) => {
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]);

View File

@ -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<GlobalActions, 'setSettingOption' | 'loadWallpapers' | 'uploadWallpaper'>;
type DispatchProps = Pick<GlobalActions, (
'loadWallpapers' | 'uploadWallpaper' | 'setThemeSettings'
)>;
const SUPPORTED_TYPES = 'image/jpeg';
@ -39,13 +42,16 @@ const runThrottled = throttle((cb) => cb(), 60000, true);
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
onScreenSelect,
customBackground,
isBackgroundBlurred,
background,
isBlurred,
loadedWallpapers,
setSettingOption,
theme,
loadWallpapers,
uploadWallpaper,
setThemeSettings,
}) => {
const themeRef = useRef<string>();
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<OwnProps & StateProps & DispatchProps> = ({
}, [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<HTMLInputElement>) => {
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<OwnProps & StateProps & DispatchProps> = ({
<Checkbox
label={lang('BackgroundBlurred')}
checked={Boolean(isBackgroundBlurred)}
checked={Boolean(isBlurred)}
onChange={handleWallPaperBlurChange}
/>
</div>
@ -129,7 +143,8 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
{loadedWallpapers.map((wallpaper) => (
<WallpaperTile
wallpaper={wallpaper}
isSelected={customBackground === wallpaper.slug}
theme={theme}
isSelected={background === wallpaper.slug}
onClick={handleWallPaperSelect}
/>
))}
@ -143,16 +158,18 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
export default memo(withGlobal<OwnProps>(
(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));

View File

@ -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<GlobalActions, 'setSettingOption'>;
type DispatchProps = Pick<GlobalActions, 'setThemeSettings'>;
interface CanvasRects {
colorRect: {
@ -49,9 +50,12 @@ const PREDEFINED_COLORS = [
];
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
customBackground,
setSettingOption,
theme,
backgroundColor,
setThemeSettings,
}) => {
const themeRef = useRef<string>();
themeRef.current = theme;
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
@ -60,7 +64,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
const huePickerRef = useRef<HTMLDivElement>(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<OwnProps & StateProps & DispatchProps> = ({
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<OwnProps & StateProps & DispatchProps> = ({
);
};
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<OwnProps>(
(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));

View File

@ -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<OwnProps> = ({
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<OwnProps> = ({
wasDownloadDisabled,
'slow',
);
// To prevent triggering of the effect for useCallback
const cacheKeyRef = useRef<string>();
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]);

View File

@ -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 {

View File

@ -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<StateProps & DispatchProps> = ({
hasPinnedOrAudioMessage,
pinnedMessagesCount,
customBackground,
theme,
backgroundColor,
patternColor,
isCustomBackgroundColor,
isRightColumnShown,
isBackgroundBlurred,
isMobileSearchActive,
@ -173,12 +178,12 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
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<StateProps & DispatchProps> = ({
--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)};
`}
>
<div
@ -318,16 +325,19 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
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)),

View File

@ -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)';

View File

@ -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: {},
};

View File

@ -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: {},
},

View File

@ -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<Record<ThemeKey, IThemeSettings>>;
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
notifyExceptions?: Record<number, NotifyException>;
};
@ -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' |

View File

@ -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;
};

View File

@ -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<ISettings>) => {
return replaceSettings(global, payload);
});
addReducer('setThemeSettings', (global, actions, payload: { theme: ThemeKey } & Partial<IThemeSettings>) => {
const { theme, ...settings } = payload;
return replaceThemeSettings(global, theme, settings);
});

View File

@ -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<ISettings>): GlobalState {
return {
@ -14,6 +16,24 @@ export function replaceSettings(global: GlobalState, newSettings?: Partial<ISett
};
}
export function replaceThemeSettings(
global: GlobalState, theme: ThemeKey, newSettings?: Partial<IThemeSettings>,
): 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 {

View File

@ -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<string, any> {
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;