From b53ec3352f8ce9084e32ddaa352526b39ec6003c Mon Sep 17 00:00:00 2001 From: Rajarshee Chatterjee Date: Wed, 28 Jan 2026 22:23:00 +0530 Subject: [PATCH] feat: Support Additional Plugin Setting Types (Dropdown and Checkboxes) --- src/plugins/types/index.ts | 48 ++++++- .../components/Modals/SourceSettings.tsx | 135 ++++++++++++++++-- 2 files changed, 167 insertions(+), 16 deletions(-) diff --git a/src/plugins/types/index.ts b/src/plugins/types/index.ts index 0f077170..250a8245 100644 --- a/src/plugins/types/index.ts +++ b/src/plugins/types/index.ts @@ -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, diff --git a/src/screens/browse/components/Modals/SourceSettings.tsx b/src/screens/browse/components/Modals/SourceSettings.tsx index 1b7a2db1..13c8ab15 100644 --- a/src/screens/browse/components/Modals/SourceSettings.tsx +++ b/src/screens/browse/components/Modals/SourceSettings.tsx @@ -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 = ({ const theme = useTheme(); const [formValues, setFormValues] = useState< - Record + Record >({}); + const [openMenus, setOpenMenus] = useState>({}); useEffect(() => { if (pluginSettings) { @@ -66,13 +59,18 @@ const SourceSettingsModal: React.FC = ({ } }, [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 = ({ /> ); } + if (setting?.type === 'Select') { + const selectedOption = setting.options.find( + opt => opt.value === formValues[key], + ); + const isMenuOpen = !!openMenus[key]; + return ( + + + setOpenMenus(prev => ({ ...prev, [key]: !prev[key] })) + } + > + + {` ${setting.label} `} + + } + value={selectedOption?.label || ''} + editable={false} + theme={{ colors: { background: 'transparent' } }} + outlineColor={ + isMenuOpen ? theme.primary : theme.onSurface + } + textColor={isMenuOpen ? theme.primary : theme.onSurface} + pointerEvents="none" + /> + + } + onDismiss={() => + setOpenMenus(prev => ({ ...prev, [key]: false })) + } + > + {setting.options.map(option => ( + { + handleChange(key, option.value); + setOpenMenus(prev => ({ ...prev, [key]: false })); + }} + /> + ))} + + + ); + } + if (setting?.type === 'CheckboxGroup') { + const value = (formValues[key] || []) as string[]; + const isExpanded = !!openMenus[key]; + return ( + + + setOpenMenus(prev => ({ ...prev, [key]: !prev[key] })) + } + android_ripple={{ color: theme.rippleColor }} + > + + {setting.label} + + + + {isExpanded && + setting.options.map(option => ( + + handleChange( + key, + insertOrRemoveIntoArray(value, option.value), + ) + } + /> + ))} + + ); + } return (