vd-plugins/plugins/Commands/settings.tsx

844 lines
27 KiB
TypeScript
Raw Normal View History

import { plugin } from "@vendetta";
import { storage } from "@vendetta/plugin";
import { useProxy } from "@vendetta/storage";
2025-10-01 16:18:11 +02:00
import { React, ReactNative as RN, stylesheet } from "@vendetta/metro/common";
import { findByProps } from "@vendetta/metro";
2025-10-01 16:28:57 +02:00
import { NavigationNative } from "@vendetta/metro/common";
2025-10-01 16:18:11 +02:00
import { semanticColors } from "@vendetta/ui";
import { getAssetIDByName } from "@vendetta/ui/assets";
import { Forms } from "@vendetta/ui/components";
import { alerts } from "@vendetta/ui";
const { ScrollView } = findByProps("ScrollView");
2025-10-01 16:24:21 +02:00
const { FormRow, FormSwitchRow } = Forms;
2025-10-01 16:36:23 +02:00
// Better Table Row Group Component
2025-10-01 16:24:21 +02:00
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>
);
}
2025-10-01 16:18:11 +02:00
// Header Component
function Header() {
const styles = stylesheet.createThemedStyleSheet({
container: {
flexDirection: "column",
alignItems: "center",
paddingVertical: 24,
paddingHorizontal: 16,
},
title: {
fontSize: 28,
fontWeight: "700",
color: semanticColors.TEXT_NORMAL,
marginBottom: 4,
},
subtitle: {
fontSize: 16,
fontWeight: "500",
color: semanticColors.TEXT_MUTED,
},
iconContainer: {
backgroundColor: semanticColors.BACKGROUND_SECONDARY,
borderRadius: 16,
padding: 12,
marginBottom: 16,
},
icon: {
width: 32,
height: 32,
tintColor: semanticColors.TEXT_NORMAL,
},
});
return (
<RN.View style={styles.container}>
<RN.View style={styles.iconContainer}>
<RN.Image
source={getAssetIDByName("SettingsIcon")}
style={styles.icon}
/>
</RN.View>
<RN.Text style={styles.title}>Commands</RN.Text>
<RN.Text style={styles.subtitle}>A collection of useful commands</RN.Text>
</RN.View>
);
}
2025-10-01 16:36:23 +02:00
// Facts Commands Settings Page
function FactsSettingsPage({ forceRerender }: { forceRerender: () => void }) {
2025-10-01 16:28:57 +02:00
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
});
return (
<RN.View style={styles.container}>
2025-10-01 16:36:23 +02:00
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="Fact Display Settings" icon={getAssetIDByName("SettingsIcon")}>
<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();
}}
/>
2025-10-01 16:28:57 +02:00
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
<BetterTableRowGroup title="Available Fact Commands" icon={getAssetIDByName("BookIcon")}>
<FormSwitchRow
label="/catfact"
subLabel="Get random cat facts"
leading={<FormRow.Icon source={getAssetIDByName("ic_cat")} />}
value={storage.enabledCommands?.catfact ?? true}
onValueChange={(v) => {
storage.enabledCommands.catfact = v;
storage.pendingRestart = true;
forceRerender();
}}
/>
<FormSwitchRow
label="/dogfact"
subLabel="Get random dog facts"
leading={<FormRow.Icon source={getAssetIDByName("ic_dog")} />}
value={storage.enabledCommands?.dogfact ?? true}
onValueChange={(v) => {
storage.enabledCommands.dogfact = v;
storage.pendingRestart = true;
forceRerender();
}}
/>
<FormSwitchRow
label="/useless"
subLabel="Get random useless facts"
leading={<FormRow.Icon source={getAssetIDByName("QuestionMarkIcon")} />}
value={storage.enabledCommands?.useless ?? true}
onValueChange={(v) => {
storage.enabledCommands.useless = v;
storage.pendingRestart = true;
forceRerender();
}}
/>
2025-10-01 16:28:57 +02:00
</BetterTableRowGroup>
</ScrollView>
</RN.View>
);
}
2025-10-01 16:36:23 +02:00
// Gary API Settings Page
2025-10-01 16:28:57 +02:00
function GaryAPIPage({ forceRerender }: { forceRerender: () => void }) {
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
optionContainer: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 16,
paddingHorizontal: 16,
backgroundColor: semanticColors.CARD_PRIMARY_BG,
borderRadius: 12,
marginHorizontal: 16,
marginVertical: 4,
},
selectedOption: {
2025-10-01 16:36:23 +02:00
backgroundColor: semanticColors.BRAND_500_ALPHA || `${semanticColors.BRAND_500}20`,
2025-10-01 16:28:57 +02:00
borderColor: semanticColors.BRAND_500,
borderWidth: 2,
},
normalOption: {
borderColor: semanticColors.BORDER_FAINT,
borderWidth: 1,
},
radioButton: {
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
borderColor: semanticColors.TEXT_MUTED,
alignItems: "center",
justifyContent: "center",
marginRight: 12,
},
selectedRadio: {
borderColor: semanticColors.BRAND_500,
},
radioInner: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: semanticColors.BRAND_500,
},
textContainer: {
flex: 1,
},
optionTitle: {
fontSize: 16,
fontWeight: "600",
color: semanticColors.TEXT_NORMAL,
},
optionDesc: {
fontSize: 14,
color: semanticColors.TEXT_MUTED,
marginTop: 2,
},
selectedText: {
color: semanticColors.BRAND_500,
},
2025-10-01 16:36:23 +02:00
infoText: {
fontSize: 14,
color: semanticColors.TEXT_MUTED,
marginBottom: 16,
textAlign: "center",
},
currentText: {
fontSize: 14,
color: semanticColors.TEXT_NORMAL,
textAlign: "center",
fontWeight: "600",
},
2025-10-01 16:28:57 +02:00
});
const options = [
{
value: "gary",
title: "Gary API",
desc: "Original Gary the cat images from api.garythe.cat",
icon: getAssetIDByName("ic_cat")
},
{
value: "catapi",
title: "Cat API",
desc: "Random cat pictures from thecatapi.com",
icon: getAssetIDByName("ic_cat")
},
{
value: "minker",
title: "Minker API",
desc: "Minky images from minky.materii.dev",
icon: getAssetIDByName("ImageIcon")
},
{
value: "goober",
title: "Goober API",
desc: "Goober images from api.garythe.cat/goober",
icon: getAssetIDByName("ImageIcon")
},
];
const currentSource = storage.garySettings?.imageSource || "gary";
return (
<RN.View style={styles.container}>
2025-10-01 16:36:23 +02:00
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="Gary Command Settings" icon={getAssetIDByName("SettingsIcon")}>
<FormSwitchRow
label="/gary"
subLabel="Send random Gary images to channel"
leading={<FormRow.Icon source={getAssetIDByName("ic_cat")} />}
value={storage.enabledCommands?.gary ?? true}
onValueChange={(v) => {
storage.enabledCommands.gary = v;
storage.pendingRestart = true;
forceRerender();
}}
/>
</BetterTableRowGroup>
<BetterTableRowGroup title="Image Source Selection" icon={getAssetIDByName("DownloadIcon")} padding={true}>
<RN.Text style={styles.infoText}>
2025-10-01 16:28:57 +02:00
Choose which API the /gary command should use to fetch images.
</RN.Text>
</BetterTableRowGroup>
{options.map((option) => {
const isSelected = currentSource === option.value;
return (
<RN.Pressable
key={option.value}
style={[
styles.optionContainer,
isSelected ? styles.selectedOption : styles.normalOption,
]}
onPress={() => {
2025-10-01 16:36:23 +02:00
console.log(`[Settings] Changing Gary API to: ${option.value}`);
2025-10-01 16:28:57 +02:00
storage.garySettings.imageSource = option.value;
forceRerender();
}}
>
<RN.View style={[
styles.radioButton,
isSelected && styles.selectedRadio,
]}>
{isSelected && <RN.View style={styles.radioInner} />}
</RN.View>
<RN.Image
source={option.icon}
style={{
width: 24,
height: 24,
tintColor: isSelected ? semanticColors.BRAND_500 : semanticColors.TEXT_MUTED,
marginRight: 12,
}}
/>
<RN.View style={styles.textContainer}>
<RN.Text style={[
styles.optionTitle,
isSelected && styles.selectedText,
]}>
{option.title}
</RN.Text>
<RN.Text style={styles.optionDesc}>
{option.desc}
</RN.Text>
</RN.View>
</RN.Pressable>
);
})}
2025-10-01 16:36:23 +02:00
<BetterTableRowGroup title="Current Selection" icon={getAssetIDByName("CheckmarkIcon")} padding={true}>
<RN.Text style={styles.currentText}>
2025-10-01 16:28:57 +02:00
Currently using: {
currentSource === "gary" ? "Gary API" :
currentSource === "catapi" ? "Cat API" :
currentSource === "minker" ? "Minker API" :
currentSource === "goober" ? "Goober API" : "Gary API"
}
</RN.Text>
</BetterTableRowGroup>
</ScrollView>
</RN.View>
);
}
2025-10-01 16:36:23 +02:00
// List Commands Settings Page
function ListSettingsPage({ forceRerender }: { forceRerender: () => void }) {
2025-10-01 16:18:11 +02:00
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
});
return (
2025-10-01 16:18:11 +02:00
<RN.View style={styles.container}>
2025-10-01 16:36:23 +02:00
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="List Display Settings" icon={getAssetIDByName("SettingsIcon")}>
2025-10-01 16:24:21 +02:00
<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();
}}
/>
2025-10-01 16:36:23 +02:00
</BetterTableRowGroup>
<BetterTableRowGroup title="Available List Commands" icon={getAssetIDByName("ListIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/plugin-list"
subLabel="List all installed plugins"
leading={<FormRow.Icon source={getAssetIDByName("PuzzlePieceIcon")} />}
value={storage.enabledCommands?.pluginList ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.pluginList = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
<FormSwitchRow
label="/theme-list"
subLabel="List all installed themes"
leading={<FormRow.Icon source={getAssetIDByName("PaintPaletteIcon")} />}
value={storage.enabledCommands?.themeList ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.themeList = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
</ScrollView>
</RN.View>
);
}
// Image Commands Settings Page
function ImageSettingsPage({ forceRerender }: { forceRerender: () => void }) {
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
});
2025-10-01 16:36:23 +02:00
return (
<RN.View style={styles.container}>
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="Image Commands" icon={getAssetIDByName("ImageIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/petpet"
subLabel="Create pet-pet GIF of a user"
leading={<FormRow.Icon source={getAssetIDByName("HandIcon")} />}
value={storage.enabledCommands?.petpet ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.petpet = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
<BetterTableRowGroup title="KonoChan Commands" icon={getAssetIDByName("ImageIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/konoself"
subLabel="Get random image from KonoChan (private)"
leading={<FormRow.Icon source={getAssetIDByName("EyeIcon")} />}
value={storage.enabledCommands?.konoself ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.konoself = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
<FormSwitchRow
label="/konosend"
subLabel="Send random image from KonoChan to channel"
leading={<FormRow.Icon source={getAssetIDByName("ImageIcon")} />}
value={storage.enabledCommands?.konosend ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.konosend = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
</ScrollView>
</RN.View>
);
}
// Other Commands Settings Page
function OtherSettingsPage({ forceRerender }: { forceRerender: () => void }) {
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
});
2025-10-01 16:18:11 +02:00
2025-10-01 16:36:23 +02:00
return (
<RN.View style={styles.container}>
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="Message Commands" icon={getAssetIDByName("ChatIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/firstmessage"
subLabel="Get the first message in a channel"
leading={<FormRow.Icon source={getAssetIDByName("ChatIcon")} />}
value={storage.enabledCommands?.firstmessage ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.firstmessage = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-09-30 19:03:33 +02:00
2025-10-01 16:36:23 +02:00
<BetterTableRowGroup title="System Commands" icon={getAssetIDByName("SettingsIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/sysinfo"
subLabel="Display system information"
leading={<FormRow.Icon source={getAssetIDByName("SettingsIcon")} />}
value={storage.enabledCommands?.sysinfo ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.sysinfo = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-10-01 16:18:11 +02:00
2025-10-01 16:36:23 +02:00
<BetterTableRowGroup title="Spotify Commands" icon={getAssetIDByName("SpotifyIcon")}>
2025-10-01 16:24:21 +02:00
<FormSwitchRow
label="/spotify track"
subLabel="Share your current Spotify track"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyTrack ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.spotifyTrack = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
<FormSwitchRow
label="/spotify album"
subLabel="Share your current track's album"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyAlbum ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.spotifyAlbum = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
<FormSwitchRow
label="/spotify artists"
subLabel="Share your current track's artists"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyArtists ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.spotifyArtists = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
<FormSwitchRow
label="/spotify cover"
subLabel="Share your current track's cover"
leading={<FormRow.Icon source={getAssetIDByName("SpotifyIcon")} />}
value={storage.enabledCommands?.spotifyCover ?? true}
2025-10-01 16:36:23 +02:00
onValueChange={(v) => {
storage.enabledCommands.spotifyCover = v;
storage.pendingRestart = true;
forceRerender();
}}
2025-10-01 16:24:21 +02:00
/>
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
</ScrollView>
</RN.View>
);
}
// Credits Page
function CreditsPage() {
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
creditItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 16,
backgroundColor: semanticColors.CARD_PRIMARY_BG,
borderRadius: 12,
marginHorizontal: 16,
marginVertical: 4,
},
avatar: {
width: 40,
height: 40,
borderRadius: 20,
marginRight: 12,
},
textContainer: {
flex: 1,
},
commandText: {
fontSize: 16,
fontWeight: "600",
color: semanticColors.TEXT_NORMAL,
},
authorText: {
fontSize: 14,
color: semanticColors.TEXT_MUTED,
marginTop: 2,
},
infoText: {
fontSize: 14,
color: semanticColors.TEXT_MUTED,
marginBottom: 16,
textAlign: "center",
},
versionText: {
fontSize: 14,
color: semanticColors.TEXT_NORMAL,
textAlign: "center",
fontWeight: "600",
lineHeight: 20,
},
});
const credits = [
{ command: "Facts Commands", author: "jdev082", avatar: "https://github.com/jdev082.png" },
{ command: "List Commands", author: "Kitomanari", avatar: "https://github.com/kitomanari.png" },
{ command: "PetPet Command", author: "wolfieeee", avatar: "https://github.com/wolfieeee.png" },
{ command: "KonoChan Commands", author: "btmc727 & Rico040", avatar: "https://github.com/btmc727.png" },
{ command: "FirstMessage Command", author: "sapphire", avatar: "https://github.com/sapphiredevs.png" },
{ command: "Sysinfo Command", author: "mugman", avatar: "https://github.com/mugmandev.png" },
{ command: "Spotify Commands", author: "Kitomanari", avatar: "https://github.com/kitomanari.png" },
{ command: "Gary Command", author: "Zach Orange", avatar: "https://github.com/zachorange.png" },
];
return (
<RN.View style={styles.container}>
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}>
<BetterTableRowGroup title="Plugin Authors" icon={getAssetIDByName("PeopleIcon")} padding={true}>
<RN.Text style={styles.infoText}>
Thanks to all the amazing developers who contributed to this plugin collection!
</RN.Text>
</BetterTableRowGroup>
2025-10-01 16:36:23 +02:00
{credits.map((credit, index) => (
<RN.View key={index} style={styles.creditItem}>
<RN.Image
source={{ uri: credit.avatar }}
style={styles.avatar}
/>
<RN.View style={styles.textContainer}>
<RN.Text style={styles.commandText}>{credit.command}</RN.Text>
<RN.Text style={styles.authorText}>by {credit.author}</RN.Text>
</RN.View>
</RN.View>
))}
<BetterTableRowGroup title="About" icon={getAssetIDByName("InfoIcon")} padding={true}>
<RN.Text style={styles.versionText}>
Commands Plugin Collection{'\n'}
Version 1.0.0{'\n'}
Made with ❤️ for the community
</RN.Text>
</BetterTableRowGroup>
</ScrollView>
</RN.View>
);
}
// Initialize storage with default values
if (!storage.factSettings) {
storage.factSettings = {
sendAsReply: true,
includeCitation: false,
};
}
if (!storage.listSettings) {
storage.listSettings = {
pluginListAlwaysDetailed: false,
themeListAlwaysDetailed: false,
};
}
if (!storage.garySettings) {
storage.garySettings = {
imageSource: "gary",
};
}
if (!storage.enabledCommands) {
storage.enabledCommands = {
catfact: true,
dogfact: true,
useless: true,
petpet: true,
pluginList: true,
themeList: true,
konoself: true,
konosend: true,
firstmessage: true,
sysinfo: true,
spotifyTrack: true,
spotifyAlbum: true,
spotifyArtists: true,
spotifyCover: true,
gary: true,
};
}
if (!storage.pendingRestart) {
storage.pendingRestart = false;
}
// Main Settings Component
export default function Settings() {
useProxy(storage);
const [rerender, forceRerender] = React.useReducer((x) => x + 1, 0);
const navigation = NavigationNative.useNavigation();
const styles = stylesheet.createThemedStyleSheet({
container: {
flex: 1,
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
},
});
// Check for pending restart when unmounting
React.useEffect(() => {
return () => {
if (storage.pendingRestart) {
storage.pendingRestart = false;
alerts.showConfirmationAlert({
title: "Restart Required",
content:
"You have made changes to commands. Please restart Discord to apply these changes.",
confirmText: "Okay",
cancelText: null,
});
}
};
}, []);
const navigateToPage = (title: string, component: React.ComponentType<any>) => {
navigation.push("VendettaCustomPage", {
title,
render: () => React.createElement(component, { forceRerender }),
});
};
return (
<RN.View style={styles.container}>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{ paddingBottom: 38 }}
showsVerticalScrollIndicator={false}
>
<Header />
{/* Command Categories */}
<BetterTableRowGroup title="Command Categories" icon={getAssetIDByName("FolderIcon")}>
<FormRow
label="Facts Commands"
subLabel="Cat facts, dog facts, and useless facts"
leading={<FormRow.Icon source={getAssetIDByName("BookIcon")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigateToPage("Facts Commands", FactsSettingsPage)}
/>
<FormRow
label="List Commands"
subLabel="Plugin lists and theme lists"
leading={<FormRow.Icon source={getAssetIDByName("ListIcon")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigateToPage("List Commands", ListSettingsPage)}
/>
<FormRow
label="Image Commands"
subLabel="PetPet, KonoChan, and image utilities"
leading={<FormRow.Icon source={getAssetIDByName("ImageIcon")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigateToPage("Image Commands", ImageSettingsPage)}
/>
<FormRow
label="Gary Commands"
subLabel={`Gary images - 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("ic_cat")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigateToPage("Gary Commands", GaryAPIPage)}
/>
<FormRow
label="Other Commands"
subLabel="System info, Spotify, and miscellaneous"
leading={<FormRow.Icon source={getAssetIDByName("MoreHorizontalIcon")} />}
trailing={<FormRow.Arrow />}
onPress={() => navigateToPage("Other Commands", OtherSettingsPage)}
/>
</BetterTableRowGroup>
{/* More Options */}
<BetterTableRowGroup title="More Options" icon={getAssetIDByName("SettingsIcon")}>
2025-10-01 16:28:57 +02:00
<FormRow
label="Credits"
subLabel="View plugin authors and contributors"
leading={<FormRow.Icon source={getAssetIDByName("PeopleIcon")} />}
trailing={<FormRow.Arrow />}
2025-10-01 16:36:23 +02:00
onPress={() => navigateToPage("Credits", CreditsPage)}
2025-10-01 16:28:57 +02:00
/>
2025-10-01 16:24:21 +02:00
</BetterTableRowGroup>
2025-09-27 20:15:20 +02:00
</ScrollView>
2025-10-01 16:18:11 +02:00
</RN.View>
);
}