Ensure stored client metadata values respect constraints

This commit is contained in:
schroda
2025-06-24 22:22:53 +02:00
parent 09b5f7e558
commit 56f01efc1e
20 changed files with 520 additions and 195 deletions

View File

@@ -16,7 +16,10 @@ import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.ts
import { ReaderSettingExitMode } from '@/modules/reader/components/settings/behaviour/ReaderSettingExitMode.tsx';
import { isOffsetDoubleSpreadPagesEditable } from '@/modules/reader/utils/ReaderSettings.utils.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,
IMAGE_PRE_LOAD_AMOUNT,
} from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { ReaderSettingAutoScroll } from '@/modules/reader/components/settings/behaviour/ReaderSettingAutoScroll.tsx';
import { ReaderSettingScrollAmount } from '@/modules/reader/components/settings/behaviour/ReaderSettingScrollAmount.tsx';
@@ -129,9 +132,9 @@ export const ReaderBehaviourSettings = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.imagePreLoadAmount,
value: settings.imagePreLoadAmount,
step: 1,
min: 1,
max: 20,
step: IMAGE_PRE_LOAD_AMOUNT.step,
min: IMAGE_PRE_LOAD_AMOUNT.min,
max: IMAGE_PRE_LOAD_AMOUNT.max,
onChange: (_, value) => {
updateSetting('imagePreLoadAmount', value as number, false);
},

View File

@@ -7,15 +7,11 @@
*/
import { useTranslation } from 'react-i18next';
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { IReaderSettings, ReaderScrollAmount } from '@/modules/reader/types/Reader.types.ts';
import { ValueToDisplayData } from '@/modules/core/Core.types.ts';
import { ButtonSelectInput } from '@/modules/core/components/inputs/ButtonSelectInput.tsx';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import {
ReaderScrollAmount,
DEFAULT_READER_SETTINGS,
SCROLL_AMOUNT,
} from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { DEFAULT_READER_SETTINGS, SCROLL_AMOUNT } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
const VALUE_TO_DISPLAY_DATA: ValueToDisplayData<ReaderScrollAmount> = {
[ReaderScrollAmount.TINY]: {

View File

@@ -12,7 +12,7 @@ import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { CUSTOM_FILTER, DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export const ReaderSettingBrightness = ({
brightness,
@@ -48,9 +48,9 @@ export const ReaderSettingBrightness = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.customFilter.brightness.value,
value: brightness.value,
step: 1,
min: 5,
max: 200,
step: CUSTOM_FILTER.brightness.step,
min: CUSTOM_FILTER.brightness.min,
max: CUSTOM_FILTER.brightness.max,
onChange: (_, value) => {
updateSetting('brightness', { ...brightness, value: value as number }, false);
},

View File

@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { CUSTOM_FILTER, DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export const ReaderSettingContrast = ({
contrast,
@@ -47,9 +47,9 @@ export const ReaderSettingContrast = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.customFilter.contrast.value,
value: contrast.value,
step: 1,
min: 5,
max: 200,
step: CUSTOM_FILTER.contrast.step,
min: CUSTOM_FILTER.contrast.min,
max: CUSTOM_FILTER.contrast.max,
onChange: (_, newValue) => {
updateSetting('contrast', { ...contrast, value: newValue as number }, false);
},

View File

@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { CUSTOM_FILTER, DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export const ReaderSettingHue = ({
hue,
@@ -43,9 +43,9 @@ export const ReaderSettingHue = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.customFilter.hue.value,
value: hue.value,
step: 1,
min: 0,
max: 200,
step: CUSTOM_FILTER.hue.step,
min: CUSTOM_FILTER.hue.min,
max: CUSTOM_FILTER.hue.max,
onChange: (_, newValue) => {
updateSetting('hue', { ...hue, value: newValue as number }, false);
},

View File

@@ -14,6 +14,7 @@ import { TranslationKey } from '@/Base.types.ts';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import {
CUSTOM_FILTER,
DEFAULT_READER_SETTINGS,
READER_BLEND_MODE_VALUE_TO_DISPLAY_DATA,
READER_BLEND_MODE_VALUES,
@@ -29,13 +30,6 @@ const RGBA_TYPE_TO_TRANSLATION_KEY: Record<RGBAType, TranslationKey> = {
alpha: 'reader.settings.custom_filter.rgba.alpha',
};
const RGBA_TYPE_TO_MAX_VALUE: Record<RGBAType, number> = {
red: 255,
green: 255,
blue: 255,
alpha: 100,
};
export const ReaderSettingRGBA = ({
rgba,
updateSetting,
@@ -84,9 +78,9 @@ export const ReaderSettingRGBA = ({
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],
step: CUSTOM_FILTER.rgba[key as RGBAType].step,
min: CUSTOM_FILTER.rgba[key as RGBAType].min,
max: CUSTOM_FILTER.rgba[key as RGBAType].max,
onChange: (_, newValue) => {
updateSetting(
'rgba',

View File

@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { CUSTOM_FILTER, DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export const ReaderSettingSaturate = ({
saturate,
@@ -47,9 +47,9 @@ export const ReaderSettingSaturate = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.customFilter.saturate.value,
value: saturate.value,
step: 1,
min: 0,
max: 200,
step: CUSTOM_FILTER.saturate.step,
min: CUSTOM_FILTER.saturate.min,
max: CUSTOM_FILTER.saturate.max,
onChange: (_, value) => {
updateSetting('saturate', { ...saturate, value: value as number }, false);
},

View File

@@ -9,7 +9,7 @@
import { useTranslation } from 'react-i18next';
import { IReaderSettings, ProgressBarType, ReaderOverlayMode } from '@/modules/reader/types/Reader.types.ts';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { AUTO_SCROLL_SPEED, DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export const ReaderSettingProgressBarSize = ({
overlayMode,
@@ -37,9 +37,9 @@ export const ReaderSettingProgressBarSize = ({
slider: {
defaultValue: DEFAULT_READER_SETTINGS.progressBarSize,
value: progressBarSize,
step: 1,
min: 2,
max: 20,
step: AUTO_SCROLL_SPEED.step,
min: AUTO_SCROLL_SPEED.min,
max: AUTO_SCROLL_SPEED.max,
onChange: (_, value) => {
setProgressBarSize(value as number, false);
},

View File

@@ -9,7 +9,7 @@
import { useTranslation } from 'react-i18next';
import { IReaderSettings, IReaderSettingsWithDefaultFlag, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
import { SliderInput } from '@/modules/core/components/inputs/SliderInput.tsx';
import { DEFAULT_READER_SETTINGS } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { DEFAULT_READER_SETTINGS, PAGE_GAP } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
import { MultiValueButtonDefaultableProps } from '@/modules/core/Core.types.ts';
@@ -37,11 +37,11 @@ export const ReaderSettingPageGap = ({
onDefault={isDefaultable ? onDefault : undefined}
slotProps={{
slider: {
defaultValue: DEFAULT_READER_SETTINGS.readerWidth.value,
defaultValue: DEFAULT_READER_SETTINGS.pageGap,
value: pageGap.value,
step: 1,
min: 0,
max: 20,
step: PAGE_GAP.step,
min: PAGE_GAP.min,
max: PAGE_GAP.max,
onChange: (_, value) => {
updateSetting(value as number, false);
},

View File

@@ -25,6 +25,7 @@ import {
ReaderHotkey,
ReaderOverlayMode,
ReaderPageScaleMode,
ReaderScrollAmount,
ReadingDirection,
ReadingMode,
} from '@/modules/reader/types/Reader.types.ts';
@@ -36,15 +37,93 @@ import { TranslationKey } from '@/Base.types.ts';
import { TapZoneLayouts } from '@/modules/reader/types/TapZoneLayout.types.ts';
import { WebtoonPageIcon } from '@/assets/icons/svg/WebtoonPageIcon.tsx';
/**
* percentage values
*/
export enum ReaderScrollAmount {
TINY = 10,
SMALL = 25,
MEDIUM = 75,
LARGE = 95,
}
export const AUTO_SCROLL_SPEED = {
min: 0.5,
max: 60,
step: 0.5,
default: 5,
};
export const SCROLL_AMOUNT = {
min: 5,
max: 100,
default: ReaderScrollAmount.LARGE,
step: 5,
};
export const PROGRESS_BAR_SIZE = {
min: 2,
max: 20,
step: 1,
default: 4,
};
export const IMAGE_PRE_LOAD_AMOUNT = {
min: 1,
max: 20,
default: 5,
step: 1,
};
export const PAGE_GAP = {
min: 0,
max: 20,
default: 5,
step: 1,
};
export const CUSTOM_FILTER = {
brightness: {
min: 5,
max: 200,
step: 1,
default: 100,
},
contrast: {
min: 5,
max: 200,
step: 1,
default: 100,
},
saturate: {
min: 0,
max: 200,
step: 1,
default: 100,
},
hue: {
min: 0,
max: 200,
step: 1,
default: 0,
},
rgba: {
red: {
min: 0,
max: 255,
step: 1,
default: 0,
},
green: {
min: 0,
max: 255,
step: 1,
default: 0,
},
blue: {
min: 0,
max: 255,
step: 1,
default: 0,
},
alpha: {
min: 0,
max: 100,
step: 1,
default: 0,
},
},
} as const;
export const READING_DIRECTION_TO_THEME_DIRECTION: Record<ReadingDirection, Direction> = {
[ReadingDirection.LTR]: 'ltr',
@@ -84,7 +163,7 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
tapZoneLayout: TapZoneLayouts.RIGHT_LEFT,
tapZoneInvertMode: { vertical: false, horizontal: false },
progressBarType: ProgressBarType.STANDARD,
progressBarSize: 4,
progressBarSize: PROGRESS_BAR_SIZE.default,
progressBarPosition: ProgressBarPosition.AUTO,
progressBarPositionAutoVertical: ProgressBarPosition.RIGHT,
pageScaleMode: ReaderPageScaleMode.ORIGINAL,
@@ -99,27 +178,27 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
backgroundColor: ReaderBackgroundColor.THEME,
customFilter: {
brightness: {
value: 100,
value: CUSTOM_FILTER.brightness.default,
enabled: false,
},
contrast: {
value: 100,
value: CUSTOM_FILTER.contrast.default,
enabled: false,
},
saturate: {
value: 100,
value: CUSTOM_FILTER.saturate.default,
enabled: false,
},
hue: {
value: 0,
value: CUSTOM_FILTER.hue.default,
enabled: false,
},
rgba: {
value: {
red: 0,
green: 0,
blue: 0,
alpha: 0,
red: CUSTOM_FILTER.rgba.red.default,
green: CUSTOM_FILTER.rgba.green.default,
blue: CUSTOM_FILTER.rgba.blue.default,
alpha: CUSTOM_FILTER.rgba.alpha.default,
blendMode: ReaderBlendMode.DEFAULT,
},
enabled: false,
@@ -128,7 +207,7 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
grayscale: false,
invert: false,
},
pageGap: 5,
pageGap: PAGE_GAP.default,
hotkeys: {
[ReaderHotkey.PREVIOUS_PAGE]: ['arrowleft', 'a'],
[ReaderHotkey.NEXT_PAGE]: ['arrowright', 'd'],
@@ -147,10 +226,10 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
[ReaderHotkey.AUTO_SCROLL_SPEED_DECREASE]: ['v'],
[ReaderHotkey.EXIT_READER]: ['c'],
},
imagePreLoadAmount: 5,
imagePreLoadAmount: IMAGE_PRE_LOAD_AMOUNT.default,
shouldUseAutoWebtoonMode: true,
autoScroll: {
value: 5,
value: AUTO_SCROLL_SPEED.default,
smooth: true,
},
shouldShowReadingModePreview: true,
@@ -303,18 +382,6 @@ export const CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION: Record<
[ReadingMode.WEBTOON]: ScrollDirection.Y,
};
export const AUTO_SCROLL_SPEED = {
min: 0.5,
max: 60,
step: 0.5,
};
export const SCROLL_AMOUNT = {
min: 5,
max: 100,
step: 5,
};
export const READER_BLEND_MODE_VALUE_TO_DISPLAY_DATA = {
[ReaderBlendMode.DEFAULT]: {
title: 'reader.settings.custom_filter.rgba.blend_mode.default',

View File

@@ -9,16 +9,18 @@
import { memo, ReactNode, useCallback, useMemo, useState } from 'react';
import { Direction, useTheme } from '@mui/material/styles';
import { useAutomaticScrolling } from '@/modules/core/hooks/useAutomaticScrolling.ts';
import { IReaderSettings, ReadingMode, TReaderAutoScrollContext } from '@/modules/reader/types/Reader.types.ts';
import {
IReaderSettings,
ReaderScrollAmount,
ReadingMode,
TReaderAutoScrollContext,
} from '@/modules/reader/types/Reader.types.ts';
import { ReaderAutoScrollContext } from '@/modules/reader/contexts/ReaderAutoScrollContext.tsx';
import { ReaderControls } from '@/modules/reader/services/ReaderControls';
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import {
CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION,
ReaderScrollAmount,
} from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
const BaseReaderAutoScrollContextProvider = ({
children,

View File

@@ -24,15 +24,13 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R
import {
PageInViewportType,
ProgressBarPosition,
ReaderScrollAmount,
ReaderTransitionPageMode,
ReadingDirection,
ReadingMode,
} from '@/modules/reader/types/Reader.types.ts';
import { ScrollDirection, ScrollOffset } from '@/modules/core/Core.types.ts';
import {
ReaderScrollAmount,
READING_DIRECTION_TO_THEME_DIRECTION,
} from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
import {
isATransitionPageVisible,
isEndOfPageInViewport,

View File

@@ -14,7 +14,6 @@ import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types
import { TMangaReader } from '@/modules/manga/Manga.types.ts';
import { useAutomaticScrolling } from '@/modules/core/hooks/useAutomaticScrolling.ts';
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
import { ReaderScrollAmount } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
export enum ProgressBarType {
HIDDEN,
@@ -130,6 +129,16 @@ export interface ReaderCustomFilter {
invert: boolean;
}
/**
* percentage values
*/
export enum ReaderScrollAmount {
TINY = 10,
SMALL = 25,
MEDIUM = 75,
LARGE = 95,
}
export interface IReaderSettingsGlobal {
overlayMode: ReaderOverlayMode;
exitMode: ReaderExitMode;