2025-09-27 20:10:37 +02:00
|
|
|
|
import { plugin } from "@vendetta";
|
2025-09-27 21:22:17 +02:00
|
|
|
|
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";
|
2025-09-27 20:10:37 +02:00
|
|
|
|
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";
|
2025-09-27 21:37:28 +02:00
|
|
|
|
import { alerts } from "@vendetta/ui";
|
2025-09-27 19:17:06 +02:00
|
|
|
|
|
2025-09-27 20:10:37 +02:00
|
|
|
|
const { ScrollView } = findByProps("ScrollView");
|
2025-09-27 20:44:51 +02:00
|
|
|
|
const { TableRowGroup, TableSwitchRow, Stack, TableRow } = findByProps(
|
2025-09-27 20:10:37 +02:00
|
|
|
|
"TableSwitchRow",
|
|
|
|
|
|
"TableRowGroup",
|
|
|
|
|
|
"Stack",
|
2025-09-27 20:44:51 +02:00
|
|
|
|
"TableRow",
|
2025-09-27 20:10:37 +02:00
|
|
|
|
);
|
2025-09-27 19:40:15 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
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>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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:28:57 +02:00
|
|
|
|
// Credits Page Component
|
|
|
|
|
|
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,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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 }}
|
|
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
|
|
>
|
|
|
|
|
|
<BetterTableRowGroup
|
|
|
|
|
|
title="Plugin Authors"
|
|
|
|
|
|
icon={getAssetIDByName("PeopleIcon")}
|
|
|
|
|
|
padding={true}
|
|
|
|
|
|
>
|
|
|
|
|
|
<RN.Text style={{
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
color: semanticColors.TEXT_MUTED,
|
|
|
|
|
|
marginBottom: 16,
|
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
|
}}>
|
|
|
|
|
|
Thanks to all the amazing developers who contributed to this plugin collection!
|
|
|
|
|
|
</RN.Text>
|
|
|
|
|
|
</BetterTableRowGroup>
|
|
|
|
|
|
|
|
|
|
|
|
{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={{
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
color: semanticColors.TEXT_MUTED,
|
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
|
lineHeight: 20,
|
|
|
|
|
|
}}>
|
|
|
|
|
|
Commands Plugin Collection{'\n'}
|
|
|
|
|
|
Version 1.0.0{'\n'}
|
|
|
|
|
|
Made with ❤️ for the community
|
|
|
|
|
|
</RN.Text>
|
|
|
|
|
|
</BetterTableRowGroup>
|
|
|
|
|
|
</ScrollView>
|
|
|
|
|
|
</RN.View>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Gary API Settings Page Component
|
|
|
|
|
|
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: {
|
|
|
|
|
|
backgroundColor: semanticColors.BRAND_500_ALPHA,
|
|
|
|
|
|
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,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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}>
|
|
|
|
|
|
<ScrollView
|
|
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
|
contentContainerStyle={{ paddingVertical: 16, paddingBottom: 38 }}
|
|
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
|
|
>
|
|
|
|
|
|
<BetterTableRowGroup
|
|
|
|
|
|
title="Image Source Selection"
|
|
|
|
|
|
icon={getAssetIDByName("DownloadIcon")}
|
|
|
|
|
|
padding={true}
|
|
|
|
|
|
>
|
|
|
|
|
|
<RN.Text style={{
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
color: semanticColors.TEXT_MUTED,
|
|
|
|
|
|
marginBottom: 16,
|
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
|
}}>
|
|
|
|
|
|
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={() => {
|
|
|
|
|
|
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>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
|
|
|
|
|
|
<BetterTableRowGroup
|
|
|
|
|
|
title="Current Selection"
|
|
|
|
|
|
icon={getAssetIDByName("CheckmarkIcon")}
|
|
|
|
|
|
padding={true}
|
|
|
|
|
|
>
|
|
|
|
|
|
<RN.Text style={{
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
color: semanticColors.TEXT_NORMAL,
|
|
|
|
|
|
textAlign: "center",
|
|
|
|
|
|
fontWeight: "600",
|
|
|
|
|
|
}}>
|
|
|
|
|
|
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-09-27 21:22:17 +02:00
|
|
|
|
// Initialize storage with default values
|
2025-09-27 20:15:20 +02:00
|
|
|
|
if (!storage.factSettings) {
|
|
|
|
|
|
storage.factSettings = {
|
|
|
|
|
|
sendAsReply: true,
|
|
|
|
|
|
includeCitation: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!storage.listSettings) {
|
|
|
|
|
|
storage.listSettings = {
|
|
|
|
|
|
pluginListAlwaysDetailed: false,
|
|
|
|
|
|
themeListAlwaysDetailed: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-09-27 19:17:06 +02:00
|
|
|
|
|
2025-10-01 15:41:01 +02:00
|
|
|
|
if (!storage.garySettings) {
|
|
|
|
|
|
storage.garySettings = {
|
2025-10-01 16:18:11 +02:00
|
|
|
|
imageSource: "gary",
|
2025-10-01 15:41:01 +02:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 20:30:21 +02:00
|
|
|
|
if (!storage.enabledCommands) {
|
|
|
|
|
|
storage.enabledCommands = {
|
|
|
|
|
|
catfact: true,
|
|
|
|
|
|
dogfact: true,
|
|
|
|
|
|
useless: true,
|
|
|
|
|
|
petpet: true,
|
|
|
|
|
|
pluginList: true,
|
|
|
|
|
|
themeList: true,
|
|
|
|
|
|
konoself: true,
|
|
|
|
|
|
konosend: true,
|
2025-09-27 23:19:06 +02:00
|
|
|
|
firstmessage: true,
|
2025-09-28 23:45:17 +02:00
|
|
|
|
sysinfo: true,
|
2025-09-30 19:03:33 +02:00
|
|
|
|
spotifyTrack: true,
|
|
|
|
|
|
spotifyAlbum: true,
|
|
|
|
|
|
spotifyArtists: true,
|
|
|
|
|
|
spotifyCover: true,
|
2025-10-01 15:41:01 +02:00
|
|
|
|
gary: true,
|
2025-09-27 20:30:21 +02:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 20:44:51 +02:00
|
|
|
|
if (!storage.pendingRestart) {
|
|
|
|
|
|
storage.pendingRestart = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 16:28:57 +02:00
|
|
|
|
// Main Settings Component
|
2025-09-27 20:10:37 +02:00
|
|
|
|
export default function Settings() {
|
2025-09-27 20:15:20 +02:00
|
|
|
|
useProxy(storage);
|
|
|
|
|
|
const [rerender, forceRerender] = React.useReducer((x) => x + 1, 0);
|
2025-10-01 16:28:57 +02:00
|
|
|
|
const navigation = NavigationNative.useNavigation();
|
2025-09-27 19:17:06 +02:00
|
|
|
|
|
2025-10-01 16:18:11 +02:00
|
|
|
|
const styles = stylesheet.createThemedStyleSheet({
|
|
|
|
|
|
container: {
|
|
|
|
|
|
flex: 1,
|
|
|
|
|
|
backgroundColor: semanticColors.BACKGROUND_PRIMARY,
|
|
|
|
|
|
},
|
|
|
|
|
|
spacing: {
|
|
|
|
|
|
height: 16,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-09-27 21:22:17 +02:00
|
|
|
|
// Check for pending restart when unmounting
|
2025-09-27 20:44:51 +02:00
|
|
|
|
React.useEffect(() => {
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
if (storage.pendingRestart) {
|
2025-09-27 21:08:38 +02:00
|
|
|
|
storage.pendingRestart = false;
|
2025-09-27 21:37:28 +02:00
|
|
|
|
alerts.showConfirmationAlert({
|
|
|
|
|
|
title: "Restart Required",
|
|
|
|
|
|
content:
|
|
|
|
|
|
"You have made changes to commands. Please restart Discord to apply these changes.",
|
|
|
|
|
|
confirmText: "Okay",
|
|
|
|
|
|
cancelText: null,
|
|
|
|
|
|
});
|
2025-09-27 20:44:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2025-09-27 20:30:21 +02:00
|
|
|
|
const handleCommandToggle = (commandName: string, value: boolean) => {
|
2025-09-27 20:44:51 +02:00
|
|
|
|
storage.enabledCommands[commandName] = value;
|
|
|
|
|
|
storage.pendingRestart = true;
|
2025-09-27 20:30:21 +02:00
|
|
|
|
forceRerender();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-10-01 16:28:57 +02:00
|
|
|
|
const navigateToCredits = () => {
|
|
|
|
|
|
navigation.push("VendettaCustomPage", {
|
|
|
|
|
|
title: "Credits",
|
|
|
|
|
|
render: () => <CreditsPage />,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const navigateToGaryAPI = () => {
|
|
|
|
|
|
navigation.push("VendettaCustomPage", {
|
|
|
|
|
|
title: "Gary API Settings",
|
|
|
|
|
|
render: () => <GaryAPIPage forceRerender={forceRerender} />,
|
2025-10-01 16:24:21 +02:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-27 19:40:15 +02:00
|
|
|
|
return (
|
2025-10-01 16:18:11 +02:00
|
|
|
|
<RN.View style={styles.container}>
|
2025-09-27 21:22:17 +02:00
|
|
|
|
<ScrollView
|
|
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
|
contentContainerStyle={{ paddingBottom: 38 }}
|
2025-10-01 16:18:11 +02:00
|
|
|
|
showsVerticalScrollIndicator={false}
|
2025-09-27 21:22:17 +02:00
|
|
|
|
>
|
2025-10-01 16:18:11 +02:00
|
|
|
|
<Header />
|
|
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-09-27 20:10:37 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-09-27 23:19:06 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-09-28 23:45:17 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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
|
2025-10-01 16:28:57 +02:00
|
|
|
|
label="Gary API Settings"
|
2025-10-01 16:24:21 +02:00
|
|
|
|
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 />}
|
2025-10-01 16:28:57 +02:00
|
|
|
|
onPress={navigateToGaryAPI}
|
2025-10-01 16:24:21 +02:00
|
|
|
|
/>
|
|
|
|
|
|
</BetterTableRowGroup>
|
2025-10-01 16:03:33 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-10-01 16:18:11 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-09-30 19:03:33 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-10-01 16:18:11 +02:00
|
|
|
|
|
2025-10-01 16:24:21 +02:00
|
|
|
|
{/* 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>
|
2025-09-27 21:08:38 +02:00
|
|
|
|
|
2025-10-01 16:28:57 +02:00
|
|
|
|
{/* Navigation Pages */}
|
2025-10-01 16:24:21 +02:00
|
|
|
|
<BetterTableRowGroup
|
2025-10-01 16:28:57 +02:00
|
|
|
|
title="More Options"
|
|
|
|
|
|
icon={getAssetIDByName("MoreHorizontalIcon")}
|
2025-10-01 16:24:21 +02:00
|
|
|
|
>
|
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 />}
|
|
|
|
|
|
onPress={navigateToCredits}
|
|
|
|
|
|
/>
|
2025-10-01 16:24:21 +02:00
|
|
|
|
</BetterTableRowGroup>
|
2025-10-01 16:18:11 +02:00
|
|
|
|
|
|
|
|
|
|
<RN.View style={styles.spacing} />
|
2025-09-27 20:15:20 +02:00
|
|
|
|
</ScrollView>
|
2025-10-01 16:18:11 +02:00
|
|
|
|
</RN.View>
|
2025-09-27 19:40:15 +02:00
|
|
|
|
);
|
2025-09-27 20:10:37 +02:00
|
|
|
|
}
|