Optionally adjust progress bar position based on available size

This commit is contained in:
schroda
2025-01-02 15:15:43 +01:00
parent 4aa144cb25
commit 92892e6604
9 changed files with 103 additions and 26 deletions

View File

@@ -14,10 +14,16 @@ import { ButtonSelect } from '@/modules/core/components/buttons/ButtonSelect.tsx
export const ButtonSelectInput = <Value extends string | number>({
label,
description,
...buttonSelectProps
}: ComponentProps<typeof ButtonSelect<Value>> & { label: string }) => (
}: ComponentProps<typeof ButtonSelect<Value>> & { label: string; description?: string }) => (
<Stack>
<Typography>{label}</Typography>
{description && (
<Typography variant="body2" color="textDisabled">
{description}
</Typography>
)}
<ButtonSelect {...buttonSelectProps} />
</Stack>
);

View File

@@ -263,7 +263,6 @@ export const ReaderProgressBar = withPropsFrom(
'pageLoadStates',
'totalPages',
'currentPageIndex',
'progressBarPosition',
'readingMode',
],
);

View File

@@ -18,7 +18,7 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
import { ReaderResumeMode, ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
import { ProgressBarPosition, ReaderResumeMode, ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx';
@@ -147,6 +147,7 @@ const BaseMobileReaderProgressBar = ({
{getOptionForDirection(<SkipPreviousIcon />, <SkipNextIcon />, direction)}
</IconButton>
<ReaderProgressBar
progressBarPosition={ProgressBarPosition.BOTTOM}
fullSegmentClicks={false}
createProgressBarSlot={useCallback(
(page, pagesIndex, _2, _3, _4, _5, isTrailingPage, totalPages) => (

View File

@@ -7,11 +7,17 @@
*/
import { useTheme } from '@mui/material/styles';
import { memo, useCallback } from 'react';
import { memo, useCallback, useState } from 'react';
import { ReaderProgressBar } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBar.tsx';
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { IReaderSettings, ProgressBarType, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
import {
IReaderSettings,
ProgressBarPosition,
ProgressBarPositionAutoVertical,
ProgressBarType,
TReaderScrollbarContext,
} from '@/modules/reader/types/Reader.types.ts';
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
import { getProgressBarPositionInfo } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
@@ -22,6 +28,7 @@ import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContex
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
import { ReaderProgressBarSlotDesktop } from '@/modules/reader/components/overlay/progress-bar/desktop/ReaderProgressBarSlotDesktop.tsx';
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
const BaseStandardReaderProgressBar = ({
readerNavBarWidth,
@@ -31,20 +38,37 @@ const BaseStandardReaderProgressBar = ({
progressBarType,
progressBarSize,
progressBarPosition,
progressBarPositionAutoVertical,
readerDirection,
scrollbarXSize,
scrollbarYSize,
totalPages,
}: Pick<NavbarContextType, 'readerNavBarWidth'> &
Pick<TReaderProgressBarContext, 'isMaximized' | 'setIsMaximized' | 'isDragging'> &
Pick<IReaderSettings, 'progressBarType' | 'progressBarSize' | 'progressBarPosition'> &
Pick<
IReaderSettings,
'progressBarType' | 'progressBarSize' | 'progressBarPosition' | 'progressBarPositionAutoVertical'
> &
Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> &
Pick<ReaderProgressBarProps, 'totalPages'> & {
readerDirection: ReturnType<typeof ReaderService.useGetThemeDirection>;
}) => {
const theme = useTheme();
const { isBottom, isLeft, isRight, isVertical, isHorizontal } = getProgressBarPositionInfo(progressBarPosition);
const [, setRefreshProgressBarPosition] = useState({});
useResizeObserver(
window.document.documentElement,
useCallback(() => setRefreshProgressBarPosition({}), []),
);
const finalProgressBarPosition =
window.innerHeight > window.innerWidth &&
progressBarPositionAutoVertical !== ProgressBarPositionAutoVertical.OFF
? (progressBarPositionAutoVertical as unknown as ProgressBarPosition)
: progressBarPosition;
const { isBottom, isLeft, isRight, isVertical, isHorizontal } =
getProgressBarPositionInfo(finalProgressBarPosition);
const arePagesLoaded = !!totalPages;
const isHidden = progressBarType === ProgressBarType.HIDDEN;
@@ -55,6 +79,7 @@ const BaseStandardReaderProgressBar = ({
return (
<ReaderProgressBarDirectionWrapper>
<ReaderProgressBar
progressBarPosition={finalProgressBarPosition}
fullSegmentClicks
createProgressBarSlot={useCallback(
(
@@ -73,13 +98,13 @@ const BaseStandardReaderProgressBar = ({
pageUrl={page.primary.url}
primaryPageLoadState={primaryPageLoadState}
secondaryPageLoadState={secondaryPageLoadState}
progressBarPosition={progressBarPosition}
progressBarPosition={finalProgressBarPosition}
isCurrentPage={isCurrentPage}
isLeadingPage={isLeadingPage}
showDraggingStyle={showDraggingStyle}
/>
),
[progressBarPosition],
[finalProgressBarPosition],
)}
slotProps={{
container: {
@@ -243,6 +268,7 @@ export const StandardReaderProgressBar = withPropsFrom(
'progressBarType',
'progressBarSize',
'progressBarPosition',
'progressBarPositionAutoVertical',
'readerDirection',
'scrollbarXSize',
'scrollbarYSize',

View File

@@ -52,9 +52,9 @@ export const ReaderGeneralSettings = ({
onDefault={() => onDefault?.('progressBarSize')}
/>
<ReaderSettingProgressBarPosition
overlayMode={overlayMode}
progressBarPosition={settings.progressBarPosition}
setProgressBarPosition={(value) => updateSetting('progressBarPosition', value)}
progressBarPositionAutoVertical={settings.progressBarPositionAutoVertical}
updateSetting={updateSetting}
/>
{(settings.progressBarType === ProgressBarType.HIDDEN || overlayMode === ReaderOverlayMode.MOBILE) && (
<CheckboxInput

View File

@@ -9,7 +9,12 @@
import { useTranslation } from 'react-i18next';
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
import { IReaderSettings, ProgressBarPosition, ReaderOverlayMode } from '@/modules/reader/types/Reader.types.ts';
import NotInterestedIcon from '@mui/icons-material/NotInterested';
import {
IReaderSettings,
ProgressBarPosition,
ProgressBarPositionAutoVertical,
} from '@/modules/reader/types/Reader.types.ts';
import { ValueToDisplayData } from '@/modules/core/Core.types.ts';
import { ButtonSelectInput } from '@/modules/core/components/inputs/ButtonSelectInput.tsx';
@@ -30,26 +35,53 @@ const VALUE_TO_DISPLAY_DATA: ValueToDisplayData<ProgressBarPosition> = {
const PROGRESS_BAR_POSITION_VALUES = Object.values(ProgressBarPosition).filter((value) => typeof value === 'number');
const VALUE_TO_DISPLAY_DATA_AUTO_VERTICAL: ValueToDisplayData<ProgressBarPositionAutoVertical> = {
...VALUE_TO_DISPLAY_DATA,
[ProgressBarPositionAutoVertical.OFF]: {
title: 'global.label.disabled',
icon: <NotInterestedIcon />,
},
};
const PROGRESS_BAR_AUTO_VERTICAL_POSITION_VALUES = Object.values(ProgressBarPositionAutoVertical).filter(
(value) => typeof value === 'number',
);
export const ReaderSettingProgressBarPosition = ({
overlayMode,
progressBarPosition,
setProgressBarPosition,
}: Pick<IReaderSettings, 'progressBarPosition' | 'overlayMode'> & {
setProgressBarPosition: (position: ProgressBarPosition) => void;
progressBarPositionAutoVertical,
updateSetting,
}: Pick<IReaderSettings, 'progressBarPosition' | 'progressBarPositionAutoVertical'> & {
updateSetting: <
Position extends keyof Pick<IReaderSettings, 'progressBarPosition' | 'progressBarPositionAutoVertical'>,
>(
filter: Position,
value: IReaderSettings[Position],
) => void;
}) => {
const { t } = useTranslation();
if (overlayMode !== ReaderOverlayMode.DESKTOP) {
return null;
}
const supportsAutoVerticalPosition = progressBarPosition === ProgressBarPosition.BOTTOM;
return (
<ButtonSelectInput
label={t('reader.settings.progress_bar.position')}
value={progressBarPosition}
values={PROGRESS_BAR_POSITION_VALUES}
setValue={setProgressBarPosition}
valueToDisplayData={VALUE_TO_DISPLAY_DATA}
/>
<>
<ButtonSelectInput
label={t('reader.settings.progress_bar.position')}
value={progressBarPosition}
values={PROGRESS_BAR_POSITION_VALUES}
setValue={(position) => updateSetting('progressBarPosition', position)}
valueToDisplayData={VALUE_TO_DISPLAY_DATA}
/>
{supportsAutoVerticalPosition && (
<ButtonSelectInput
label={t('reader.settings.progress_bar.auto_vertical_position.title')}
description={t('reader.settings.progress_bar.auto_vertical_position.description')}
value={progressBarPositionAutoVertical}
values={PROGRESS_BAR_AUTO_VERTICAL_POSITION_VALUES}
setValue={(position) => updateSetting('progressBarPositionAutoVertical', position)}
valueToDisplayData={VALUE_TO_DISPLAY_DATA_AUTO_VERTICAL}
/>
)}
</>
);
};

View File

@@ -50,6 +50,7 @@ const GLOBAL_READER_SETTING_OBJECT: Record<keyof IReaderSettingsGlobal, undefine
progressBarType: undefined,
progressBarSize: undefined,
progressBarPosition: undefined,
progressBarPositionAutoVertical: undefined,
shouldShowPageNumber: undefined,
isStaticNav: undefined,
backgroundColor: undefined,
@@ -73,6 +74,7 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
progressBarType: ProgressBarType.STANDARD,
progressBarSize: 4,
progressBarPosition: ProgressBarPosition.BOTTOM,
progressBarPositionAutoVertical: ProgressBarPosition.RIGHT,
pageScaleMode: ReaderPageScaleMode.ORIGINAL,
shouldStretchPage: false,
shouldOffsetDoubleSpreads: false,

View File

@@ -25,6 +25,12 @@ export enum ProgressBarPosition {
RIGHT,
}
export enum ProgressBarPositionAutoVertical {
OFF = -1,
LEFT = ProgressBarPosition.LEFT,
RIGHT = ProgressBarPosition.RIGHT,
}
export enum ReadingDirection {
LTR,
RTL,
@@ -119,6 +125,7 @@ export interface IReaderSettingsGlobal {
*/
progressBarSize: number;
progressBarPosition: ProgressBarPosition;
progressBarPositionAutoVertical: ProgressBarPositionAutoVertical;
shouldShowPageNumber: boolean;
isStaticNav: boolean;
backgroundColor: ReaderBackgroundColor;