import { storage } from "@vendetta/plugin"; import { useProxy } from "@vendetta/storage"; import { React, ReactNative as RN, stylesheet } from "@vendetta/metro/common"; import { NavigationNative } from "@vendetta/metro/common"; import { semanticColors } from "@vendetta/ui"; import { getAssetIDByName } from "@vendetta/ui/assets"; import { Forms } from "@vendetta/ui/components"; import { alerts } from "@vendetta/ui"; const { ScrollView } = RN; const { FormRow, FormSwitchRow } = Forms; // Initialize storage with default values - MOVED TO TOP storage.factSettings ??= { sendAsReply: true, includeCitation: false, }; storage.listSettings ??= { pluginListAlwaysDetailed: false, themeListAlwaysDetailed: false, }; storage.garySettings ??= { imageSource: "gary", }; 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, }; storage.pendingRestart ??= false; // Better Table Row Group Component 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 ( {title && ( {icon && ( )} {title.toUpperCase()} )} {padding ? ( {children} ) : children} ); } // 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 ( Commands A collection of useful commands ); } // Facts Commands Settings Page - FIXED with local force update function FactsSettingsPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); return ( } value={storage.factSettings.sendAsReply} onValueChange={(v) => { storage.factSettings.sendAsReply = v; }} /> } value={storage.factSettings.includeCitation} onValueChange={(v) => { storage.factSettings.includeCitation = v; }} /> } value={storage.enabledCommands.catfact} onValueChange={(v) => { storage.enabledCommands.catfact = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.dogfact} onValueChange={(v) => { storage.enabledCommands.dogfact = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.useless} onValueChange={(v) => { storage.enabledCommands.useless = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> ); } // Gary API Settings Page - FIXED with local force update function GaryAPIPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); const styles = stylesheet.createThemedStyleSheet({ container: { flex: 1, backgroundColor: semanticColors.BACKGROUND_PRIMARY, }, infoText: { fontSize: 14, color: semanticColors.TEXT_MUTED, marginBottom: 16, textAlign: "center", }, currentText: { fontSize: 14, color: semanticColors.TEXT_NORMAL, textAlign: "center", fontWeight: "600", }, }); const currentSource = storage.garySettings.imageSource; return ( } value={storage.enabledCommands.gary} onValueChange={(v) => { storage.enabledCommands.gary = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> Choose which API the /gary command should use to fetch images. } value={currentSource === "gary"} onValueChange={(v) => { if (v) { storage.garySettings.imageSource = "gary"; forceUpdate(); // Force this page to re-render } }} /> } value={currentSource === "catapi"} onValueChange={(v) => { if (v) { storage.garySettings.imageSource = "catapi"; forceUpdate(); // Force this page to re-render } }} /> } value={currentSource === "minker"} onValueChange={(v) => { if (v) { storage.garySettings.imageSource = "minker"; forceUpdate(); // Force this page to re-render } }} /> } value={currentSource === "goober"} onValueChange={(v) => { if (v) { storage.garySettings.imageSource = "goober"; forceUpdate(); // Force this page to re-render } }} /> Currently using: { currentSource === "gary" ? "Gary API" : currentSource === "catapi" ? "Cat API" : currentSource === "minker" ? "Minker API" : currentSource === "goober" ? "Goober API" : "Gary API" } ); } // List Settings Page - FIXED with local force update function ListSettingsPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); return ( } value={storage.listSettings.pluginListAlwaysDetailed} onValueChange={(v) => { storage.listSettings.pluginListAlwaysDetailed = v; }} /> } value={storage.listSettings.themeListAlwaysDetailed} onValueChange={(v) => { storage.listSettings.themeListAlwaysDetailed = v; }} /> } value={storage.enabledCommands.pluginList} onValueChange={(v) => { storage.enabledCommands.pluginList = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.themeList} onValueChange={(v) => { storage.enabledCommands.themeList = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> ); } // Image Settings Page - FIXED with local force update function ImageSettingsPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); return ( } value={storage.enabledCommands.petpet} onValueChange={(v) => { storage.enabledCommands.petpet = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.konoself} onValueChange={(v) => { storage.enabledCommands.konoself = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.konosend} onValueChange={(v) => { storage.enabledCommands.konosend = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> ); } // Spotify Settings Page - FIXED with local force update function SpotifySettingsPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); return ( } value={storage.enabledCommands.spotifyTrack} onValueChange={(v) => { storage.enabledCommands.spotifyTrack = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.spotifyAlbum} onValueChange={(v) => { storage.enabledCommands.spotifyAlbum = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.spotifyArtists} onValueChange={(v) => { storage.enabledCommands.spotifyArtists = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.spotifyCover} onValueChange={(v) => { storage.enabledCommands.spotifyCover = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> These commands allow you to share your current Spotify activity in Discord. Make sure you have Spotify connected to Discord for these commands to work properly. ); } // Other Settings Page - FIXED with local force update function OtherSettingsPage() { useProxy(storage); const [, forceUpdate] = React.useReducer((x) => x + 1, 0); return ( } value={storage.enabledCommands.firstmessage} onValueChange={(v) => { storage.enabledCommands.firstmessage = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> } value={storage.enabledCommands.sysinfo} onValueChange={(v) => { storage.enabledCommands.sysinfo = v; storage.pendingRestart = true; forceUpdate(); // Force this page to re-render }} /> ); } // Credits Page function CreditsPage() { const styles = stylesheet.createThemedStyleSheet({ container: { flex: 1, backgroundColor: semanticColors.BACKGROUND_PRIMARY, }, creditItem: { flexDirection: "row", alignItems: "center", paddingVertical: 16, paddingHorizontal: 20, backgroundColor: semanticColors.CARD_PRIMARY_BG, borderRadius: 12, marginHorizontal: 16, marginVertical: 6, shadowColor: semanticColors.BLACK, shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, }, avatar: { width: 48, height: 48, borderRadius: 24, marginRight: 16, backgroundColor: semanticColors.BACKGROUND_SECONDARY, }, textContainer: { flex: 1, }, commandText: { fontSize: 17, fontWeight: "600", color: semanticColors.TEXT_NORMAL, marginBottom: 4, }, authorText: { fontSize: 15, color: semanticColors.TEXT_MUTED, marginBottom: 2, }, linkText: { fontSize: 13, color: semanticColors.TEXT_BRAND, fontWeight: "500", }, infoText: { fontSize: 14, color: semanticColors.TEXT_MUTED, marginBottom: 20, textAlign: "center", lineHeight: 20, }, versionText: { fontSize: 15, color: semanticColors.TEXT_NORMAL, textAlign: "center", fontWeight: "600", lineHeight: 22, }, }); const credits = [ { command: "Facts Commands", author: "jdev082", avatar: "https://github.com/jdev082.png", github: "https://github.com/jdev082" }, { command: "List Commands", author: "Kitomanari", avatar: "https://github.com/Kitosight.png", github: "https://github.com/Kitosight" }, { command: "PetPet", author: "wolfieeee", avatar: "https://github.com/WolfPlugs.png", github: "https://github.com/WolfPlugs" }, { command: "KonoChan Commands", author: "btmc727 & Rico040", avatar: "https://github.com/OTKUSteyler.png", github: "https://github.com/OTKUSteyler" }, { command: "FirstMessage Command", author: "sapphire", avatar: "https://github.com/aeongdesu.png", github: "https://github.com/aeongdesu" }, { command: "Sysinfo Command", author: "mugman", avatar: "https://github.com/mugman174.png", github: "https://github.com/mugman174" }, { command: "Spotify Commands", author: "Kitomanari", avatar: "https://github.com/Kitosight.png", github: "https://github.com/Kitosight" }, { command: "Gary Command", author: "Zach Orange", avatar: "https://github.com/Zach11111.png", github: "https://github.com/Zach11111" }, ]; const handleProfilePress = (githubUrl: string) => { RN.Linking.openURL(githubUrl); }; return ( Thanks to this developers for creating such a nice plugins!{'\n'} Tap on any developer to visit their GitHub profile. {credits.map((credit, index) => ( handleProfilePress(credit.github)} android_ripple={{ color: semanticColors.ANDROID_RIPPLE, radius: 200 }} > {credit.command} by {credit.author} {credit.github.replace('https://github.com/', '@')} ))} Commands Plugin Collection{'\n'} Version 1.0.0 ); } // MAIN SETTINGS COMPONENT export default function Settings() { useProxy(storage); const navigation = NavigationNative.useNavigation(); // 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, }); } }; }, []); return (
{/* Command Categories */} } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Facts Commands", render: FactsSettingsPage, })} /> } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "List Commands", render: ListSettingsPage, })} /> } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Image Commands", render: ImageSettingsPage, })} /> } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Gary Commands", render: GaryAPIPage, })} /> } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Spotify Commands", render: SpotifySettingsPage, })} /> } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Other Commands", render: OtherSettingsPage, })} /> {/* More Options */} } trailing={} onPress={() => navigation.push("VendettaCustomPage", { title: "Credits", render: CreditsPage, })} /> ); }