Refactor settings page v2

This commit is contained in:
kmmiio99o 2025-10-01 16:24:21 +02:00
parent b1bffebfd9
commit bcde37c365

View file

@ -16,6 +16,76 @@ const { TableRowGroup, TableSwitchRow, Stack, TableRow } = findByProps(
"TableRow",
);
const { FormRow, FormSwitchRow } = Forms;
// Better Table Row Group Component (inspired by nexpid's styling)
function BetterTableRowGroup({
title,
icon,
children,
padding = false,
}: React.PropsWithChildren<{
title?: string;
icon?: number;
padding?: boolean;
}>) {
const styles = stylesheet.createThemedStyleSheet({
main: {
backgroundColor: semanticColors.CARD_PRIMARY_BG,
borderColor: semanticColors.BORDER_FAINT,
borderWidth: 1,
borderRadius: 16,
overflow: "hidden",
flex: 1,
},
titleContainer: {
marginBottom: 8,
marginHorizontal: 0,
marginTop: 8,
gap: 4,
flexDirection: "row",
alignItems: "center",
},
icon: {
width: 16,
height: 16,
marginTop: 1.5,
tintColor: semanticColors.TEXT_MUTED,
},
titleText: {
fontSize: 14,
fontWeight: "600",
color: semanticColors.TEXT_MUTED,
},
});
return (
<RN.View style={{ marginHorizontal: 16, marginTop: 16 }}>
{title && (
<RN.View style={styles.titleContainer}>
{icon && (
<RN.Image
style={styles.icon}
source={icon}
resizeMode="cover"
/>
)}
<RN.Text style={styles.titleText}>
{title.toUpperCase()}
</RN.Text>
</RN.View>
)}
<RN.View style={styles.main}>
{padding ? (
<RN.View style={{ paddingHorizontal: 16, paddingVertical: 16 }}>
{children}
</RN.View>
) : children}
</RN.View>
</RN.View>
);
}
// Header Component
function Header() {
const styles = stylesheet.createThemedStyleSheet({
@ -63,119 +133,6 @@ function Header() {
);
}
// Gary API Selection Component
function GaryAPISelection({ forceRerender }: { forceRerender: () => void }) {
const styles = stylesheet.createThemedStyleSheet({
container: {
backgroundColor: semanticColors.BACKGROUND_SECONDARY,
borderRadius: 12,
marginHorizontal: 16,
marginVertical: 8,
padding: 16,
},
title: {
fontSize: 18,
fontWeight: "600",
color: semanticColors.TEXT_NORMAL,
marginBottom: 12,
},
optionContainer: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 8,
borderRadius: 8,
marginVertical: 2,
},
selectedOption: {
backgroundColor: semanticColors.BACKGROUND_MODIFIER_SELECTED,
},
optionText: {
fontSize: 16,
fontWeight: "500",
marginLeft: 12,
flex: 1,
},
selectedText: {
color: semanticColors.TEXT_BRAND,
},
normalText: {
color: semanticColors.TEXT_NORMAL,
},
radioButton: {
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: semanticColors.TEXT_MUTED,
alignItems: "center",
justifyContent: "center",
},
selectedRadio: {
borderColor: semanticColors.TEXT_BRAND,
},
radioInner: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: semanticColors.TEXT_BRAND,
},
});
const options = [
{ value: "gary", label: "Gary API", desc: "Original Gary cat images" },
{ value: "catapi", label: "Cat API", desc: "Random cat pictures" },
{ value: "minker", label: "Minker API", desc: "Minky images" },
{ value: "goober", label: "Goober API", desc: "Goober images" },
];
const currentSource = storage.garySettings?.imageSource || "gary";
return (
<RN.View style={styles.container}>
<RN.Text style={styles.title}>Gary Image Source</RN.Text>
{options.map((option) => {
const isSelected = currentSource === option.value;
return (
<RN.Pressable
key={option.value}
style={[
styles.optionContainer,
isSelected && styles.selectedOption,
]}
onPress={() => {
storage.garySettings.imageSource = option.value;
forceRerender();
}}
>
<RN.View style={[
styles.radioButton,
isSelected && styles.selectedRadio,
]}>
{isSelected && <RN.View style={styles.radioInner} />}
</RN.View>
<RN.View style={{ flex: 1, marginLeft: 12 }}>
<RN.Text style={[
styles.optionText,
isSelected ? styles.selectedText : styles.normalText,
]}>
{option.label}
</RN.Text>
<RN.Text style={{
fontSize: 14,
color: semanticColors.TEXT_MUTED,
marginTop: 2,
}}>
{option.desc}
</RN.Text>
</RN.View>
</RN.Pressable>
);
})}
</RN.View>
);
}
// Initialize storage with default values
if (!storage.factSettings) {
storage.factSettings = {
@ -257,6 +214,50 @@ export default function Settings() {
forceRerender();
};
const showGarySourceSelection = () => {
alerts.showConfirmationAlert({
title: "Choose Gary Image Source",
content: "Select an image source for the Gary command:",
confirmText: "Gary API",
cancelText: "Other Options",
confirmColor: "brand",
onConfirm: () => {
storage.garySettings.imageSource = "gary";
forceRerender();
},
onCancel: () => {
alerts.showConfirmationAlert({
title: "Choose Image Source",
content: "Select from remaining options:",
confirmText: "Cat API",
cancelText: "More Options",
confirmColor: "brand",
onConfirm: () => {
storage.garySettings.imageSource = "catapi";
forceRerender();
},
onCancel: () => {
alerts.showConfirmationAlert({
title: "Choose Image Source",
content: "Select from final options:",
confirmText: "Minker API",
cancelText: "Goober API",
confirmColor: "brand",
onConfirm: () => {
storage.garySettings.imageSource = "minker";
forceRerender();
},
onCancel: () => {
storage.garySettings.imageSource = "goober";
forceRerender();
},
});
},
});
},
});
};
return (
<RN.View style={styles.container}>
<ScrollView
@ -266,195 +267,238 @@ export default function Settings() {
>
<Header />
<Stack spacing={8}>
{/* Facts Commands */}
<TableRowGroup title="Facts Commands">
<TableSwitchRow
label="Send as Reply"
subLabel="Send facts as a reply to the command message"
value={storage.factSettings?.sendAsReply ?? true}
onValueChange={(v: boolean) => {
storage.factSettings.sendAsReply = v;
forceRerender();
}}
/>
<TableSwitchRow
label="Include Source Citation"
subLabel="Include the source of facts when available"
value={storage.factSettings?.includeCitation ?? false}
onValueChange={(v: boolean) => {
storage.factSettings.includeCitation = v;
forceRerender();
}}
/>
<TableSwitchRow
label="/catfact"
subLabel="Get random cat facts"
value={storage.enabledCommands?.catfact ?? true}
onValueChange={(v) => handleCommandToggle("catfact", v)}
/>
<TableSwitchRow
label="/dogfact"
subLabel="Get random dog facts"
value={storage.enabledCommands?.dogfact ?? true}
onValueChange={(v) => handleCommandToggle("dogfact", v)}
/>
<TableSwitchRow
label="/useless"
subLabel="Get random useless facts"
value={storage.enabledCommands?.useless ?? true}
onValueChange={(v) => handleCommandToggle("useless", v)}
/>
</TableRowGroup>
{/* Facts Commands */}
<BetterTableRowGroup
title="Facts Commands"
icon={getAssetIDByName("BookIcon")}
>
<FormSwitchRow
label="Send as Reply"
subLabel="Send facts as a reply to the command message"
leading={<FormRow.Icon source={getAssetIDByName("ReplyIcon")} />}
value={storage.factSettings?.sendAsReply ?? true}
onValueChange={(v: boolean) => {
storage.factSettings.sendAsReply = v;
forceRerender();
}}
/>
<FormSwitchRow
label="Include Source Citation"
subLabel="Include the source of facts when available"
leading={<FormRow.Icon source={getAssetIDByName("LinkIcon")} />}
value={storage.factSettings?.includeCitation ?? false}
onValueChange={(v: boolean) => {
storage.factSettings.includeCitation = v;
forceRerender();
}}
/>
<FormSwitchRow
label="/catfact"
subLabel="Get random cat facts"
leading={<FormRow.Icon source={getAssetIDByName("ic_cat")} />}
value={storage.enabledCommands?.catfact ?? true}
onValueChange={(v) => handleCommandToggle("catfact", v)}
/>
<FormSwitchRow
label="/dogfact"
subLabel="Get random dog facts"
leading={<FormRow.Icon source={getAssetIDByName("ic_dog")} />}
value={storage.enabledCommands?.dogfact ?? true}
onValueChange={(v) => handleCommandToggle("dogfact", v)}
/>
<FormSwitchRow
label="/useless"
subLabel="Get random useless facts"
leading={<FormRow.Icon source={getAssetIDByName("QuestionMarkIcon")} />}
value={storage.enabledCommands?.useless ?? true}
onValueChange={(v) => handleCommandToggle("useless", v)}
/>
</BetterTableRowGroup>
{/* List Commands */}
<TableRowGroup title="List Commands">
<TableSwitchRow
label="Always Send Detailed Plugin List"
subLabel="Always use detailed mode when listing plugins"
value={storage.listSettings?.pluginListAlwaysDetailed ?? false}
onValueChange={(v: boolean) => {
storage.listSettings.pluginListAlwaysDetailed = v;
forceRerender();
}}
/>
<TableSwitchRow
label="Always Send Detailed Theme List"
subLabel="Always use detailed mode when listing themes"
value={storage.listSettings?.themeListAlwaysDetailed ?? false}
onValueChange={(v: boolean) => {
storage.listSettings.themeListAlwaysDetailed = v;
forceRerender();
}}
/>
<TableSwitchRow
label="/plugin-list"
subLabel="List all installed plugins"
value={storage.enabledCommands?.pluginList ?? true}
onValueChange={(v) => handleCommandToggle("pluginList", v)}
/>
<TableSwitchRow
label="/theme-list"
subLabel="List all installed themes"
value={storage.enabledCommands?.themeList ?? true}
onValueChange={(v) => handleCommandToggle("themeList", v)}
/>
</TableRowGroup>
{/* List Commands */}
<BetterTableRowGroup
title="List Commands"
icon={getAssetIDByName("ListIcon")}
>
<FormSwitchRow
label="Always Send Detailed Plugin List"
subLabel="Always use detailed mode when listing plugins"
leading={<FormRow.Icon source={getAssetIDByName("PuzzlePieceIcon")} />}
value={storage.listSettings?.pluginListAlwaysDetailed ?? false}
onValueChange={(v: boolean) => {
storage.listSettings.pluginListAlwaysDetailed = v;
forceRerender();
}}
/>
<FormSwitchRow
label="Always Send Detailed Theme List"
subLabel="Always use detailed mode when listing themes"
leading={<FormRow.Icon source={getAssetIDByName("PaintPaletteIcon")} />}
value={storage.listSettings?.themeListAlwaysDetailed ?? false}
onValueChange={(v: boolean) => {
storage.listSettings.themeListAlwaysDetailed = v;
forceRerender();
}}
/>
<FormSwitchRow
label="/plugin-list"
subLabel="List all installed plugins"
leading={<FormRow.Icon source={getAssetIDByName("PuzzlePieceIcon")} />}
value={storage.enabledCommands?.pluginList ?? true}
onValueChange={(v) => handleCommandToggle("pluginList", v)}
/>
<FormSwitchRow
label="/theme-list"
subLabel="List all installed themes"
leading={<FormRow.Icon source={getAssetIDByName("PaintPaletteIcon")} />}
value={storage.enabledCommands?.themeList ?? true}
onValueChange={(v) => handleCommandToggle("themeList", v)}
/>
</BetterTableRowGroup>
{/* Image Commands */}
<TableRowGroup title="Petpet Commands">
<TableSwitchRow
label="/petpet"
subLabel="Create pet-pet GIF of a user"
value={storage.enabledCommands?.petpet ?? true}
onValueChange={(v) => handleCommandToggle("petpet", v)}
/>
</TableRowGroup>
{/* Image Commands */}
<BetterTableRowGroup
title="Image Commands"
icon={getAssetIDByName("ImageIcon")}
>
<FormSwitchRow
label="/petpet"
subLabel="Create pet-pet GIF of a user"
leading={<FormRow.Icon source={getAssetIDByName("HandIcon")} />}
value={storage.enabledCommands?.petpet ?? true}
onValueChange={(v) => handleCommandToggle("petpet", v)}
/>
</BetterTableRowGroup>
{/* KonoChan Commands */}
<TableRowGroup title="KonoChan Commands">
<TableSwitchRow
label="/konoself"
subLabel="Get random image from KonoChan (private)"
value={storage.enabledCommands?.konoself ?? true}
onValueChange={(v) => handleCommandToggle("konoself", v)}
/>
<TableSwitchRow
label="/konosend"
subLabel="Send random image from KonoChan to channel"
value={storage.enabledCommands?.konosend ?? true}
onValueChange={(v) => handleCommandToggle("konosend", v)}
/>
</TableRowGroup>
{/* Gary Commands */}
<BetterTableRowGroup
title="Gary Commands"
icon={getAssetIDByName("ic_cat")}
>
<FormSwitchRow
label="/gary"
subLabel="Send random Gary images to channel"
leading={<FormRow.Icon source={getAssetIDByName("ic_cat")} />}
value={storage.enabledCommands?.gary ?? true}
onValueChange={(v) => handleCommandToggle("gary", v)}
/>
<FormRow
label="Gary Image Source"
subLabel={`Current: ${storage.garySettings?.imageSource === "gary" ? "Gary API" :
storage.garySettings?.imageSource === "catapi" ? "Cat API" :
storage.garySettings?.imageSource === "minker" ? "Minker API" :
storage.garySettings?.imageSource === "goober" ? "Goober API" : "Gary API"}`}
leading={<FormRow.Icon source={getAssetIDByName("DownloadIcon")} />}
trailing={<FormRow.Arrow />}
onPress={showGarySourceSelection}
/>
</BetterTableRowGroup>
{/* Message Commands */}
<TableRowGroup title="Message Commands">
<TableSwitchRow
label="/firstmessage"
subLabel="Get the first message in a channel"
value={storage.enabledCommands?.firstmessage ?? true}
onValueChange={(v) => handleCommandToggle("firstmessage", v)}
/>
</TableRowGroup>
{/* KonoChan Commands */}
<BetterTableRowGroup
title="KonoChan Commands"
icon={getAssetIDByName("ImageIcon")}
>
<FormSwitchRow
label="/konoself"
subLabel="Get random image from KonoChan (private)"
leading={<FormRow.Icon source={getAssetIDByName("EyeIcon")} />}
value={storage.enabledCommands?.konoself ?? true}
onValueChange={(v) => handleCommandToggle("konoself", v)}
/>
<FormSwitchRow
label="/konosend"
subLabel="Send random image from KonoChan to channel"
leading={<FormRow.Icon source={getAssetIDByName("ImageIcon")} />}
value={storage.enabledCommands?.konosend ?? true}
onValueChange={(v) => handleCommandToggle("konosend", v)}
/>
</BetterTableRowGroup>
{/* System Commands */}
<TableRowGroup title="System Commands">
<TableSwitchRow
label="/sysinfo"
subLabel="Display system information"
value={storage.enabledCommands?.sysinfo ?? true}
onValueChange={(v) => handleCommandToggle("sysinfo", v)}
/>
</TableRowGroup>
{/* Message Commands */}
<BetterTableRowGroup
title="Message Commands"
icon={getAssetIDByName("ChatIcon")}
>
<FormSwitchRow
label="/firstmessage"
subLabel="Get the first message in a channel"
leading={<FormRow.Icon source={getAssetIDByName("ChatIcon")} />}
value={storage.enabledCommands?.firstmessage ?? true}
onValueChange={(v) => handleCommandToggle("firstmessage", v)}
/>
</BetterTableRowGroup>
{/* Spotify Commands */}
<TableRowGroup title="Spotify Commands">
<TableSwitchRow
label="/spotify track"
subLabel="Share your current Spotify track"
value={storage.enabledCommands?.spotifyTrack ?? true}
onValueChange={(v) => handleCommandToggle("spotifyTrack", v)}
/>
<TableSwitchRow
label="/spotify album"
subLabel="Share your current track's album"
value={storage.enabledCommands?.spotifyAlbum ?? true}
onValueChange={(v) => handleCommandToggle("spotifyAlbum", v)}
/>
<TableSwitchRow
label="/spotify artists"
subLabel="Share your current track's artists"
value={storage.enabledCommands?.spotifyArtists ?? true}
onValueChange={(v) => handleCommandToggle("spotifyArtists", v)}
/>
<TableSwitchRow
label="/spotify cover"
subLabel="Share your current track's cover"
value={storage.enabledCommands?.spotifyCover ?? true}
onValueChange={(v) => handleCommandToggle("spotifyCover", v)}
/>
</TableRowGroup>
{/* System Commands */}
<BetterTableRowGroup
title="System Commands"
icon={getAssetIDByName("SettingsIcon")}
>
<FormSwitchRow
label="/sysinfo"
subLabel="Display system information"
leading={<FormRow.Icon source={getAssetIDByName("SettingsIcon")} />}
value={storage.enabledCommands?.sysinfo ?? true}
onValueChange={(v) => handleCommandToggle("sysinfo", v)}
/>
</BetterTableRowGroup>
{/* Gary Commands */}
<TableRowGroup title="Gary Commands">
<TableSwitchRow
label="/gary"
subLabel="Send random Gary images to channel"
value={storage.enabledCommands?.gary ?? true}
onValueChange={(v) => handleCommandToggle("gary", v)}
/>
</TableRowGroup>
</Stack>
{/* Spotify Commands */}
<BetterTableRowGroup
title="Spotify Commands"
icon={getAssetIDByName("SpotifyIcon")}
>
<FormSwitchRow
label="/spotify track"
subLabel="Share your current Spotify track"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyTrack ?? true}
onValueChange={(v) => handleCommandToggle("spotifyTrack", v)}
/>
<FormSwitchRow
label="/spotify album"
subLabel="Share your current track's album"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyAlbum ?? true}
onValueChange={(v) => handleCommandToggle("spotifyAlbum", v)}
/>
<FormSwitchRow
label="/spotify artists"
subLabel="Share your current track's artists"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyArtists ?? true}
onValueChange={(v) => handleCommandToggle("spotifyArtists", v)}
/>
<FormSwitchRow
label="/spotify cover"
subLabel="Share your current track's cover"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyCover ?? true}
onValueChange={(v) => handleCommandToggle("spotifyCover", v)}
/>
</BetterTableRowGroup>
{/* Custom Gary API Selection */}
<GaryAPISelection forceRerender={forceRerender} />
<RN.View style={styles.spacing} />
<Stack spacing={8}>
{/* Credits */}
<TableRowGroup title="Credits">
<TableRow label="Facts Commands" subLabel="by jdev082" />
<TableRow label="List Commands" subLabel="by Kitomanari" />
<TableRow label="PetPet Command" subLabel="by wolfieeee" />
<TableRow
label="KonoChan Commands"
subLabel="by btmc727 & Rico040"
/>
<TableRow label="FirstMessage Command" subLabel="by sapphire" />
<TableRow label="Sysinfo Command" subLabel="by mugman" />
<TableRow label="Spotify Commands" subLabel="by Kitomanari" />
<TableRow label="Gary Command" subLabel="by Zach Orange" />
</TableRowGroup>
{/* About */}
<TableRowGroup title="About">
<TableRow
label="Commands"
subLabel="A collection of commands"
/>
</TableRowGroup>
</Stack>
{/* Credits */}
<BetterTableRowGroup
title="Credits"
icon={getAssetIDByName("PeopleIcon")}
padding={true}
>
<RN.Text style={{
fontSize: 14,
color: semanticColors.TEXT_MUTED,
lineHeight: 20
}}>
Facts Commands by jdev082{'\n'}
List Commands by Kitomanari{'\n'}
PetPet Command by wolfieeee{'\n'}
KonoChan Commands by btmc727 & Rico040{'\n'}
FirstMessage Command by sapphire{'\n'}
Sysinfo Command by mugman{'\n'}
Spotify Commands by Kitomanari{'\n'}
Gary Command by Zach Orange
</RN.Text>
</BetterTableRowGroup>
<RN.View style={styles.spacing} />
</ScrollView>