mirror of
https://github.com/danog/telegram-tt.git
synced 2025-01-21 21:01:29 +01:00
Middle Column: Custom background should be memorized related to a theme (#1042)
This commit is contained in:
parent
b2242f7fe4
commit
e5dc1f485b
@ -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),
|
||||
};
|
||||
},
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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]);
|
||||
|
@ -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 {
|
||||
|
@ -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)),
|
||||
|
@ -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)';
|
||||
|
@ -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: {},
|
||||
};
|
||||
|
@ -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: {},
|
||||
},
|
||||
|
@ -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' |
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user