diff --git a/plugins/Commands/settings.tsx b/plugins/Commands/settings.tsx index 1b06ee4..378a298 100644 --- a/plugins/Commands/settings.tsx +++ b/plugins/Commands/settings.tsx @@ -13,1445 +13,1443 @@ const { FormRow, FormSwitchRow } = Forms; // Initialize storage with default values storage.factSettings ??= { - sendAsReply: true, - includeCitation: false, + sendAsReply: true, + includeCitation: false, }; storage.listSettings ??= { - pluginListAlwaysDetailed: false, - themeListAlwaysDetailed: false, + pluginListAlwaysDetailed: false, + themeListAlwaysDetailed: false, }; storage.garySettings ??= { - imageSource: "gary", + 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, - ip: true, - lovefemboys: false, - nekoslife: false, - friendInviteCreate: true, - friendInviteView: true, - friendInviteRevoke: true, + 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, + ip: true, + lovefemboys: false, + nekoslife: false, + friendInviteCreate: true, + friendInviteView: true, + friendInviteRevoke: true, }; storage.pendingRestart ??= false; // Hidden settings storage with NSFW bypass option storage.hiddenSettings ??= { - enabled: false, - visible: false, - konochanBypassNsfw: false, + enabled: false, + visible: false, + konochanBypassNsfw: false, }; // Better Table Row Group Component function BetterTableRowGroup({ - title, - icon, - children, - padding = false, + 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, - }, - }); + 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 - )} - + return ( + + {title && ( + + {icon && ( + + )} + {title.toUpperCase()} - ); + )} + + {padding ? ( + + {children} + + ) : ( + children + )} + + + ); } // Header Component with secret unlock function Header({ onHiddenUnlock }: { onHiddenUnlock?: () => void }) { - const [clickCounter, setClickCounter] = React.useState(0); - const [clickTimeout, setClickTimeout] = React.useState( - null, + const [clickCounter, setClickCounter] = React.useState(0); + const [clickTimeout, setClickTimeout] = React.useState( + null, + ); + + const styles = stylesheet.createThemedStyleSheet({ + container: { + flexDirection: "column", + alignItems: "center", + paddingVertical: 24, + paddingHorizontal: 16, + }, + title: { + fontSize: 28, + fontWeight: "700", + color: semanticColors.HEADER_PRIMARY, + marginBottom: 4, + }, + subtitle: { + fontSize: 16, + fontWeight: "500", + color: semanticColors.HEADER_SECONDARY, + }, + iconContainer: { + backgroundColor: semanticColors.BACKGROUND_SECONDARY, + borderRadius: 50, + width: 64, + height: 64, + justifyContent: "center", + alignItems: "center", + marginBottom: 16, + }, + icon: { + width: 32, + height: 32, + tintColor: semanticColors.INTERACTIVE_NORMAL, + }, + }); + + const handleIconPress = () => { + if (storage.hiddenSettings.enabled) { + storage.hiddenSettings.visible = !storage.hiddenSettings.visible; + showToast( + `Hidden settings ${storage.hiddenSettings.visible ? "visible" : "hidden"}`, + getAssetIDByName("SettingsIcon"), + ); + onHiddenUnlock?.(); + return; + } + + if (clickTimeout) { + clearTimeout(clickTimeout); + } + + const newTimeout = setTimeout(() => { + setClickCounter(0); + }, 1000); + setClickTimeout(newTimeout); + + const newCounter = clickCounter + 1; + setClickCounter(newCounter); + + if (newCounter < 10) { + return; + } + + showToast( + "🔓 Hidden settings unlocked!", + getAssetIDByName("CheckmarkIcon"), ); + storage.hiddenSettings.enabled = true; + storage.hiddenSettings.visible = true; + setClickCounter(0); - 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, - }, - }); + onHiddenUnlock?.(); + }; - const handleIconPress = () => { - if (storage.hiddenSettings.enabled) { - storage.hiddenSettings.visible = !storage.hiddenSettings.visible; - showToast( - `Hidden settings ${storage.hiddenSettings.visible ? "visible" : "hidden"}`, - getAssetIDByName("SettingsIcon"), - ); - onHiddenUnlock?.(); - return; - } - - if (clickTimeout) { - clearTimeout(clickTimeout); - } - - const newTimeout = setTimeout(() => { - setClickCounter(0); - }, 1000); - setClickTimeout(newTimeout); - - const newCounter = clickCounter + 1; - setClickCounter(newCounter); - - if (newCounter < 10) { - return; - } - - showToast( - "🔓 Hidden settings unlocked!", - getAssetIDByName("CheckmarkIcon"), - ); - storage.hiddenSettings.enabled = true; - storage.hiddenSettings.visible = true; - setClickCounter(0); - - onHiddenUnlock?.(); - }; - - return ( - - - - - Commands - A collection of useful commands - - ); + return ( + + + + + Commands + A collection of useful commands + + ); } // NekosLife Categories Reference Page - SFW ONLY function NekosLifeCategoriesPage() { - const styles = stylesheet.createThemedStyleSheet({ - container: { - flex: 1, - backgroundColor: semanticColors.BACKGROUND_PRIMARY, - }, - tableHeader: { - flexDirection: "row", - alignItems: "center", - paddingVertical: 12, - paddingHorizontal: 16, - backgroundColor: semanticColors.BACKGROUND_MODIFIER_ACCENT, - borderBottomWidth: 2, - borderBottomColor: semanticColors.BORDER_STRONG, - }, - headerText: { - fontSize: 14, - fontWeight: "700", - color: semanticColors.TEXT_NORMAL, - textTransform: "uppercase", - }, - nameHeader: { - flex: 2, - }, - codeHeader: { - flex: 2, - textAlign: "center", - }, - badgeHeader: { - flex: 1, - textAlign: "center", - }, - categoryItem: { - flexDirection: "row", - alignItems: "center", - paddingVertical: 12, - paddingHorizontal: 16, - borderBottomWidth: 1, - borderBottomColor: semanticColors.BORDER_FAINT, - }, - categoryName: { - fontSize: 16, - fontWeight: "500", - color: semanticColors.TEXT_NORMAL, - flex: 2, - }, - categoryValue: { - fontSize: 14, - color: semanticColors.TEXT_MUTED, - fontFamily: "monospace", - flex: 2, - textAlign: "center", - }, - sfwBadgeContainer: { - flex: 1, - alignItems: "center", - }, - sfwBadge: { - backgroundColor: semanticColors.STATUS_POSITIVE, - paddingHorizontal: 8, - paddingVertical: 4, - borderRadius: 12, - }, - badgeText: { - fontSize: 12, - fontWeight: "600", - color: semanticColors.WHITE, - }, - infoText: { - fontSize: 14, - color: semanticColors.TEXT_MUTED, - textAlign: "center", - lineHeight: 20, - }, - }); + const styles = stylesheet.createThemedStyleSheet({ + container: { + flex: 1, + backgroundColor: semanticColors.BACKGROUND_PRIMARY, + }, + tableHeader: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 12, + paddingHorizontal: 16, + backgroundColor: semanticColors.BACKGROUND_MODIFIER_ACCENT, + borderBottomWidth: 2, + borderBottomColor: semanticColors.BORDER_STRONG, + }, + headerText: { + fontSize: 14, + fontWeight: "700", + color: semanticColors.HEADER_PRIMARY, + textTransform: "uppercase", + }, + nameHeader: { + flex: 2, + }, + codeHeader: { + flex: 2, + textAlign: "center", + }, + badgeHeader: { + flex: 1, + textAlign: "center", + }, + categoryItem: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 12, + paddingHorizontal: 16, + borderBottomWidth: 1, + borderBottomColor: semanticColors.BORDER_FAINT, + }, + categoryName: { + fontSize: 16, + fontWeight: "500", + color: semanticColors.TEXT_NORMAL, + flex: 2, + }, + categoryValue: { + fontSize: 14, + color: semanticColors.TEXT_MUTED, + fontFamily: "monospace", + flex: 2, + textAlign: "center", + }, + sfwBadgeContainer: { + flex: 1, + alignItems: "center", + }, + sfwBadge: { + backgroundColor: semanticColors.STATUS_POSITIVE, + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 12, + }, + badgeText: { + fontSize: 12, + fontWeight: "600", + color: semanticColors.TEXT_NORMAL, + }, + infoText: { + fontSize: 14, + color: semanticColors.TEXT_MUTED, + textAlign: "center", + lineHeight: 20, + }, + }); - // nekos.life categories - const sfwCategories = [ - { name: "Avatar", value: "avatar" }, - { name: "Classic", value: "classic" }, - { name: "Cuddle", value: "cuddle" }, - { name: "Fox Girl", value: "fox_girl" }, - { name: "Gecg", value: "gecg" }, - { name: "Holo", value: "holo" }, - { name: "Kemonomimi", value: "kemonomimi" }, - { name: "Kiss", value: "kiss" }, - { name: "Neko", value: "neko" }, - { name: "Neko GIF", value: "ngif" }, - { name: "Smug", value: "smug" }, - { name: "Spank", value: "spank" }, - { name: "Tickle", value: "tickle" }, - { name: "Waifu", value: "waifu" }, - { name: "Wallpaper", value: "wallpaper" }, - { name: "Woof", value: "woof" }, - ]; + // nekos.life categories + const sfwCategories = [ + { name: "Avatar", value: "avatar" }, + { name: "Classic", value: "classic" }, + { name: "Cuddle", value: "cuddle" }, + { name: "Fox Girl", value: "fox_girl" }, + { name: "Gecg", value: "gecg" }, + { name: "Holo", value: "holo" }, + { name: "Kemonomimi", value: "kemonomimi" }, + { name: "Kiss", value: "kiss" }, + { name: "Neko", value: "neko" }, + { name: "Neko GIF", value: "ngif" }, + { name: "Smug", value: "smug" }, + { name: "Spank", value: "spank" }, + { name: "Tickle", value: "tickle" }, + { name: "Waifu", value: "waifu" }, + { name: "Wallpaper", value: "wallpaper" }, + { name: "Woof", value: "woof" }, + ]; - // Sort categories alphabetically - const sortedCategories = sfwCategories.sort((a, b) => - a.name.localeCompare(b.name), - ); + // Sort categories alphabetically + const sortedCategories = sfwCategories.sort((a, b) => + a.name.localeCompare(b.name), + ); - return ( - - - - + return ( + + + + Total SFW Categories: {sfwCategories.length} - {"\n\n"} + {"\n\n"} Use these category names with the /nekoslife command.{"\n"} All categories are Safe For Work (SFW). - - + + - - {/* Table Header */} - - + + {/* Table Header */} + + Category Name - - + + Command Code - - + + Type - - + + - {/* Table Rows */} - {sortedCategories.map((category, index) => ( - - {category.name} - {category.value} - - - SFW - - - - ))} - + {/* Table Rows */} + {sortedCategories.map((category, index) => ( + + {category.name} + {category.value} + + + SFW + + - - ); + ))} + + + + ); } // Hidden Commands Settings Page function HiddenSettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); - const navigation = NavigationNative.useNavigation(); + useProxy(storage); + const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + const navigation = NavigationNative.useNavigation(); - const styles = stylesheet.createThemedStyleSheet({ - container: { - flex: 1, - backgroundColor: semanticColors.BACKGROUND_PRIMARY, - }, - warningText: { - fontSize: 14, - color: semanticColors.TEXT_DANGER, - textAlign: "center", - lineHeight: 20, - fontWeight: "600", - }, - infoText: { - fontSize: 14, - color: semanticColors.TEXT_MUTED, - textAlign: "center", - lineHeight: 20, - marginTop: 8, - }, - }); + const styles = stylesheet.createThemedStyleSheet({ + container: { + flex: 1, + backgroundColor: semanticColors.BACKGROUND_PRIMARY, + }, + warningText: { + fontSize: 14, + color: semanticColors.TEXT_DANGER, + textAlign: "center", + lineHeight: 20, + fontWeight: "600", + }, + infoText: { + fontSize: 14, + color: semanticColors.TEXT_MUTED, + textAlign: "center", + lineHeight: 20, + marginTop: 8, + }, + }); - return ( - - - - + return ( + + + + These are hidden commands that may contain mature content or experimental features. - - + + Use at your own discretion. Commands in this section are disabled by default. - - + + - - } - value={storage.enabledCommands.lovefemboys} - onValueChange={(v) => { - storage.enabledCommands.lovefemboys = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - + + } + value={storage.enabledCommands.lovefemboys} + onValueChange={(v) => { + storage.enabledCommands.lovefemboys = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - } - value={storage.hiddenSettings.konochanBypassNsfw} - onValueChange={(v) => { - if (v) { - alerts.showConfirmationAlert({ - title: "⚠️ NSFW Bypass Warning", - content: + + } + value={storage.hiddenSettings.konochanBypassNsfw} + onValueChange={(v) => { + if (v) { + alerts.showConfirmationAlert({ + title: "⚠️ NSFW Bypass Warning", + content: "Enabling this allows NSFW content from KonoChan to be sent in any channel, including non-NSFW channels. This could violate server rules or Discord ToS. Use responsibly!", - confirmText: "I Understand", - cancelText: "Cancel", - onConfirm: () => { - storage.hiddenSettings.konochanBypassNsfw = true; - forceUpdate(); - }, - onCancel: () => { - }, - }); - } else { - storage.hiddenSettings.konochanBypassNsfw = false; - forceUpdate(); - } - }} - /> - + confirmText: "I Understand", + cancelText: "Cancel", + onConfirm: () => { + storage.hiddenSettings.konochanBypassNsfw = true; + forceUpdate(); + }, + onCancel: () => {}, + }); + } else { + storage.hiddenSettings.konochanBypassNsfw = false; + forceUpdate(); + } + }} + /> + - - } - value={storage.hiddenSettings.visible} - onValueChange={(v) => { - storage.hiddenSettings.visible = v; - }} - /> - } - onPress={() => { - alerts.showConfirmationAlert({ - title: "Reset Hidden Settings", - content: + + } + value={storage.hiddenSettings.visible} + onValueChange={(v) => { + storage.hiddenSettings.visible = v; + }} + /> + } + onPress={() => { + alerts.showConfirmationAlert({ + title: "Reset Hidden Settings", + content: "This will hide the hidden settings section and disable all hidden commands. Are you sure?", - confirmText: "Reset", - onConfirm: () => { - storage.hiddenSettings.enabled = false; - storage.hiddenSettings.visible = false; - storage.hiddenSettings.konochanBypassNsfw = false; - storage.enabledCommands.lovefemboys = false; + confirmText: "Reset", + onConfirm: () => { + storage.hiddenSettings.enabled = false; + storage.hiddenSettings.visible = false; + storage.hiddenSettings.konochanBypassNsfw = false; + storage.enabledCommands.lovefemboys = false; - storage.pendingRestart = true; - showToast( - "Hidden settings reset", - getAssetIDByName("CheckmarkIcon"), - ); - }, - cancelText: "Cancel", - }); - }} - /> - - - - ); + storage.pendingRestart = true; + showToast( + "Hidden settings reset", + getAssetIDByName("CheckmarkIcon"), + ); + }, + cancelText: "Cancel", + }); + }} + /> + + + + ); } // Facts Commands Settings Page function FactsSettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + 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.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(); - }} - /> - - } - value={storage.enabledCommands.dogfact} - onValueChange={(v) => { - storage.enabledCommands.dogfact = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - } - value={storage.enabledCommands.useless} - onValueChange={(v) => { - storage.enabledCommands.useless = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - - - ); + + + } + value={storage.enabledCommands.catfact} + onValueChange={(v) => { + storage.enabledCommands.catfact = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.dogfact} + onValueChange={(v) => { + storage.enabledCommands.dogfact = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.useless} + onValueChange={(v) => { + storage.enabledCommands.useless = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + + + ); } // Gary API Settings Page function GaryAPIPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + 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 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; + const currentSource = storage.garySettings.imageSource; - return ( - - - - - } - value={storage.enabledCommands.gary} - onValueChange={(v) => { - storage.enabledCommands.gary = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - + return ( + + + + + } + value={storage.enabledCommands.gary} + onValueChange={(v) => { + storage.enabledCommands.gary = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - + + Choose which API the /gary command should use to fetch images. - - + + - - } - value={currentSource === "gary"} - onValueChange={(v) => { - if (v) { - storage.garySettings.imageSource = "gary"; - forceUpdate(); - } - }} - /> - } - value={currentSource === "catapi"} - onValueChange={(v) => { - if (v) { - storage.garySettings.imageSource = "catapi"; - forceUpdate(); - } - }} - /> - } - value={currentSource === "minker"} - onValueChange={(v) => { - if (v) { - storage.garySettings.imageSource = "minker"; - forceUpdate(); - } - }} - /> - } - value={currentSource === "goober"} - onValueChange={(v) => { - if (v) { - storage.garySettings.imageSource = "goober"; - forceUpdate(); - } - }} - /> - + + } + value={currentSource === "gary"} + onValueChange={(v) => { + if (v) { + storage.garySettings.imageSource = "gary"; + forceUpdate(); + } + }} + /> + } + value={currentSource === "catapi"} + onValueChange={(v) => { + if (v) { + storage.garySettings.imageSource = "catapi"; + forceUpdate(); + } + }} + /> + } + value={currentSource === "minker"} + onValueChange={(v) => { + if (v) { + storage.garySettings.imageSource = "minker"; + forceUpdate(); + } + }} + /> + } + value={currentSource === "goober"} + onValueChange={(v) => { + if (v) { + storage.garySettings.imageSource = "goober"; + forceUpdate(); + } + }} + /> + - - + + Currently using:{" "} - {currentSource === "gary" - ? "Gary API" - : currentSource === "catapi" - ? "Cat API" - : currentSource === "minker" - ? "Minker API" - : currentSource === "goober" - ? "Goober API" - : "Gary API"} - - - - - ); + {currentSource === "gary" + ? "Gary API" + : currentSource === "catapi" + ? "Cat API" + : currentSource === "minker" + ? "Minker API" + : currentSource === "goober" + ? "Goober API" + : "Gary API"} + + + + + ); } // List Settings Page function ListSettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + 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.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(); - }} - /> - - } - value={storage.enabledCommands.themeList} - onValueChange={(v) => { - storage.enabledCommands.themeList = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - - - ); + + + } + value={storage.enabledCommands.pluginList} + onValueChange={(v) => { + storage.enabledCommands.pluginList = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.themeList} + onValueChange={(v) => { + storage.enabledCommands.themeList = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + + + ); } // Image Settings Page function ImageSettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + 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(); - }} - /> - + + } + value={storage.enabledCommands.petpet} + onValueChange={(v) => { + storage.enabledCommands.petpet = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - } - value={storage.enabledCommands.konoself} - onValueChange={(v) => { - storage.enabledCommands.konoself = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - } - value={storage.enabledCommands.konosend} - onValueChange={(v) => { - storage.enabledCommands.konosend = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - - - ); + + } + value={storage.enabledCommands.konoself} + onValueChange={(v) => { + storage.enabledCommands.konoself = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + } + value={storage.enabledCommands.konosend} + onValueChange={(v) => { + storage.enabledCommands.konosend = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + + + ); } // Spotify Settings Page function SpotifySettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + useProxy(storage); + const [, forceUpdate] = React.useReducer((x) => x + 1, 0); - const styles = stylesheet.createThemedStyleSheet({ - infoText: { - fontSize: 14, - color: semanticColors.TEXT_MUTED, - textAlign: "center", - lineHeight: 20, - }, - }); + const styles = stylesheet.createThemedStyleSheet({ + infoText: { + fontSize: 14, + color: semanticColors.TEXT_MUTED, + textAlign: "center", + lineHeight: 20, + }, + }); - return ( - + + - - - - } - value={storage.enabledCommands.spotifyTrack} - onValueChange={(v) => { - storage.enabledCommands.spotifyTrack = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - } - value={storage.enabledCommands.spotifyAlbum} - onValueChange={(v) => { - storage.enabledCommands.spotifyAlbum = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - } - value={storage.enabledCommands.spotifyArtists} - onValueChange={(v) => { - storage.enabledCommands.spotifyArtists = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - } - value={storage.enabledCommands.spotifyCover} - onValueChange={(v) => { - storage.enabledCommands.spotifyCover = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - + + } + value={storage.enabledCommands.spotifyTrack} + onValueChange={(v) => { + storage.enabledCommands.spotifyTrack = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.spotifyAlbum} + onValueChange={(v) => { + storage.enabledCommands.spotifyAlbum = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.spotifyArtists} + onValueChange={(v) => { + storage.enabledCommands.spotifyArtists = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + } + value={storage.enabledCommands.spotifyCover} + onValueChange={(v) => { + storage.enabledCommands.spotifyCover = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - + + 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 - Updated with friend invite commands function OtherSettingsPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + 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(); - }} - /> - + } + value={storage.enabledCommands.firstmessage} + onValueChange={(v) => { + storage.enabledCommands.firstmessage = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - } - value={storage.enabledCommands.sysinfo} - onValueChange={(v) => { - storage.enabledCommands.sysinfo = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - + + } + value={storage.enabledCommands.sysinfo} + onValueChange={(v) => { + storage.enabledCommands.sysinfo = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - { - storage.enabledCommands.friendInviteCreate = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - { - storage.enabledCommands.friendInviteView = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - { - storage.enabledCommands.friendInviteRevoke = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - - - - ); + + { + storage.enabledCommands.friendInviteCreate = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + { + storage.enabledCommands.friendInviteView = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + { + storage.enabledCommands.friendInviteRevoke = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + + + + ); } // Credits Page function AliucordPage() { - useProxy(storage); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); - const navigation = NavigationNative.useNavigation(); + useProxy(storage); + const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + const navigation = NavigationNative.useNavigation(); - return ( - - - } - value={storage.enabledCommands.ip} - onValueChange={(v) => { - storage.enabledCommands.ip = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - + return ( + + + } + value={storage.enabledCommands.ip} + onValueChange={(v) => { + storage.enabledCommands.ip = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + - - } - value={storage.enabledCommands.nekoslife} - onValueChange={(v) => { - storage.enabledCommands.nekoslife = v; - storage.pendingRestart = true; - forceUpdate(); - }} - /> - } - trailing={} - onPress={() => - navigation.push("VendettaCustomPage", { - title: "NekosLife Categories", - render: NekosLifeCategoriesPage, - }) - } - /> - + + } + value={storage.enabledCommands.nekoslife} + onValueChange={(v) => { + storage.enabledCommands.nekoslife = v; + storage.pendingRestart = true; + forceUpdate(); + }} + /> + } + trailing={} + onPress={() => + navigation.push("VendettaCustomPage", { + title: "NekosLife Categories", + render: NekosLifeCategoriesPage, + }) + } + /> + - - - ); + + + ); } 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 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, + }, + 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_LINK, + fontWeight: "500", + }, + infoText: { + fontSize: 14, + color: semanticColors.TEXT_NORMAL, + 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/IAmGaryTheCat.png", - github: "https://github.com/IAmGaryTheCat", - }, - { - command: "IP & NekosLife Commands", - author: "scruzism", - avatar: "https://github.com/scrazzz.png", - github: "https://github.com/scrazzz", - }, - { - command: "FriendInvites", - author: "nikosszzz", - avatar: "https://github.com/nikosszzz.png", - github: "https://github.com/nikosszzz", - }, - ]; + 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/IAmGaryTheCat.png", + github: "https://github.com/IAmGaryTheCat", + }, + { + command: "IP & NekosLife Commands", + author: "scruzism", + avatar: "https://github.com/scrazzz.png", + github: "https://github.com/scrazzz", + }, + { + command: "FriendInvites", + author: "nikosszzz", + avatar: "https://github.com/nikosszzz.png", + github: "https://github.com/nikosszzz", + }, + ]; - const handleProfilePress = (githubUrl: string) => { - RN.Linking.openURL(githubUrl); - }; + const handleProfilePress = (githubUrl: string) => { + RN.Linking.openURL(githubUrl); + }; - return ( - - - - + 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/", "@")} - - - - ))} + {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.2.1 - - - - - ); + + + + + ); } // MAIN SETTINGS COMPONENT export default function Settings() { - useProxy(storage); - const navigation = NavigationNative.useNavigation(); - const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + useProxy(storage); + const navigation = NavigationNative.useNavigation(); + const [, forceUpdate] = React.useReducer((x) => x + 1, 0); - React.useEffect(() => { - return () => { - if (storage.pendingRestart) { - storage.pendingRestart = false; - alerts.showConfirmationAlert({ - title: "Restart Required", - content: + 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, - }); - } - }; - }, []); + confirmText: "Okay", + cancelText: null, + onConfirm: () => {}, // Fixed TypeScript error: added onConfirm handler + }); + } + }; + }, []); - return ( - +
+ + + } + 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: "Aliucord", + render: AliucordPage, + }) + } + /> + } + trailing={} + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Other Commands", + render: OtherSettingsPage, + }) + } + /> + + + {storage.hiddenSettings?.visible && ( + -
+ } + trailing={} + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Hidden Settings", + render: HiddenSettingsPage, + }) + } + /> + + )} - - } - 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: "Aliucord", - render: AliucordPage, - }) - } - /> - } - trailing={} - onPress={() => - navigation.push("VendettaCustomPage", { - title: "Other Commands", - render: OtherSettingsPage, - }) - } - /> - + + } + trailing={} + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Credits", + render: CreditsPage, + }) + } + /> + - {storage.hiddenSettings?.visible && ( - - } - trailing={} - onPress={() => - navigation.push("VendettaCustomPage", { - title: "Hidden Settings", - render: HiddenSettingsPage, - }) - } - /> - - )} - - - } - trailing={} - onPress={() => - navigation.push("VendettaCustomPage", { - title: "Credits", - render: CreditsPage, - }) - } - /> - - - - - ); + + + ); } diff --git a/plugins/Commands/src/commands/firstmessage.ts b/plugins/Commands/src/commands/firstmessage.ts index dd48454..fda85f0 100644 --- a/plugins/Commands/src/commands/firstmessage.ts +++ b/plugins/Commands/src/commands/firstmessage.ts @@ -42,7 +42,8 @@ export const firstMessageCommand = { name: "user", displayName: "user", description: "Target user to get their first message in this server/dm", - displayDescription: "Target user to get their first message in this server/dm", + displayDescription: + "Target user to get their first message in this server/dm", type: 6, // USER type required: false, }, @@ -74,40 +75,24 @@ export const firstMessageCommand = { const channelId = ctx.channel.id; const isDM = ctx.channel.type === 1; - let result = "https://discord.com/channels/"; + // Channel option is not valid in DMs + if (isDM && channel) { + return { type: 4 }; + } + let result = "https://discord.com/channels/"; let message; - if (!user && !channel) { - if (isDM) { - message = await getFirstDMMessage(channelId); - result += `@me/${channelId}/${message.id}`; - } else { - message = await getFirstGuildMessage(guildId); - result += `${guildId}/${message.channel_id}/${message.id}`; - } - } else if (user) { - if (isDM) { - message = await getFirstDMMessage(channelId, user); - result += `@me/${channelId}/${message.id}`; - } else { - message = await getFirstGuildMessage(guildId, user); - result += `${guildId}/${message.channel_id}/${message.id}`; - } - } else if (channel) { - if (isDM) { - // Silent fail for invalid combination - return { type: 4 }; - } - message = await getFirstGuildMessage(guildId, null, channel); - result += `${guildId}/${channel}/${message.id}`; + + if (isDM) { + // DM logic: only user parameter matters + message = await getFirstDMMessage(channelId, user); + result += `@me/${channelId}/${message.id}`; } else { - // both user and channel specified - if (isDM) { - // Silent fail for invalid combination - return { type: 4 }; - } + // Guild logic: both user and channel parameters can be used message = await getFirstGuildMessage(guildId, user, channel); - result += `${guildId}/${channel}/${message.id}`; + // Use the specified channel if provided, otherwise use the message's channel + const targetChannel = channel || message.channel_id; + result += `${guildId}/${targetChannel}/${message.id}`; } if (send) { @@ -116,13 +101,13 @@ export const firstMessageCommand = { ctx.channel.id, { content: result }, void 0, - { nonce: fixNonce } + { nonce: fixNonce }, ); - return { type: 4 }; } else { - RN.Linking.openURL(result); // FIXED: use RN.Linking.openURL - return { type: 4 }; + RN.Linking.openURL(result); } + + return { type: 4 }; } catch (error) { console.error("[FirstMessage] Error:", error); // Silent fail - no error message in chat