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'> & {
|
type StateProps = Pick<GlobalState, 'uiReadyState'> & {
|
||||||
hasCustomBackground?: boolean;
|
hasCustomBackground?: boolean;
|
||||||
isCustomBackgroundColor: boolean;
|
hasCustomBackgroundColor: boolean;
|
||||||
isRightColumnShown?: boolean;
|
isRightColumnShown?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
page,
|
page,
|
||||||
children,
|
children,
|
||||||
hasCustomBackground,
|
hasCustomBackground,
|
||||||
isCustomBackgroundColor,
|
hasCustomBackgroundColor,
|
||||||
isRightColumnShown,
|
isRightColumnShown,
|
||||||
setIsUiReady,
|
setIsUiReady,
|
||||||
}) => {
|
}) => {
|
||||||
@ -134,8 +134,8 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'middle',
|
'middle',
|
||||||
hasCustomBackground && !isCustomBackgroundColor && 'custom-bg-image',
|
hasCustomBackground && 'custom-bg-image',
|
||||||
hasCustomBackground && isCustomBackgroundColor && 'custom-bg-color',
|
hasCustomBackgroundColor && 'custom-bg-color',
|
||||||
isRightColumnShown && 'with-right-column',
|
isRightColumnShown && 'with-right-column',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -152,10 +152,13 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
export default withGlobal<OwnProps>(
|
export default withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
|
const { theme } = global.settings.byKey;
|
||||||
|
const { background, backgroundColor } = global.settings.themes[theme] || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uiReadyState: global.uiReadyState,
|
uiReadyState: global.uiReadyState,
|
||||||
hasCustomBackground: Boolean(global.settings.byKey.customBackground),
|
hasCustomBackground: Boolean(background),
|
||||||
isCustomBackgroundColor: Boolean((global.settings.byKey.customBackground || '').match(/^#[a-f\d]{6,8}$/i)),
|
hasCustomBackgroundColor: Boolean(backgroundColor),
|
||||||
isRightColumnShown: selectIsRightColumnShown(global),
|
isRightColumnShown: selectIsRightColumnShown(global),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -7,9 +7,7 @@ import { GlobalActions } from '../../../global/types';
|
|||||||
import { LeftColumnContent, ISettings } from '../../../types';
|
import { LeftColumnContent, ISettings } from '../../../types';
|
||||||
import { ApiChat } from '../../../api/types';
|
import { ApiChat } from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import { APP_INFO, FEEDBACK_URL } from '../../../config';
|
||||||
APP_INFO, DEFAULT_PATTERN_COLOR, FEEDBACK_URL, DARK_THEME_BG_COLOR, DARK_THEME_PATTERN_COLOR,
|
|
||||||
} from '../../../config';
|
|
||||||
import { IS_MOBILE_SCREEN } from '../../../util/environment';
|
import { IS_MOBILE_SCREEN } from '../../../util/environment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
@ -128,13 +126,8 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
const handleDarkModeToggle = useCallback((e: React.SyntheticEvent<HTMLDivElement>) => {
|
const handleDarkModeToggle = useCallback((e: React.SyntheticEvent<HTMLDivElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const newTheme = theme === 'light' ? 'dark' : 'light';
|
const newTheme = theme === 'light' ? 'dark' : 'light';
|
||||||
const isNewThemeDark = newTheme === 'dark';
|
|
||||||
|
|
||||||
setSettingOption({
|
setSettingOption({ theme: newTheme });
|
||||||
theme: newTheme,
|
|
||||||
customBackground: isNewThemeDark ? DARK_THEME_BG_COLOR : undefined,
|
|
||||||
patternColor: isNewThemeDark ? DARK_THEME_PATTERN_COLOR : DEFAULT_PATTERN_COLOR,
|
|
||||||
});
|
|
||||||
switchTheme(newTheme, animationLevel > 0);
|
switchTheme(newTheme, animationLevel > 0);
|
||||||
}, [animationLevel, setSettingOption, theme]);
|
}, [animationLevel, setSettingOption, theme]);
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useEffect, useCallback,
|
FC, memo, useEffect, useCallback, useRef,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { withGlobal } from '../../../lib/teact/teactn';
|
import { withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { GlobalActions } from '../../../global/types';
|
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 { 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 { pick } from '../../../util/iteratees';
|
||||||
import { throttle } from '../../../util/schedulers';
|
import { throttle } from '../../../util/schedulers';
|
||||||
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
||||||
import { getAverageColor, getPatternColor } from '../../../util/colors';
|
import { getAverageColor, getPatternColor, rgb2hex } from '../../../util/colors';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
@ -26,12 +26,15 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
customBackground?: string;
|
background?: string;
|
||||||
isBackgroundBlurred?: boolean;
|
isBlurred?: boolean;
|
||||||
loadedWallpapers?: ApiWallpaper[];
|
loadedWallpapers?: ApiWallpaper[];
|
||||||
|
theme: ThemeKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, 'setSettingOption' | 'loadWallpapers' | 'uploadWallpaper'>;
|
type DispatchProps = Pick<GlobalActions, (
|
||||||
|
'loadWallpapers' | 'uploadWallpaper' | 'setThemeSettings'
|
||||||
|
)>;
|
||||||
|
|
||||||
const SUPPORTED_TYPES = 'image/jpeg';
|
const SUPPORTED_TYPES = 'image/jpeg';
|
||||||
|
|
||||||
@ -39,13 +42,16 @@ const runThrottled = throttle((cb) => cb(), 60000, true);
|
|||||||
|
|
||||||
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
customBackground,
|
background,
|
||||||
isBackgroundBlurred,
|
isBlurred,
|
||||||
loadedWallpapers,
|
loadedWallpapers,
|
||||||
setSettingOption,
|
theme,
|
||||||
loadWallpapers,
|
loadWallpapers,
|
||||||
uploadWallpaper,
|
uploadWallpaper,
|
||||||
|
setThemeSettings,
|
||||||
}) => {
|
}) => {
|
||||||
|
const themeRef = useRef<string>();
|
||||||
|
themeRef.current = theme;
|
||||||
// Due to the parent Transition, this component never gets unmounted,
|
// Due to the parent Transition, this component never gets unmounted,
|
||||||
// that's why we use throttled API call on every update.
|
// that's why we use throttled API call on every update.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -71,23 +77,31 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
}, [onScreenSelect]);
|
}, [onScreenSelect]);
|
||||||
|
|
||||||
const handleResetToDefault = useCallback(() => {
|
const handleResetToDefault = useCallback(() => {
|
||||||
setSettingOption({ customBackground: undefined, patternColor: DEFAULT_PATTERN_COLOR });
|
setThemeSettings({
|
||||||
}, [setSettingOption]);
|
theme,
|
||||||
|
background: undefined,
|
||||||
|
backgroundColor: undefined,
|
||||||
|
isBlurred: true,
|
||||||
|
patternColor: theme === 'dark' ? DARK_THEME_PATTERN_COLOR : DEFAULT_PATTERN_COLOR,
|
||||||
|
});
|
||||||
|
}, [setThemeSettings, theme]);
|
||||||
|
|
||||||
const handleWallPaperSelect = useCallback((slug: string) => {
|
const handleWallPaperSelect = useCallback((slug: string) => {
|
||||||
setSettingOption({ customBackground: slug });
|
setThemeSettings({ theme: themeRef.current, background: slug });
|
||||||
const currentWallpaper = loadedWallpapers && loadedWallpapers.find((wallpaper) => wallpaper.slug === slug);
|
const currentWallpaper = loadedWallpapers && loadedWallpapers.find((wallpaper) => wallpaper.slug === slug);
|
||||||
if (currentWallpaper && currentWallpaper.document.thumbnail) {
|
if (currentWallpaper && currentWallpaper.document.thumbnail) {
|
||||||
getAverageColor(currentWallpaper.document.thumbnail.dataUri)
|
getAverageColor(currentWallpaper.document.thumbnail.dataUri)
|
||||||
.then((color) => {
|
.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>) => {
|
const handleWallPaperBlurChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setSettingOption({ isBackgroundBlurred: e.target.checked });
|
setThemeSettings({ theme: themeRef.current, isBlurred: e.target.checked });
|
||||||
}, [setSettingOption]);
|
}, [setThemeSettings]);
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
@ -119,7 +133,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('BackgroundBlurred')}
|
label={lang('BackgroundBlurred')}
|
||||||
checked={Boolean(isBackgroundBlurred)}
|
checked={Boolean(isBlurred)}
|
||||||
onChange={handleWallPaperBlurChange}
|
onChange={handleWallPaperBlurChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -129,7 +143,8 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
{loadedWallpapers.map((wallpaper) => (
|
{loadedWallpapers.map((wallpaper) => (
|
||||||
<WallpaperTile
|
<WallpaperTile
|
||||||
wallpaper={wallpaper}
|
wallpaper={wallpaper}
|
||||||
isSelected={customBackground === wallpaper.slug}
|
theme={theme}
|
||||||
|
isSelected={background === wallpaper.slug}
|
||||||
onClick={handleWallPaperSelect}
|
onClick={handleWallPaperSelect}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@ -143,16 +158,18 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const { isBackgroundBlurred, customBackground } = global.settings.byKey;
|
const { theme } = global.settings.byKey;
|
||||||
|
const { background, isBlurred } = global.settings.themes[theme] || {};
|
||||||
const { loadedWallpapers } = global.settings;
|
const { loadedWallpapers } = global.settings;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customBackground,
|
background,
|
||||||
isBackgroundBlurred,
|
isBlurred,
|
||||||
loadedWallpapers,
|
loadedWallpapers,
|
||||||
|
theme,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||||
'setSettingOption', 'loadWallpapers', 'uploadWallpaper',
|
'loadWallpapers', 'uploadWallpaper', 'setThemeSettings',
|
||||||
]),
|
]),
|
||||||
)(SettingsGeneralBackground));
|
)(SettingsGeneralBackground));
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React, {
|
|||||||
import { withGlobal } from '../../../lib/teact/teactn';
|
import { withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { GlobalActions } from '../../../global/types';
|
import { GlobalActions } from '../../../global/types';
|
||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens, ThemeKey } from '../../../types';
|
||||||
|
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
import {
|
import {
|
||||||
@ -24,10 +24,11 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
customBackground?: string;
|
backgroundColor?: string;
|
||||||
|
theme: ThemeKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, 'setSettingOption'>;
|
type DispatchProps = Pick<GlobalActions, 'setThemeSettings'>;
|
||||||
|
|
||||||
interface CanvasRects {
|
interface CanvasRects {
|
||||||
colorRect: {
|
colorRect: {
|
||||||
@ -49,9 +50,12 @@ const PREDEFINED_COLORS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||||
customBackground,
|
theme,
|
||||||
setSettingOption,
|
backgroundColor,
|
||||||
|
setThemeSettings,
|
||||||
}) => {
|
}) => {
|
||||||
|
const themeRef = useRef<string>();
|
||||||
|
themeRef.current = theme;
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
// eslint-disable-next-line no-null/no-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 huePickerRef = useRef<HTMLDivElement>(null);
|
||||||
const isFirstRunRef = useRef(true);
|
const isFirstRunRef = useRef(true);
|
||||||
|
|
||||||
const [hsb, setHsb] = useState(getInitialHsb(customBackground));
|
const [hsb, setHsb] = useState(getInitialHsb(backgroundColor));
|
||||||
// Cache for drag handlers
|
// Cache for drag handlers
|
||||||
const hsbRef = useRef(hsb);
|
const hsbRef = useRef(hsb);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -139,13 +143,16 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
setHexInput(color);
|
setHexInput(color);
|
||||||
|
|
||||||
if (!isFirstRunRef.current) {
|
if (!isFirstRunRef.current) {
|
||||||
setSettingOption({
|
const patternColor = getPatternColor(rgb);
|
||||||
customBackground: color,
|
setThemeSettings({
|
||||||
patternColor: getPatternColor(rgb),
|
theme: themeRef.current,
|
||||||
|
background: undefined,
|
||||||
|
backgroundColor: color,
|
||||||
|
patternColor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
isFirstRunRef.current = false;
|
isFirstRunRef.current = false;
|
||||||
}, [hsb, setSettingOption]);
|
}, [hsb, setThemeSettings]);
|
||||||
|
|
||||||
// Redraw color picker when hue changes
|
// Redraw color picker when hue changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -226,9 +233,9 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getInitialHsb(customBackground?: string) {
|
function getInitialHsb(backgroundColor?: string) {
|
||||||
return customBackground && customBackground.startsWith('#')
|
return backgroundColor && backgroundColor.startsWith('#')
|
||||||
? rgb2hsb(hex2rgb(customBackground.replace('#', '')))
|
? rgb2hsb(hex2rgb(backgroundColor.replace('#', '')))
|
||||||
: DEFAULT_HSB;
|
: DEFAULT_HSB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,9 +336,12 @@ function drawHue(canvas: HTMLCanvasElement) {
|
|||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
|
const { theme } = global.settings.byKey;
|
||||||
|
const { backgroundColor } = global.settings.themes[theme] || {};
|
||||||
return {
|
return {
|
||||||
customBackground: global.settings.byKey.customBackground,
|
backgroundColor,
|
||||||
|
theme,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, ['setSettingOption']),
|
(setGlobal, actions): DispatchProps => pick(actions, ['setThemeSettings']),
|
||||||
)(SettingsGeneralBackground));
|
)(SettingsGeneralBackground));
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useEffect, useState,
|
FC, memo, useCallback, useEffect, useState, useRef,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { ApiWallpaper } from '../../../api/types';
|
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 { CUSTOM_BG_CACHE_NAME } from '../../../config';
|
||||||
import * as cacheApi from '../../../util/cacheApi';
|
import * as cacheApi from '../../../util/cacheApi';
|
||||||
@ -21,6 +21,7 @@ import './WallpaperTile.scss';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
wallpaper: ApiWallpaper;
|
wallpaper: ApiWallpaper;
|
||||||
|
theme: ThemeKey;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
onClick: (slug: string) => void;
|
onClick: (slug: string) => void;
|
||||||
};
|
};
|
||||||
@ -29,11 +30,11 @@ const ANIMATION_DURATION = 300;
|
|||||||
|
|
||||||
const WallpaperTile: FC<OwnProps> = ({
|
const WallpaperTile: FC<OwnProps> = ({
|
||||||
wallpaper,
|
wallpaper,
|
||||||
|
theme,
|
||||||
isSelected,
|
isSelected,
|
||||||
onClick,
|
onClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { slug, document } = wallpaper;
|
const { slug, document } = wallpaper;
|
||||||
|
|
||||||
const localMediaHash = `wallpaper${document.id!}`;
|
const localMediaHash = `wallpaper${document.id!}`;
|
||||||
const localBlobUrl = document.previewBlobUrl;
|
const localBlobUrl = document.previewBlobUrl;
|
||||||
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
|
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
|
||||||
@ -56,11 +57,14 @@ const WallpaperTile: FC<OwnProps> = ({
|
|||||||
wasDownloadDisabled,
|
wasDownloadDisabled,
|
||||||
'slow',
|
'slow',
|
||||||
);
|
);
|
||||||
|
// To prevent triggering of the effect for useCallback
|
||||||
|
const cacheKeyRef = useRef<string>();
|
||||||
|
cacheKeyRef.current = theme;
|
||||||
|
|
||||||
const handleSelect = useCallback(() => {
|
const handleSelect = useCallback(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const blob = await fetchBlob(fullMedia!);
|
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);
|
onClick(slug);
|
||||||
})();
|
})();
|
||||||
}, [fullMedia, onClick, slug]);
|
}, [fullMedia, onClick, slug]);
|
||||||
|
|||||||
@ -16,11 +16,18 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: #A2AF8E;
|
background-color: var(--theme-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::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-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@ -32,10 +39,15 @@
|
|||||||
body.animation-level-0 & {
|
body.animation-level-0 & {
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
.custom-bg-color > &::before {
|
||||||
background-image: url('../../assets/chat-bg-mobile.jpg');
|
filter: blur(0);
|
||||||
}
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-bg-color:not(.custom-bg-image) > &::after {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-bg-image > &::after {
|
.custom-bg-image > &::after {
|
||||||
@ -44,20 +56,10 @@
|
|||||||
transform: scale(1.1);
|
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 {
|
.custom-bg-image.blurred > &::after {
|
||||||
filter: blur(12px);
|
filter: blur(12px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-bg-color > &::after {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1276px) {
|
@media screen and (min-width: 1276px) {
|
||||||
body.animation-level-2 &::before,
|
body.animation-level-2 &::before,
|
||||||
body.animation-level-2 &::after {
|
body.animation-level-2 &::after {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { withGlobal } from '../../lib/teact/teactn';
|
|||||||
|
|
||||||
import { MAIN_THREAD_ID } from '../../api/types';
|
import { MAIN_THREAD_ID } from '../../api/types';
|
||||||
import { GlobalActions, MessageListType } from '../../global/types';
|
import { GlobalActions, MessageListType } from '../../global/types';
|
||||||
|
import { ThemeKey } from '../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,
|
MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,
|
||||||
@ -15,6 +16,8 @@ import {
|
|||||||
CONTENT_TYPES_FOR_QUICK_UPLOAD,
|
CONTENT_TYPES_FOR_QUICK_UPLOAD,
|
||||||
ANIMATION_LEVEL_MAX,
|
ANIMATION_LEVEL_MAX,
|
||||||
ANIMATION_END_DELAY,
|
ANIMATION_END_DELAY,
|
||||||
|
DARK_THEME_BG_COLOR,
|
||||||
|
LIGHT_THEME_BG_COLOR,
|
||||||
} from '../../config';
|
} from '../../config';
|
||||||
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV, MASK_IMAGE_DISABLED } from '../../util/environment';
|
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV, MASK_IMAGE_DISABLED } from '../../util/environment';
|
||||||
import { DropAreaState } from './composer/DropArea';
|
import { DropAreaState } from './composer/DropArea';
|
||||||
@ -59,9 +62,10 @@ type StateProps = {
|
|||||||
messageSendingRestrictionReason?: string;
|
messageSendingRestrictionReason?: string;
|
||||||
hasPinnedOrAudioMessage?: boolean;
|
hasPinnedOrAudioMessage?: boolean;
|
||||||
pinnedMessagesCount?: number;
|
pinnedMessagesCount?: number;
|
||||||
|
theme: ThemeKey;
|
||||||
customBackground?: string;
|
customBackground?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
patternColor?: string;
|
patternColor?: string;
|
||||||
isCustomBackgroundColor?: boolean;
|
|
||||||
isRightColumnShown?: boolean;
|
isRightColumnShown?: boolean;
|
||||||
isBackgroundBlurred?: boolean;
|
isBackgroundBlurred?: boolean;
|
||||||
isMobileSearchActive?: boolean;
|
isMobileSearchActive?: boolean;
|
||||||
@ -88,8 +92,9 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
hasPinnedOrAudioMessage,
|
hasPinnedOrAudioMessage,
|
||||||
pinnedMessagesCount,
|
pinnedMessagesCount,
|
||||||
customBackground,
|
customBackground,
|
||||||
|
theme,
|
||||||
|
backgroundColor,
|
||||||
patternColor,
|
patternColor,
|
||||||
isCustomBackgroundColor,
|
|
||||||
isRightColumnShown,
|
isRightColumnShown,
|
||||||
isBackgroundBlurred,
|
isBackgroundBlurred,
|
||||||
isMobileSearchActive,
|
isMobileSearchActive,
|
||||||
@ -173,12 +178,12 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
openChat({ id: chatId });
|
openChat({ id: chatId });
|
||||||
}, [unpinAllMessages, openChat, closeUnpinModal, chatId]);
|
}, [unpinAllMessages, openChat, closeUnpinModal, chatId]);
|
||||||
|
|
||||||
const customBackgroundValue = useCustomBackground(customBackground);
|
const customBackgroundValue = useCustomBackground(theme, customBackground);
|
||||||
|
|
||||||
const className = buildClassName(
|
const className = buildClassName(
|
||||||
renderingHasTools && 'has-header-tools',
|
renderingHasTools && 'has-header-tools',
|
||||||
customBackground && !isCustomBackgroundColor && 'custom-bg-image',
|
customBackground && 'custom-bg-image',
|
||||||
customBackground && isCustomBackgroundColor && 'custom-bg-color',
|
backgroundColor && 'custom-bg-color',
|
||||||
customBackground && isBackgroundBlurred && 'blurred',
|
customBackground && isBackgroundBlurred && 'blurred',
|
||||||
MASK_IMAGE_DISABLED ? 'mask-image-disabled' : 'mask-image-enabled',
|
MASK_IMAGE_DISABLED ? 'mask-image-disabled' : 'mask-image-enabled',
|
||||||
);
|
);
|
||||||
@ -219,6 +224,8 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
--composer-translate-x: ${composerTranslateX}px;
|
--composer-translate-x: ${composerTranslateX}px;
|
||||||
--toolbar-translate-x: ${toolbarTranslateX}px;
|
--toolbar-translate-x: ${toolbarTranslateX}px;
|
||||||
--pattern-color: ${patternColor};
|
--pattern-color: ${patternColor};
|
||||||
|
--theme-background-color:
|
||||||
|
${backgroundColor || (theme === 'dark' ? DARK_THEME_BG_COLOR : LIGHT_THEME_BG_COLOR)};
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -318,16 +325,19 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(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 currentMessageList = selectCurrentMessageList(global);
|
||||||
const { chats: { listIds } } = global;
|
const { chats: { listIds } } = global;
|
||||||
|
|
||||||
const state: StateProps = {
|
const state: StateProps = {
|
||||||
|
theme,
|
||||||
customBackground,
|
customBackground,
|
||||||
|
backgroundColor,
|
||||||
patternColor,
|
patternColor,
|
||||||
isCustomBackgroundColor,
|
|
||||||
isRightColumnShown: selectIsRightColumnShown(global),
|
isRightColumnShown: selectIsRightColumnShown(global),
|
||||||
isBackgroundBlurred,
|
isBackgroundBlurred,
|
||||||
isMobileSearchActive: Boolean(IS_MOBILE_SCREEN && selectCurrentTextSearch(global)),
|
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 LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos'];
|
||||||
export const TIPS_USERNAME = 'TelegramTips';
|
export const TIPS_USERNAME = 'TelegramTips';
|
||||||
export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time';
|
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_BG_COLOR = '#0F0F0F';
|
||||||
export const DARK_THEME_PATTERN_COLOR = '#0a0a0a8c';
|
export const DARK_THEME_PATTERN_COLOR = '#0a0a0a8c';
|
||||||
export const DEFAULT_PATTERN_COLOR = 'rgba(90, 110, 70, 0.6)';
|
export const DEFAULT_PATTERN_COLOR = 'rgba(90, 110, 70, 0.6)';
|
||||||
|
|||||||
@ -77,6 +77,10 @@ function readCache(initialState: GlobalState) {
|
|||||||
...initialState.settings.byKey,
|
...initialState.settings.byKey,
|
||||||
...cached.settings.byKey,
|
...cached.settings.byKey,
|
||||||
};
|
};
|
||||||
|
cached.settings.themes = {
|
||||||
|
...initialState.settings.themes,
|
||||||
|
...cached.settings.themes,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -204,10 +208,11 @@ function reduceMessages(global: GlobalState): GlobalState['messages'] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reduceSettings(global: GlobalState): GlobalState['settings'] {
|
function reduceSettings(global: GlobalState): GlobalState['settings'] {
|
||||||
const { byKey } = global.settings;
|
const { byKey, themes } = global.settings;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
byKey,
|
byKey,
|
||||||
|
themes,
|
||||||
privacy: {},
|
privacy: {},
|
||||||
notifyExceptions: {},
|
notifyExceptions: {},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { GlobalState } from './types';
|
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 = {
|
export const INITIAL_STATE: GlobalState = {
|
||||||
isLeftColumnShown: true,
|
isLeftColumnShown: true,
|
||||||
@ -100,8 +102,6 @@ export const INITIAL_STATE: GlobalState = {
|
|||||||
settings: {
|
settings: {
|
||||||
byKey: {
|
byKey: {
|
||||||
messageTextSize: DEFAULT_MESSAGE_TEXT_SIZE_PX,
|
messageTextSize: DEFAULT_MESSAGE_TEXT_SIZE_PX,
|
||||||
isBackgroundBlurred: true,
|
|
||||||
patternColor: DEFAULT_PATTERN_COLOR,
|
|
||||||
animationLevel: ANIMATION_LEVEL_DEFAULT,
|
animationLevel: ANIMATION_LEVEL_DEFAULT,
|
||||||
messageSendKeyCombo: 'enter',
|
messageSendKeyCombo: 'enter',
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
@ -115,6 +115,16 @@ export const INITIAL_STATE: GlobalState = {
|
|||||||
shouldLoopStickers: true,
|
shouldLoopStickers: true,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
},
|
},
|
||||||
|
themes: {
|
||||||
|
light: {
|
||||||
|
isBlurred: true,
|
||||||
|
patternColor: DEFAULT_PATTERN_COLOR,
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
isBlurred: true,
|
||||||
|
patternColor: DARK_THEME_PATTERN_COLOR,
|
||||||
|
},
|
||||||
|
},
|
||||||
privacy: {},
|
privacy: {},
|
||||||
notifyExceptions: {},
|
notifyExceptions: {},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -34,6 +34,8 @@ import {
|
|||||||
Receipt,
|
Receipt,
|
||||||
ApiPrivacyKey,
|
ApiPrivacyKey,
|
||||||
ApiPrivacySettings,
|
ApiPrivacySettings,
|
||||||
|
ThemeKey,
|
||||||
|
IThemeSettings,
|
||||||
NotifyException,
|
NotifyException,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
@ -365,6 +367,7 @@ export type GlobalState = {
|
|||||||
settings: {
|
settings: {
|
||||||
byKey: ISettings;
|
byKey: ISettings;
|
||||||
loadedWallpapers?: ApiWallpaper[];
|
loadedWallpapers?: ApiWallpaper[];
|
||||||
|
themes: Partial<Record<ThemeKey, IThemeSettings>>;
|
||||||
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
|
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
|
||||||
notifyExceptions?: Record<number, NotifyException>;
|
notifyExceptions?: Record<number, NotifyException>;
|
||||||
};
|
};
|
||||||
@ -438,7 +441,7 @@ export type ActionTypes = (
|
|||||||
'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations' |
|
'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations' |
|
||||||
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' |
|
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' |
|
||||||
'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' |
|
'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' |
|
||||||
'loadNotificationExceptions' |
|
'loadNotificationExceptions' | 'setThemeSettings' |
|
||||||
// Stickers & GIFs
|
// Stickers & GIFs
|
||||||
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
||||||
'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' |
|
'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';
|
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);
|
const [value, setValue] = useState(settingValue);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -13,12 +17,16 @@ export default (settingValue?: string) => {
|
|||||||
if (settingValue.startsWith('#')) {
|
if (settingValue.startsWith('#')) {
|
||||||
setValue(settingValue);
|
setValue(settingValue);
|
||||||
} else {
|
} 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) => {
|
.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 { addReducer } from '../../../lib/teact/teactn';
|
||||||
import { ISettings } from '../../../types';
|
import { ISettings, IThemeSettings, ThemeKey } from '../../../types';
|
||||||
import { replaceSettings } from '../../reducers';
|
import { replaceSettings, replaceThemeSettings } from '../../reducers';
|
||||||
|
|
||||||
addReducer('setSettingOption', (global, actions, payload?: Partial<ISettings>) => {
|
addReducer('setSettingOption', (global, actions, payload?: Partial<ISettings>) => {
|
||||||
return replaceSettings(global, payload);
|
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 { 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 {
|
export function replaceSettings(global: GlobalState, newSettings?: Partial<ISettings>): GlobalState {
|
||||||
return {
|
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(
|
export function addNotifyException(
|
||||||
global: GlobalState, id: number, notifyException: NotifyException,
|
global: GlobalState, id: number, notifyException: NotifyException,
|
||||||
): GlobalState {
|
): GlobalState {
|
||||||
|
|||||||
@ -20,6 +20,14 @@ export interface IAlbum {
|
|||||||
mainMessage: ApiMessage;
|
mainMessage: ApiMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ThemeKey = 'light' | 'dark';
|
||||||
|
export interface IThemeSettings {
|
||||||
|
background?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
patternColor?: string;
|
||||||
|
isBlurred?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type NotifySettings = {
|
export type NotifySettings = {
|
||||||
hasPrivateChatsNotifications?: boolean;
|
hasPrivateChatsNotifications?: boolean;
|
||||||
hasPrivateChatsMessagePreview?: boolean;
|
hasPrivateChatsMessagePreview?: boolean;
|
||||||
@ -31,13 +39,10 @@ export type NotifySettings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface ISettings extends NotifySettings, Record<string, any> {
|
export interface ISettings extends NotifySettings, Record<string, any> {
|
||||||
|
theme: ThemeKey;
|
||||||
messageTextSize: number;
|
messageTextSize: number;
|
||||||
customBackground?: string;
|
|
||||||
patternColor?: string;
|
|
||||||
isBackgroundBlurred?: boolean;
|
|
||||||
animationLevel: 0 | 1 | 2;
|
animationLevel: 0 | 1 | 2;
|
||||||
messageSendKeyCombo: 'enter' | 'ctrl-enter';
|
messageSendKeyCombo: 'enter' | 'ctrl-enter';
|
||||||
theme: 'light' | 'dark';
|
|
||||||
shouldAutoDownloadMediaFromContacts: boolean;
|
shouldAutoDownloadMediaFromContacts: boolean;
|
||||||
shouldAutoDownloadMediaInPrivateChats: boolean;
|
shouldAutoDownloadMediaInPrivateChats: boolean;
|
||||||
shouldAutoDownloadMediaInGroups: boolean;
|
shouldAutoDownloadMediaInGroups: boolean;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user