Add "blend mode" to "custom color filter"
This commit is contained in:
@@ -869,6 +869,15 @@
|
|||||||
"invert": "Invert",
|
"invert": "Invert",
|
||||||
"rgba": {
|
"rgba": {
|
||||||
"alpha": "Alpha",
|
"alpha": "Alpha",
|
||||||
|
"blend_mode": {
|
||||||
|
"darken": "Darken",
|
||||||
|
"default": "$t(global.label.default)",
|
||||||
|
"lighten": "Lighten",
|
||||||
|
"multiply": "Multiply",
|
||||||
|
"overlay": "Overlay",
|
||||||
|
"screen": "Screen",
|
||||||
|
"title": "Color filter blend mode"
|
||||||
|
},
|
||||||
"blue": "Blue",
|
"blue": "Blue",
|
||||||
"green": "Green",
|
"green": "Green",
|
||||||
"red": "Red",
|
"red": "Red",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const BaseReaderRGBAFilter = ({
|
|||||||
readerNavBarWidth,
|
readerNavBarWidth,
|
||||||
customFilter: {
|
customFilter: {
|
||||||
rgba: {
|
rgba: {
|
||||||
value: { red, green, blue, alpha },
|
value: { red, green, blue, alpha, blendMode },
|
||||||
enabled,
|
enabled,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -36,6 +36,7 @@ const BaseReaderRGBAFilter = ({
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
background: `rgba(${red} ${green} ${blue} / ${alpha}%)`,
|
background: `rgba(${red} ${green} ${blue} / ${alpha}%)`,
|
||||||
|
mixBlendMode: `${blendMode}`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,9 +13,14 @@ import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.ts
|
|||||||
import { TranslationKey } from '@/Base.types.ts';
|
import { TranslationKey } from '@/Base.types.ts';
|
||||||
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
|
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
|
||||||
|
|
||||||
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
import {
|
||||||
|
DEFAULT_READER_SETTINGS,
|
||||||
|
READER_BLEND_MODE_VALUE_TO_DISPLAY_DATA,
|
||||||
|
READER_BLEND_MODE_VALUES,
|
||||||
|
} from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
||||||
|
import { ButtonSelectInput } from '@/modules/core/components/inputs/ButtonSelectInput.tsx';
|
||||||
|
|
||||||
type RGBAType = keyof IReaderSettings['customFilter']['rgba']['value'];
|
type RGBAType = Exclude<keyof IReaderSettings['customFilter']['rgba']['value'], 'blendMode'>;
|
||||||
|
|
||||||
const RGBA_TYPE_TO_TRANSLATION_KEY: Record<RGBAType, TranslationKey> = {
|
const RGBA_TYPE_TO_TRANSLATION_KEY: Record<RGBAType, TranslationKey> = {
|
||||||
red: 'reader.settings.custom_filter.rgba.red',
|
red: 'reader.settings.custom_filter.rgba.red',
|
||||||
@@ -52,49 +57,71 @@ export const ReaderSettingRGBA = ({
|
|||||||
/>
|
/>
|
||||||
{rgba.enabled && (
|
{rgba.enabled && (
|
||||||
<Stack sx={{ gap: 1 }}>
|
<Stack sx={{ gap: 1 }}>
|
||||||
{Object.entries(rgba.value).map(([key, value]) => (
|
{Object.entries(rgba.value).map(([key, value]) => {
|
||||||
<SliderInput
|
if (key === 'blendMode') {
|
||||||
key={key}
|
return null;
|
||||||
label={t(RGBA_TYPE_TO_TRANSLATION_KEY[key as RGBAType])}
|
}
|
||||||
value={value}
|
|
||||||
onDefault={() =>
|
return (
|
||||||
updateSetting(
|
<SliderInput
|
||||||
'rgba',
|
key={key}
|
||||||
{
|
label={t(RGBA_TYPE_TO_TRANSLATION_KEY[key as RGBAType])}
|
||||||
...rgba,
|
value={value}
|
||||||
value: {
|
onDefault={() =>
|
||||||
...rgba.value,
|
updateSetting(
|
||||||
[key]: DEFAULT_READER_SETTINGS.customFilter.rgba.value[key as RGBAType],
|
'rgba',
|
||||||
|
{
|
||||||
|
...rgba,
|
||||||
|
value: {
|
||||||
|
...rgba.value,
|
||||||
|
[key]: DEFAULT_READER_SETTINGS.customFilter.rgba.value[key as RGBAType],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
slotProps={{
|
||||||
|
slider: {
|
||||||
|
value,
|
||||||
|
defaultValue: DEFAULT_READER_SETTINGS.customFilter.rgba.value[key as RGBAType],
|
||||||
|
step: 1,
|
||||||
|
min: 0,
|
||||||
|
max: RGBA_TYPE_TO_MAX_VALUE[key as RGBAType],
|
||||||
|
onChange: (_, newValue) => {
|
||||||
|
updateSetting(
|
||||||
|
'rgba',
|
||||||
|
{ ...rgba, value: { ...rgba.value, [key]: newValue } },
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onChangeCommitted: (_, newValue) => {
|
||||||
|
updateSetting(
|
||||||
|
'rgba',
|
||||||
|
{ ...rgba, value: { ...rgba.value, [key]: newValue } },
|
||||||
|
true,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
true,
|
}}
|
||||||
)
|
/>
|
||||||
}
|
);
|
||||||
slotProps={{
|
})}
|
||||||
slider: {
|
<ButtonSelectInput
|
||||||
value,
|
label={t('reader.settings.custom_filter.rgba.blend_mode.title')}
|
||||||
defaultValue: DEFAULT_READER_SETTINGS.customFilter.rgba.value[key as RGBAType],
|
value={rgba.value.blendMode}
|
||||||
step: 1,
|
values={READER_BLEND_MODE_VALUES}
|
||||||
min: 0,
|
setValue={(value) =>
|
||||||
max: RGBA_TYPE_TO_MAX_VALUE[key as RGBAType],
|
updateSetting(
|
||||||
onChange: (_, newValue) => {
|
'rgba',
|
||||||
updateSetting(
|
{
|
||||||
'rgba',
|
...rgba,
|
||||||
{ ...rgba, value: { ...rgba.value, [key]: newValue } },
|
value: { ...rgba.value, blendMode: value },
|
||||||
false,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onChangeCommitted: (_, newValue) => {
|
|
||||||
updateSetting(
|
|
||||||
'rgba',
|
|
||||||
{ ...rgba, value: { ...rgba.value, [key]: newValue } },
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}}
|
true,
|
||||||
/>
|
)
|
||||||
))}
|
}
|
||||||
|
valueToDisplayData={READER_BLEND_MODE_VALUE_TO_DISPLAY_DATA}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
ProgressBarPosition,
|
ProgressBarPosition,
|
||||||
ProgressBarType,
|
ProgressBarType,
|
||||||
ReaderBackgroundColor,
|
ReaderBackgroundColor,
|
||||||
|
ReaderBlendMode,
|
||||||
ReaderExitMode,
|
ReaderExitMode,
|
||||||
ReaderHotkey,
|
ReaderHotkey,
|
||||||
ReaderOverlayMode,
|
ReaderOverlayMode,
|
||||||
@@ -108,6 +109,7 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
|
|||||||
green: 0,
|
green: 0,
|
||||||
blue: 0,
|
blue: 0,
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
|
blendMode: ReaderBlendMode.DEFAULT,
|
||||||
},
|
},
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
@@ -300,3 +302,32 @@ export const AUTO_SCROLL_SPEED = {
|
|||||||
max: 60,
|
max: 60,
|
||||||
step: 0.5,
|
step: 0.5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const READER_BLEND_MODE_VALUE_TO_DISPLAY_DATA = {
|
||||||
|
[ReaderBlendMode.DEFAULT]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.default',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
[ReaderBlendMode.MULTIPLY]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.multiply',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
[ReaderBlendMode.SCREEN]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.screen',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
[ReaderBlendMode.OVERLAY]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.overlay',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
[ReaderBlendMode.DARKEN]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.darken',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
[ReaderBlendMode.LIGHTEN]: {
|
||||||
|
title: 'reader.settings.custom_filter.rgba.blend_mode.lighten',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
} satisfies ValueToDisplayData<ReaderBlendMode>;
|
||||||
|
|
||||||
|
export const READER_BLEND_MODE_VALUES = Object.values(ReaderBlendMode);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies,no-restricted-imports
|
||||||
|
import { deepmerge } from '@mui/utils';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import {
|
import {
|
||||||
requestUpdateMangaMetadata,
|
requestUpdateMangaMetadata,
|
||||||
@@ -109,9 +111,11 @@ const convertMetadataToSettings = (
|
|||||||
tapZoneInvertMode:
|
tapZoneInvertMode:
|
||||||
jsonSaveParse<IReaderSettings['tapZoneInvertMode']>((metadata.tapZoneInvertMode as string) ?? '') ??
|
jsonSaveParse<IReaderSettings['tapZoneInvertMode']>((metadata.tapZoneInvertMode as string) ?? '') ??
|
||||||
defaultSettings.tapZoneInvertMode,
|
defaultSettings.tapZoneInvertMode,
|
||||||
customFilter:
|
customFilter: deepmerge(
|
||||||
jsonSaveParse<IReaderSettings['customFilter']>((metadata.customFilter as string) ?? '') ??
|
|
||||||
defaultSettings.customFilter,
|
defaultSettings.customFilter,
|
||||||
|
jsonSaveParse<IReaderSettings['customFilter']>((metadata.customFilter as string) ?? '') ??
|
||||||
|
defaultSettings.customFilter,
|
||||||
|
),
|
||||||
readerWidth:
|
readerWidth:
|
||||||
jsonSaveParse<IReaderSettings['readerWidth']>((metadata.readerWidth as string) ?? '') ??
|
jsonSaveParse<IReaderSettings['readerWidth']>((metadata.readerWidth as string) ?? '') ??
|
||||||
defaultSettings.readerWidth,
|
defaultSettings.readerWidth,
|
||||||
|
|||||||
@@ -79,6 +79,16 @@ export interface ReaderFilterRGBA {
|
|||||||
green: number;
|
green: number;
|
||||||
blue: number;
|
blue: number;
|
||||||
alpha: number;
|
alpha: number;
|
||||||
|
blendMode: ReaderBlendMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ReaderBlendMode {
|
||||||
|
DEFAULT = 'normal',
|
||||||
|
MULTIPLY = 'multiply',
|
||||||
|
SCREEN = 'screen',
|
||||||
|
OVERLAY = 'overlay',
|
||||||
|
DARKEN = 'darken',
|
||||||
|
LIGHTEN = 'lighten',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReaderCustomFilter {
|
export interface ReaderCustomFilter {
|
||||||
|
|||||||
Reference in New Issue
Block a user