/* * Copyright (C) Contributors to the Suwayomi project * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import Dialog from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import TextField from '@mui/material/TextField'; import { InputAdornment, ListItemText, Stack, SxProps, Typography, Theme } from '@mui/material'; import DialogActions from '@mui/material/DialogActions'; import Button from '@mui/material/Button'; import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import ListItemButton from '@mui/material/ListItemButton'; import * as React from 'react'; import ListItemIcon from '@mui/material/ListItemIcon'; import Slider from '@mui/material/Slider'; import DialogContentText from '@mui/material/DialogContentText'; import InfoIcon from '@mui/icons-material/Info'; type BaseProps = { settingTitle: string; settingValue?: string; settingIcon?: React.ReactNode; value: number; defaultValue?: number; minValue?: number; maxValue?: number; stepSize?: number; dialogTitle?: string; dialogDescription?: string; dialogDisclaimer?: string; valueUnit: string; handleUpdate: (value: number) => void; showSlider?: never; disabled?: boolean; listItemTextSx?: SxProps; handleLiveUpdate?: (value: number) => void; }; type PropsWithSlider = Omit & Required> & { showSlider: true }; type Props = BaseProps | PropsWithSlider; export const NumberSetting = ({ settingTitle, settingValue, settingIcon, dialogDescription, dialogDisclaimer, value, defaultValue, minValue, maxValue, stepSize, dialogTitle = settingTitle, valueUnit, handleUpdate, showSlider, disabled = false, handleLiveUpdate, listItemTextSx: sx, }: Props) => { const { t } = useTranslation(); const [isDialogOpen, setIsDialogOpen] = useState(false); const [dialogValue, setDialogValue] = useState(value); const [originalValue, setOriginalValue] = useState(value); const updateValue = useCallback( (newValue: number, persist: boolean) => { setDialogValue(newValue); const didValueChange = newValue !== originalValue; // Call handleUpdate if the value changed and 'persist' is true, // otherwise call handleLiveUpdate if it's defined. if (persist && didValueChange) { handleUpdate(newValue); } else if (handleLiveUpdate) { handleLiveUpdate(newValue); } }, [originalValue, setDialogValue, handleLiveUpdate, handleUpdate], ); const cancel = useCallback(() => { updateValue(originalValue, true); setOriginalValue(originalValue); setIsDialogOpen(false); }, [originalValue, handleUpdate]); const resetToDefault = useCallback(() => { if (defaultValue !== undefined) { updateValue(defaultValue, true); setOriginalValue(defaultValue); setIsDialogOpen(false); } }, [defaultValue, handleUpdate]); const submit = () => { updateValue(dialogValue, true); setOriginalValue(dialogValue); setIsDialogOpen(false); }; return ( <> setIsDialogOpen(true)}> {settingIcon ? {settingIcon} : null} {dialogTitle} {(!!dialogDescription || !!dialogDisclaimer) && ( {dialogDescription && ( {dialogDescription} )} {dialogDisclaimer && ( {dialogDisclaimer} )} )} {valueUnit}, }} autoFocus value={dialogValue} type="number" onChange={(e) => { const newValue = Number(e.target.value); updateValue(newValue, false); }} /> {showSlider ? ( { updateValue(newValue as number, false); }} /> ) : null} {defaultValue !== undefined ? ( ) : null} ); };