feat: Support Additional Plugin Setting Types (Dropdown and Checkboxes)
This commit is contained in:
@@ -1,5 +1,51 @@
|
||||
import { FilterToValues, Filters } from './filterTypes';
|
||||
|
||||
export interface TextSetting {
|
||||
value: string;
|
||||
label: string;
|
||||
type?: 'Text';
|
||||
}
|
||||
|
||||
export interface SwitchSetting {
|
||||
value: boolean;
|
||||
label: string;
|
||||
type: 'Switch';
|
||||
}
|
||||
|
||||
export interface SelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface SelectSetting {
|
||||
value: string;
|
||||
label: string;
|
||||
type: 'Select';
|
||||
options: SelectOption[];
|
||||
}
|
||||
|
||||
export interface CheckboxOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface CheckboxGroupSetting {
|
||||
value: string[];
|
||||
label: string;
|
||||
type: 'CheckboxGroup';
|
||||
options: CheckboxOption[];
|
||||
}
|
||||
|
||||
export type PluginSetting =
|
||||
| TextSetting
|
||||
| SwitchSetting
|
||||
| SelectSetting
|
||||
| CheckboxGroupSetting;
|
||||
|
||||
export interface PluginSettings {
|
||||
[key: string]: PluginSetting;
|
||||
}
|
||||
|
||||
export interface NovelItem {
|
||||
id: undefined;
|
||||
name: string;
|
||||
@@ -69,7 +115,7 @@ export interface ImageRequestInit {
|
||||
export interface Plugin extends PluginItem {
|
||||
imageRequestInit: ImageRequestInit;
|
||||
filters?: Filters;
|
||||
pluginSettings: any;
|
||||
pluginSettings?: PluginSettings;
|
||||
popularNovels: (
|
||||
pageNo: number,
|
||||
options?: PopularNovelsOptions<Filters>,
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { TextInput } from 'react-native-paper';
|
||||
import { Button, Modal, SwitchItem } from '@components/index';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import { TextInput, Menu, overlay } from 'react-native-paper';
|
||||
import { Button, Modal, SwitchItem, Checkbox } from '@components/index';
|
||||
import { useTheme } from '@hooks/persisted';
|
||||
import { getString } from '@strings/translations';
|
||||
import { Storage } from '@plugins/helpers/storage';
|
||||
|
||||
interface PluginSetting {
|
||||
value: string;
|
||||
label: string;
|
||||
type?: 'Switch';
|
||||
}
|
||||
|
||||
interface PluginSettings {
|
||||
[key: string]: PluginSetting;
|
||||
}
|
||||
import MaterialCommunityIcons from '@react-native-vector-icons/material-design-icons';
|
||||
import { PluginSettings } from '@plugins/types';
|
||||
|
||||
interface SourceSettingsModal {
|
||||
visible: boolean;
|
||||
@@ -36,8 +28,9 @@ const SourceSettingsModal: React.FC<SourceSettingsModal> = ({
|
||||
const theme = useTheme();
|
||||
|
||||
const [formValues, setFormValues] = useState<
|
||||
Record<string, string | boolean>
|
||||
Record<string, string | boolean | string[]>
|
||||
>({});
|
||||
const [openMenus, setOpenMenus] = useState<Record<string, boolean>>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (pluginSettings) {
|
||||
@@ -66,13 +59,18 @@ const SourceSettingsModal: React.FC<SourceSettingsModal> = ({
|
||||
}
|
||||
}, [pluginSettings, pluginId]);
|
||||
|
||||
const handleChange = (key: string, value: string | boolean) => {
|
||||
const handleChange = (key: string, value: string | boolean | string[]) => {
|
||||
setFormValues(prevValues => ({
|
||||
...prevValues,
|
||||
[key]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const insertOrRemoveIntoArray = (array: string[], val: string): string[] =>
|
||||
array.indexOf(val) > -1
|
||||
? array.filter(ele => ele !== val)
|
||||
: [...array, val];
|
||||
|
||||
const handleSave = () => {
|
||||
const storage = new Storage(pluginId);
|
||||
Object.entries(formValues).forEach(([key, value]) => {
|
||||
@@ -112,6 +110,103 @@ const SourceSettingsModal: React.FC<SourceSettingsModal> = ({
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (setting?.type === 'Select') {
|
||||
const selectedOption = setting.options.find(
|
||||
opt => opt.value === formValues[key],
|
||||
);
|
||||
const isMenuOpen = !!openMenus[key];
|
||||
return (
|
||||
<View key={key} style={styles.selectContainer}>
|
||||
<Menu
|
||||
visible={isMenuOpen}
|
||||
contentStyle={{ backgroundColor: theme.surfaceVariant }}
|
||||
anchor={
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
setOpenMenus(prev => ({ ...prev, [key]: !prev[key] }))
|
||||
}
|
||||
>
|
||||
<TextInput
|
||||
mode="outlined"
|
||||
label={
|
||||
<Text
|
||||
style={{
|
||||
color: isMenuOpen ? theme.primary : theme.onSurface,
|
||||
backgroundColor: overlay(2, theme.surface),
|
||||
}}
|
||||
>
|
||||
{` ${setting.label} `}
|
||||
</Text>
|
||||
}
|
||||
value={selectedOption?.label || ''}
|
||||
editable={false}
|
||||
theme={{ colors: { background: 'transparent' } }}
|
||||
outlineColor={
|
||||
isMenuOpen ? theme.primary : theme.onSurface
|
||||
}
|
||||
textColor={isMenuOpen ? theme.primary : theme.onSurface}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
</Pressable>
|
||||
}
|
||||
onDismiss={() =>
|
||||
setOpenMenus(prev => ({ ...prev, [key]: false }))
|
||||
}
|
||||
>
|
||||
{setting.options.map(option => (
|
||||
<Menu.Item
|
||||
key={option.value}
|
||||
title={option.label}
|
||||
titleStyle={{ color: theme.onSurfaceVariant }}
|
||||
onPress={() => {
|
||||
handleChange(key, option.value);
|
||||
setOpenMenus(prev => ({ ...prev, [key]: false }));
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (setting?.type === 'CheckboxGroup') {
|
||||
const value = (formValues[key] || []) as string[];
|
||||
const isExpanded = !!openMenus[key];
|
||||
return (
|
||||
<View key={key}>
|
||||
<Pressable
|
||||
style={styles.checkboxHeader}
|
||||
onPress={() =>
|
||||
setOpenMenus(prev => ({ ...prev, [key]: !prev[key] }))
|
||||
}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>
|
||||
{setting.label}
|
||||
</Text>
|
||||
<MaterialCommunityIcons
|
||||
name={isExpanded ? 'chevron-up' : 'chevron-down'}
|
||||
color={theme.onSurface}
|
||||
size={24}
|
||||
/>
|
||||
</Pressable>
|
||||
{isExpanded &&
|
||||
setting.options.map(option => (
|
||||
<Checkbox
|
||||
key={option.value}
|
||||
label={option.label}
|
||||
theme={theme}
|
||||
status={value.includes(option.value)}
|
||||
onPress={() =>
|
||||
handleChange(
|
||||
key,
|
||||
insertOrRemoveIntoArray(value, option.value),
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TextInput
|
||||
key={key}
|
||||
@@ -161,4 +256,14 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 8,
|
||||
marginTop: 16,
|
||||
},
|
||||
selectContainer: {
|
||||
marginVertical: 8,
|
||||
},
|
||||
checkboxHeader: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user