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 */}