From a2a20ab1a1e36b7dc0dbf60571b4bfd1ec918f57 Mon Sep 17 00:00:00 2001 From: kmmiio99o Date: Sun, 24 May 2026 16:05:48 +0200 Subject: [PATCH] Revert "feat: detach Sidebar patches as they" This reverts commit ecd97c7018767264e1e8287f71fdfb49168aa7b3. --- chatboxavatar/index.tsx | 178 ++++++++++++++++++ chatboxavatar/settings.tsx | 58 ++++++ chatboxavatar/storage.ts | 22 +++ eslint.config.mjs | 85 +++++++++ plugins/ChatboxAvatar/manifest.json | 18 ++ plugins/ChatboxAvatar/src/index.tsx | 165 ++++++++++++++++ plugins/ChatboxAvatar/src/settings.tsx | 101 ++++++++++ plugins/Commands/index.ts | 55 ++++++ plugins/Commands/settings/settings.tsx | 4 +- plugins/multi-scrobbler/src/index.tsx | 84 +++++++++ .../multi-scrobbler/src/ui/pages/Settings.tsx | 59 ++++++ 11 files changed, 827 insertions(+), 2 deletions(-) create mode 100644 chatboxavatar/index.tsx create mode 100644 chatboxavatar/settings.tsx create mode 100644 chatboxavatar/storage.ts create mode 100644 eslint.config.mjs create mode 100644 plugins/ChatboxAvatar/manifest.json create mode 100644 plugins/ChatboxAvatar/src/index.tsx create mode 100644 plugins/ChatboxAvatar/src/settings.tsx diff --git a/chatboxavatar/index.tsx b/chatboxavatar/index.tsx new file mode 100644 index 0000000..afdba15 --- /dev/null +++ b/chatboxavatar/index.tsx @@ -0,0 +1,178 @@ +import { after } from "@api/patcher"; +import { findByNameLazy, findByProps, findByPropsLazy, findByStoreName, findByTypeDisplayName } from "@metro"; +import { ReactNative } from "@metro/common"; +import { definePlugin } from "@plugins"; +import { Contributors } from "@rain/Developers"; +import React, { useEffect, useRef } from "react"; + +import ChatboxAvatarSettings from "./settings"; +import { useChatboxAvatarSettings } from "./storage"; + +const Flux = findByProps("useStateFromStores"); +const ChatInputActions = findByTypeDisplayName("ChatInputActions"); +const ChatInputSendButton = findByTypeDisplayName("ChatInputSendButton"); +let hasText = false; +let sendBtnRef: { setHasText?: (hasText: boolean) => void } | undefined; +const { Pressable, View, Animated } = ReactNative; + +const avatarCollapse = new Animated.Value(0); + +const Avatar = findByPropsLazy("default", "AvatarSizes", "getStatusSize")?.default; + +const UserStore = findByStoreName("UserStore"); +const SelectedChannelStore = findByStoreName("SelectedChannelStore"); +const ChannelStore = findByStoreName("ChannelStore"); +const SelfPresenceStore = findByStoreName("SelfPresenceStore"); +const showUserProfileActionSheet = findByNameLazy("showUserProfileActionSheet"); +const showYouAccountActionSheetByProp = findByPropsLazy("showYouAccountActionSheet"); + +function AvatarAction() { + const [textState, setTextState] = React.useState(false); + const self = Flux?.useStateFromStores?.([UserStore], () => UserStore?.getCurrentUser?.()); + const status = Flux?.useStateFromStores?.([SelfPresenceStore], () => SelfPresenceStore?.getStatus?.()); + const settings = useChatboxAvatarSettings(); + const channelId = Flux?.useStateFromStores?.([SelectedChannelStore], () => SelectedChannelStore?.getCurrentlySelectedChannelId?.()); + const channel = Flux?.useStateFromStores?.([ChannelStore], () => ChannelStore?.getChannel?.(channelId), [channelId]); + + const animated = useRef(avatarCollapse).current; + + React.useEffect(() => { + const interval = setInterval(() => { + setTextState(hasText); + }, 100); + return () => clearInterval(interval); + }, []); + + useEffect(() => { + const shouldCollapse = settings.collapseWhileTyping && textState; + Animated.parallel([ + Animated.timing(animated, { + toValue: shouldCollapse ? 1 : 0, + duration: 200, + useNativeDriver: false, + }), + ]).start(); + }, [textState, settings.collapseWhileTyping, animated]); + + if (!self) return null; + + const openAccountSheet = () => { + const fn = showYouAccountActionSheetByProp?.showYouAccountActionSheet; + if (typeof fn === "function") { + try { + fn(true, true); + return; + } catch (err) { + } + } + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + }; + + const handlePress = () => { + switch (settings.pressAction) { + case "profile": + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + break; + case "server": + openAccountSheet(); + break; + default: + break; + } + }; + + const handleLongPress = () => { + switch (settings.longPressAction) { + case "profile": + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + break; + case "server": + openAccountSheet(); + break; + default: + break; + } + }; + + return ( + + + {Avatar && ( + + )} + + + ); +} + +const unpatches: (() => void)[] = []; + +export default definePlugin({ + name: "ChatboxAvatar", + description: "Adds your avatar to the chatbox.", + author: [Contributors.LampDelivery], + id: "chatboxavatar", + version: "v1.0.0", + requiresRestart: true, + settings: ChatboxAvatarSettings, + async start() { + if (!ChatInputActions?.type || !ChatInputSendButton?.type) return; + unpatches.push( + after("render", ChatInputSendButton.type, (args, ret) => { + setImmediate(() => { + setImmediate(() => { + if (args?.[1]?.current) { + sendBtnRef = args[1].current; + const origSetHasText = sendBtnRef?.setHasText; + unpatches.push(() => { if (sendBtnRef && origSetHasText) sendBtnRef.setHasText = origSetHasText; }); + if (sendBtnRef) { + sendBtnRef.setHasText = (hasText_: boolean) => { + hasText = hasText_; + if (origSetHasText) return origSetHasText.call(sendBtnRef, hasText_); + }; + } + } + }); + }); + }) + ); + + }, + async eagerStart() { + if (!ChatInputActions?.type || !ChatInputSendButton?.type) return; + unpatches.push( + after("render", ChatInputActions.type, (args, ret) => { + return React.createElement( + View, + { style: { flexDirection: "row", alignItems: "center" } }, + ret, + React.createElement(AvatarAction) + ); + }) + ); + }, + stop() { + for (const unpatch of unpatches) unpatch?.(); + unpatches.length = 0; + }, +}); diff --git a/chatboxavatar/settings.tsx b/chatboxavatar/settings.tsx new file mode 100644 index 0000000..0c54d5b --- /dev/null +++ b/chatboxavatar/settings.tsx @@ -0,0 +1,58 @@ +import { Stack, TableRadioGroup, TableRadioRow } from "@metro/common/components"; +import React from "react"; + +import { ChatboxAvatarSettings, useChatboxAvatarSettings } from "./storage"; +export default function ChatboxAvatarSettings() { + const settings = useChatboxAvatarSettings(); + const [, forceUpdate] = React.useReducer(x => ~x, 0); + const setPressAction = (value: string) => { + useChatboxAvatarSettings.getState().updateSettings?.({ pressAction: value as ChatboxAvatarSettings["pressAction"] }); + forceUpdate(); + }; + const setLongPressAction = (value: string) => { + useChatboxAvatarSettings.getState().updateSettings?.({ longPressAction: value as ChatboxAvatarSettings["longPressAction"] }); + forceUpdate(); + }; + return ( + + + + + + + + + + { + useChatboxAvatarSettings.getState().updateSettings?.({ showStatusCutout: v === "true" }); + forceUpdate(); + }} + title="Status Icon" + > + + + + { + useChatboxAvatarSettings.getState().updateSettings?.({ collapseWhileTyping: v === "true" }); + forceUpdate(); + }} + title="Collapse While Typing" + > + + + + + ); +} diff --git a/chatboxavatar/storage.ts b/chatboxavatar/storage.ts new file mode 100644 index 0000000..046f2c6 --- /dev/null +++ b/chatboxavatar/storage.ts @@ -0,0 +1,22 @@ +import { createPluginStore } from "@api/storage"; + +export interface ChatboxAvatarSettings { + replaceButton: "gallery" | "apps" | "gift"; + pressAction: "profile" | "server"; + longPressAction: "profile" | "server"; + serverId?: string; + showStatusCutout?: boolean; + collapseWhileTyping?: boolean; +} + +export const { + useStore: useChatboxAvatarSettings, + settings: chatboxAvatarSettings, +} = createPluginStore("chatboxavatar", { + replaceButton: "gallery", + pressAction: "profile", + longPressAction: "server", + serverId: "", + showStatusCutout: false, + collapseWhileTyping: false, +}); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..72decb0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,85 @@ +import eslint from "@eslint/js"; +import tseslintPlugin from "@typescript-eslint/eslint-plugin"; +import tseslintParser from "@typescript-eslint/parser"; +import reactPlugin from "eslint-plugin-react"; +import globals from "globals"; + +export default [ + eslint.configs.recommended, + { + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + parser: tseslintParser, + globals: { + ...globals.node, + ...globals.browser, + NodeJS: "readonly", + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + plugins: { + "@typescript-eslint": tseslintPlugin, + react: reactPlugin, + }, + settings: { + react: { + version: "detect", + }, + }, + rules: { + ...tseslintPlugin.configs.recommended.rules, + ...reactPlugin.configs.recommended.rules, + indent: ["error", 4, { SwitchCase: 1 }], + quotes: ["error", "double"], + semi: ["error", "always"], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/triple-slash-reference": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "react/react-in-jsx-scope": "off", + "eol-last": "error", + }, + }, + { + files: ["**/*.{js,jsx}"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.node, + ...globals.browser, + NodeJS: "readonly", + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + plugins: { + react: reactPlugin, + }, + settings: { + react: { + version: "detect", + }, + }, + rules: { + ...reactPlugin.configs.recommended.rules, + indent: ["error", 4, { SwitchCase: 1 }], + quotes: ["error", "double"], + semi: ["error", "always"], + "react/react-in-jsx-scope": "off", + "eol-last": "error", + }, + }, + { + ignores: ["dist/**", "node_modules/**"], + }, +]; diff --git a/plugins/ChatboxAvatar/manifest.json b/plugins/ChatboxAvatar/manifest.json new file mode 100644 index 0000000..8ebd537 --- /dev/null +++ b/plugins/ChatboxAvatar/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Chatbox Avatar", + "description": "Quickly view your profile from the chatbox.", + "authors": [ + { + "name": "Cynosphere", + "id": "150745989836308480" + }, + { + "name": "kmmiio99o", + "id": "879393496627306587" + } + ], + "main": "src/index.tsx", + "vendetta": { + "icon": "UserSquareIcon" + } +} diff --git a/plugins/ChatboxAvatar/src/index.tsx b/plugins/ChatboxAvatar/src/index.tsx new file mode 100644 index 0000000..d08b9e8 --- /dev/null +++ b/plugins/ChatboxAvatar/src/index.tsx @@ -0,0 +1,165 @@ +import { after } from "@vendetta/patcher"; +import { findByName, findByProps, findByStoreName, findByDisplayName } from "@vendetta/metro"; +import { ReactNative } from "@vendetta/metro/common"; +import { plugin } from "@vendetta"; +import React, { useEffect, useRef } from "react"; + +import ChatboxAvatarSettings from "./settings"; + +const Flux = findByProps("useStateFromStores"); +const ChatInputActions = findByDisplayName("ChatInputActions"); +const ChatInputSendButton = findByDisplayName("ChatInputSendButton"); +let hasText = false; +let sendBtnRef: { setHasText?: (hasText: boolean) => void } | undefined; +const { Pressable, View, Animated } = ReactNative; + +const avatarCollapse = new Animated.Value(0); + +const Avatar = findByProps("default", "AvatarSizes", "getStatusSize")?.default; + +const UserStore = findByStoreName("UserStore"); +const SelectedChannelStore = findByStoreName("SelectedChannelStore"); +const ChannelStore = findByStoreName("ChannelStore"); +const SelfPresenceStore = findByStoreName("SelfPresenceStore"); +const showUserProfileActionSheet = findByName("showUserProfileActionSheet"); +const showYouAccountActionSheetByProp = findByProps("showYouAccountActionSheet"); + +function AvatarAction() { + const [textState, setTextState] = React.useState(false); + const self = Flux?.useStateFromStores?.([UserStore], () => UserStore?.getCurrentUser?.()); + const status = Flux?.useStateFromStores?.([SelfPresenceStore], () => SelfPresenceStore?.getStatus?.()); + const settings = plugin.storage; + const channelId = Flux?.useStateFromStores?.([SelectedChannelStore], () => SelectedChannelStore?.getCurrentlySelectedChannelId?.()); + const channel = Flux?.useStateFromStores?.([ChannelStore], () => ChannelStore?.getChannel?.(channelId), [channelId]); + + const animated = useRef(avatarCollapse).current; + + React.useEffect(() => { + const interval = setInterval(() => { + setTextState(hasText); + }, 100); + return () => clearInterval(interval); + }, []); + + useEffect(() => { + const shouldCollapse = settings.collapseWhileTyping && textState; + Animated.parallel([ + Animated.timing(animated, { + toValue: shouldCollapse ? 1 : 0, + duration: 200, + useNativeDriver: false, + }), + ]).start(); + }, [textState, settings.collapseWhileTyping, animated]); + + if (!self) return null; + + const openAccountSheet = () => { + const fn = showYouAccountActionSheetByProp?.showYouAccountActionSheet; + if (typeof fn === "function") { + try { + fn(true, true); + return; + } catch {} + } + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + }; + + const handlePress = () => { + switch (settings.pressAction) { + case "profile": + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + break; + case "server": + openAccountSheet(); + break; + default: + break; + } + }; + + const handleLongPress = () => { + switch (settings.longPressAction) { + case "profile": + showUserProfileActionSheet?.({ userId: self.id, channelId: channel?.id ?? channelId }); + break; + case "server": + openAccountSheet(); + break; + default: + break; + } + }; + + return ( + + + {Avatar && ( + + )} + + + ); +} + +const unpatches: (() => void)[] = []; + +export default { + onLoad() { + if (!ChatInputActions?.prototype?.render || !ChatInputSendButton?.prototype?.render) return; + unpatches.push( + after("render", ChatInputActions.prototype, (args, ret) => { + return React.createElement( + View, + { style: { flexDirection: "row", alignItems: "center" } }, + ret, + React.createElement(AvatarAction) + ); + }) + ); + unpatches.push( + after("render", ChatInputSendButton.prototype, (args, ret) => { + setImmediate(() => { + setImmediate(() => { + if (args?.[1]?.current) { + sendBtnRef = args[1].current; + const origSetHasText = sendBtnRef?.setHasText; + unpatches.push(() => { if (sendBtnRef && origSetHasText) sendBtnRef.setHasText = origSetHasText; }); + if (sendBtnRef) { + sendBtnRef.setHasText = (hasText_: boolean) => { + hasText = hasText_; + if (origSetHasText) return origSetHasText.call(sendBtnRef, hasText_); + }; + } + } + }); + }); + }) + ); + }, + onUnload() { + for (const unpatch of unpatches) unpatch?.(); + unpatches.length = 0; + }, + settings: ChatboxAvatarSettings, +}; diff --git a/plugins/ChatboxAvatar/src/settings.tsx b/plugins/ChatboxAvatar/src/settings.tsx new file mode 100644 index 0000000..e4005eb --- /dev/null +++ b/plugins/ChatboxAvatar/src/settings.tsx @@ -0,0 +1,101 @@ +import { plugin } from "@vendetta"; +import { useProxy } from "@vendetta/storage"; +import { React, ReactNative } from "@vendetta/metro/common"; +import { findByProps } from "@vendetta/metro"; + +const { ScrollView } = ReactNative; +const { TableRowGroup, TableCheckboxRow, Stack } = findByProps( + "TableCheckboxRow", "TableRowGroup", "Stack" +); + +plugin.storage.pressAction ??= "profile"; +plugin.storage.longPressAction ??= "server"; +plugin.storage.showStatusCutout ??= false; +plugin.storage.collapseWhileTyping ??= false; + +export default function ChatboxAvatarSettings() { + useProxy(plugin.storage); + const [, forceUpdate] = React.useReducer((x) => x + 1, 0); + + return ( + + + + { + plugin.storage.pressAction = "profile"; + forceUpdate(); + }} + /> + { + plugin.storage.pressAction = "server"; + forceUpdate(); + }} + /> + + + + { + plugin.storage.longPressAction = "profile"; + forceUpdate(); + }} + /> + { + plugin.storage.longPressAction = "server"; + forceUpdate(); + }} + /> + + + + { + plugin.storage.showStatusCutout = true; + forceUpdate(); + }} + /> + { + plugin.storage.showStatusCutout = false; + forceUpdate(); + }} + /> + + + + { + plugin.storage.collapseWhileTyping = true; + forceUpdate(); + }} + /> + { + plugin.storage.collapseWhileTyping = false; + forceUpdate(); + }} + /> + + + + ); +} diff --git a/plugins/Commands/index.ts b/plugins/Commands/index.ts index 9718c11..632a60c 100644 --- a/plugins/Commands/index.ts +++ b/plugins/Commands/index.ts @@ -26,6 +26,7 @@ import { friendInviteRevokeCommand, } from "./src/commands/friendinvites"; import settings from "./settings/settings"; +import patchSidebar from "./sidebar"; if (!storage.factSettings) { storage.factSettings = { @@ -76,6 +77,10 @@ if (!storage.hiddenSettings) { konochanBypassNsfw: false, }; } +// sidebar enabled setting +if (storage.sidebarEnabled === undefined) { + storage.sidebarEnabled = true; +} const commandMap = { catfact: catFactCommand, @@ -102,11 +107,13 @@ const commandMap = { }; let commands: Array<() => void> = []; +let sidebarUnpatch: (() => void) | undefined; export default { onLoad: () => { console.log("[Commands Plugin] Loading..."); +<<<<<<< HEAD // Register commands for (const [key, command] of Object.entries(commandMap)) { if (storage.enabledCommands[key]) { @@ -120,11 +127,35 @@ export default { ); } } +======= + // Patch sidebar if enabled + if (storage.sidebarEnabled !== false) { + try { + sidebarUnpatch = patchSidebar(); + console.log("[Commands Plugin] Sidebar patched successfully"); + } catch (error) { + console.error("[Commands Plugin] Failed to patch sidebar:", error); + } + } + + // Register commands + for (const [key, command] of Object.entries(commandMap)) { + if (storage.enabledCommands[key]) { + try { + commands.push(registerCommand(command as any)); + console.log(`[Commands Plugin] Registered command: ${key}`); + } catch (error) { + console.error( + `[Commands Plugin] Failed to register command ${key}:`, + error, + ); +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) } }, onUnload: () => { console.log("[Commands Plugin] Unloading..."); +<<<<<<< HEAD // Unregister commands commands.forEach((unregister) => { try { @@ -136,4 +167,28 @@ export default { commands = []; }, settings, +======= + // Unregister commands + commands.forEach((unregister) => { + try { + unregister(); + } catch (error) { + // Ignore errors during cleanup + } + }); + commands = []; + + // Unpatch sidebar + if (sidebarUnpatch) { + try { + sidebarUnpatch(); + sidebarUnpatch = undefined; + console.log("[Commands Plugin] Sidebar unpatched"); + } catch (error) { + console.error("[Commands Plugin] Failed to unpatch sidebar:", error); + } + } + }, + settings, +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) }; diff --git a/plugins/Commands/settings/settings.tsx b/plugins/Commands/settings/settings.tsx index dea4501..3a0ace3 100644 --- a/plugins/Commands/settings/settings.tsx +++ b/plugins/Commands/settings/settings.tsx @@ -71,8 +71,8 @@ storage.hiddenSettings ??= { konochanBypassNsfw: false, }; -// Sidebar setting -storage.sidebarEnabled ??= false; +// Sidebar setting (enabled by default) +storage.sidebarEnabled ??= true; // MAIN SETTINGS COMPONENT export default function Settings() { diff --git a/plugins/multi-scrobbler/src/index.tsx b/plugins/multi-scrobbler/src/index.tsx index e91c160..7ec92d6 100644 --- a/plugins/multi-scrobbler/src/index.tsx +++ b/plugins/multi-scrobbler/src/index.tsx @@ -8,6 +8,7 @@ import { UserStore } from "./modules"; import { serviceFactory } from "./services/ServiceFactory"; import Settings from "./ui/pages/Settings"; +import patchSidebar from "./sidebar"; export const pluginState = { pluginStopped: false, @@ -21,6 +22,8 @@ export const pluginState = { lastTrackUrl?: string; }; +let sidebarUnpatch: (() => void) | undefined; + // Initialize default settings const defaultSettings: LFMSettings = Constants.DEFAULT_SETTINGS; Object.keys(defaultSettings).forEach((key) => { @@ -28,6 +31,8 @@ Object.keys(defaultSettings).forEach((key) => { plugin.storage[key] ?? defaultSettings[key as keyof typeof defaultSettings]; }); +plugin.storage.addToSidebar ??= false; + export const currentSettings = new Proxy(plugin.storage, { get(target, prop: string) { return target[prop]; @@ -119,13 +124,87 @@ export default { console.log("[Multi-Scrobbler] Loading..."); pluginState.pluginStopped = false; +<<<<<<< HEAD validateAndInitialize(); }, +======= + // Patch sidebar if enabled + if (currentSettings.addToSidebar !== false) { + try { + sidebarUnpatch = patchSidebar(); + console.log("[Multi-Scrobbler] Sidebar patched successfully"); + } catch (error) { + console.error("[Multi-Scrobbler] Failed to patch sidebar:", error); + } + } + + validateAndInitialize(); + }, +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) onUnload() { console.log("[Multi-Scrobbler] Unloading..."); pluginState.pluginStopped = true; +<<<<<<< HEAD +======= + // Unpatch sidebar + if (sidebarUnpatch) { + try { + sidebarUnpatch(); + sidebarUnpatch = undefined; + console.log("[Multi-Scrobbler] Sidebar unpatched"); + } catch (error) { + console.error("[Multi-Scrobbler] Failed to unpatch sidebar:", error); + } + } + + stop(); + }, + + async onSettingsUpdate(newSettings: any) { + const oldService = currentSettings.service; + const newService = newSettings.service; + const oldSidebar = currentSettings.addToSidebar; + const newSidebar = newSettings.addToSidebar; + + Object.assign(currentSettings, newSettings); + + // Check if sidebar setting changed + if (oldSidebar !== newSidebar) { + if (newSidebar) { + try { + sidebarUnpatch = patchSidebar(); + console.log("[Multi-Scrobbler] Sidebar enabled"); + } catch (error) { + console.error("[Multi-Scrobbler] Failed to enable sidebar:", error); + } + } else { + if (sidebarUnpatch) { + try { + sidebarUnpatch(); + } catch (e) { + console.error("[Multi-Scrobbler] Failed to unpatch sidebar:", e); + } + sidebarUnpatch = undefined; + console.log("[Multi-Scrobbler] Sidebar disabled"); + } + } + } + + if (oldService !== newService && newService) { + console.log(`[Multi-Scrobbler] Service changed from ${oldService || "none"} to ${newService}`); + try { + await switchService(newService); + } catch (e) { + console.error("[Multi-Scrobbler] Failed to switch service:", e); + } + } else if (!pluginState.pluginStopped && currentSettings.service) { + tryInitialize(); + } else if (!currentSettings.service) { + console.log("[Multi-Scrobbler] Service unselected, stopping plugin..."); + try { +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) stop(); }, @@ -133,6 +212,7 @@ export default { const oldService = currentSettings.service; const newService = newSettings.service; +<<<<<<< HEAD Object.assign(currentSettings, newSettings); if (oldService !== newService && newService) { @@ -163,3 +243,7 @@ export default { settings: Settings, }; +======= + settings: Settings, +}; +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) diff --git a/plugins/multi-scrobbler/src/ui/pages/Settings.tsx b/plugins/multi-scrobbler/src/ui/pages/Settings.tsx index 16b3bb7..02e9879 100644 --- a/plugins/multi-scrobbler/src/ui/pages/Settings.tsx +++ b/plugins/multi-scrobbler/src/ui/pages/Settings.tsx @@ -229,6 +229,7 @@ export default function Settings() { /> +<<<<<<< HEAD {/* Plugin Configuration */} +======= + {/* Plugin Configuration */} + + } + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Display Settings", + render: DisplaySettingsPage, + }) + } + /> + } + onPress={() => + navigation.push("VendettaCustomPage", { + title: "RPC Customization", + render: RPCCustomizationSettingsPage, + }) + } + /> + } + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Ignore List Settings", + render: IgnoreListSettingsPage, + }) + } + /> + } + onPress={() => + navigation.push("VendettaCustomPage", { + title: "Logging Settings", + render: LoggingSettingsPage, + }) + } + /> + { + setStorage("addToSidebar", value); + forceUpdate(); + }} + /> + +>>>>>>> parent of ecd97c7 (feat: detach Sidebar patches as they) {/* About */}