diff --git a/src/components/sourceConfiguration/MultiSelectListPreference.tsx b/src/components/sourceConfiguration/MultiSelectListPreference.tsx new file mode 100644 index 00000000..8e4adb51 --- /dev/null +++ b/src/components/sourceConfiguration/MultiSelectListPreference.tsx @@ -0,0 +1,153 @@ +/* + * 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 React, { useState, useEffect } from 'react'; +import ListItem from '@mui/material/ListItem'; +import ListItemText from '@mui/material/ListItemText'; +import Dialog from '@mui/material/Dialog'; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogActions from '@mui/material/DialogActions'; +import FormGroup from '@mui/material/FormGroup'; +import Checkbox from '@mui/material/Checkbox'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Button from '@mui/material/Button'; +import cloneObject from 'util/cloneObject'; + +interface IListDialogProps{ + selectedValues: string[] + open: boolean + onClose: (arg0: string[] | null) => void + values: string[] +} + +function ListDialog(props: IListDialogProps) { + const { + selectedValues: selectedValuesProp, open, onClose, values, + } = props; + const [selectedValues, setSelectedValues] = React.useState(selectedValuesProp); + + React.useEffect(() => { + if (!open) { + setSelectedValues(selectedValuesProp); + } + }, [selectedValuesProp, open]); + + const handleCancel = () => { + onClose(null); + }; + + const handleOk = () => { + onClose(selectedValues); + }; + + const handleChange = (event: React.ChangeEvent, value: string) => { + const { checked } = event.target as HTMLInputElement; + + const hasEntry = selectedValues.some((selectedValue) => value === selectedValue); + if (checked) { + if (!hasEntry) { + const selectedValuesClone = cloneObject(selectedValues) as string[]; + selectedValuesClone.push(value); + setSelectedValues(selectedValuesClone); + } + } else if (hasEntry) { // not checked and has entry + const selectedValuesClone = cloneObject(selectedValues) as string[]; + const index = selectedValuesClone.indexOf(value); + selectedValuesClone.splice(index, 1); + setSelectedValues(selectedValuesClone); + } + }; + + return ( + + Phone Ringtone + + + {values.map((value) => ( + value === selectedValue, + )} + onChange={(e) => handleChange(e, value)} + color="default" + /> + )} + label={value} + key={value} + /> + ))} + + + + + + + + ); +} + +export default function MultiSelectListPreference(props: MultiSelectListPreferenceProps) { + const { + title, summary, currentValue, updateValue, entryValues, entries, + } = props; + const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue); + const [dialogOpen, setDialogOpen] = useState(false); + + useEffect(() => { + setInternalCurrentValue(currentValue); + }, [currentValue]); + + const findEntriesOf = (values: string[]) => values.map((value) => { + const idx = entryValues.indexOf(value); + return entries[idx]; + }); + + const findEntryValuesOf = (values: string[]) => values.map((value) => { + const idx = entries.indexOf(value); + return entryValues[idx]; + }); + + const getSummary = () => summary; + + const handleDialogClose = (newValue: string[] | null) => { + if (newValue !== null) { + // console.log(newValue); + updateValue(findEntryValuesOf(newValue)); + + // appear smooth + setInternalCurrentValue(newValue); + } + + setDialogOpen(false); + }; + + return ( + <> + setDialogOpen(true)} + > + + + + + ); +} diff --git a/src/screens/SourceConfigure.tsx b/src/screens/SourceConfigure.tsx index f57b02d2..8795396e 100644 --- a/src/screens/SourceConfigure.tsx +++ b/src/screens/SourceConfigure.tsx @@ -12,6 +12,7 @@ import client from 'util/client'; import { SwitchPreferenceCompat, CheckBoxPreference } from 'components/sourceConfiguration/TwoStatePreference'; import ListPreference from 'components/sourceConfiguration/ListPreference'; import EditTextPreference from 'components/sourceConfiguration/EditTextPreference'; +import MultiSelectListPreference from 'components/sourceConfiguration/MultiSelectListPreference'; import List from '@mui/material/List'; import cloneObject from 'util/cloneObject'; @@ -25,6 +26,8 @@ function getPrefComponent(type: string) { return ListPreference; case 'EditTextPreference': return EditTextPreference; + case 'MultiSelectListPreference': + return MultiSelectListPreference; default: return CheckBoxPreference; } @@ -47,10 +50,19 @@ export default function SourceConfigure() { .then((data) => setSourcePreferences(data)); }, [updateTriggerHolder]); + const convertToString = (position: number, value: any): string => { + switch (sourcePreferences[position].props.defaultValueType) { + case 'Set': + return JSON.stringify(value); + default: + return value.toString(); + } + }; + const updateValue = (position: number) => ( (value: any) => { client.post(`/api/v1/source/${sourceId}/preferences`, - JSON.stringify({ position, value: value.toString() })) + JSON.stringify({ position, value: convertToString(position, value) })) .then(() => triggerUpdate()); } ); diff --git a/src/typings.d.ts b/src/typings.d.ts index b7b1d270..6e0fc51d 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -180,11 +180,19 @@ interface TwoStatePreferenceProps extends PreferenceProps { type: 'Switch' | 'Checkbox' } interface CheckBoxPreferenceProps extends PreferenceProps {} + interface SwitchPreferenceCompatProps extends PreferenceProps {} + interface ListPreferenceProps extends PreferenceProps { entries: string[] entryValues: string[] } + +interface MultiSelectListPreferenceProps extends PreferenceProps { + entries: string[] + entryValues: string[] +} + interface EditTextPreferenceProps extends PreferenceProps { dialogTitle: string dialogMessage: string