Drop SpotifyActivityToggle
This commit is contained in:
parent
334c39decc
commit
3165f6e2aa
4 changed files with 48 additions and 144 deletions
|
|
@ -19,6 +19,7 @@ import { Margins } from "@utils/margins";
|
|||
import { classes } from "@utils/misc";
|
||||
import { getStylusWebStoreUrl } from "@utils/web";
|
||||
import { React, Select, showToast, TextInput, Toasts, useEffect, useMemo, useRef, useState } from "@webpack/common";
|
||||
import { SyntheticEvent } from "react";
|
||||
|
||||
import { OnlineThemesSection } from "./OnlineThemes";
|
||||
import { QuickActionsSection } from "./QuickActions";
|
||||
|
|
@ -113,12 +114,7 @@ function ThemesTab() {
|
|||
}
|
||||
}
|
||||
|
||||
async function onFileUpload(e: React.SyntheticEvent<HTMLInputElement>) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (!e.currentTarget?.files?.length) return;
|
||||
const { files } = e.currentTarget;
|
||||
|
||||
async function doUploadThemes(files: ArrayLike<File>) {
|
||||
const uploads = Array.from(files, file => {
|
||||
const { name } = file;
|
||||
if (!name.endsWith(".css")) return;
|
||||
|
|
@ -138,6 +134,47 @@ function ThemesTab() {
|
|||
refreshLocalThemes();
|
||||
}
|
||||
|
||||
async function onFileUpload(e: SyntheticEvent<HTMLInputElement>) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!e.currentTarget?.files?.length) return;
|
||||
await doUploadThemes(e.currentTarget.files);
|
||||
}
|
||||
|
||||
function useDropFile(refreshThemes: Function) {
|
||||
useEffect(() => {
|
||||
const onDragOver = (e: DragEvent) => {
|
||||
if (!e.dataTransfer?.items.length) return;
|
||||
if (!Array.from(e.dataTransfer.items).some(item => item.kind === "file" && item.getAsFile()?.name.endsWith(".css")))
|
||||
return;
|
||||
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = "copy";
|
||||
};
|
||||
|
||||
const onDrop = async (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!e.dataTransfer?.files.length) return;
|
||||
|
||||
await doUploadThemes(
|
||||
Array.from(e.dataTransfer.files).filter(file => file.name.endsWith(".css"))
|
||||
);
|
||||
|
||||
refreshThemes();
|
||||
};
|
||||
|
||||
window.addEventListener("dragover", onDragOver);
|
||||
window.addEventListener("drop", onDrop);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("dragover", onDragOver);
|
||||
window.removeEventListener("drop", onDrop);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function addThemeLink(link: string) {
|
||||
if (!themeLinkValid) return;
|
||||
if (settings.themeLinks.includes(link)) return;
|
||||
|
|
@ -147,6 +184,9 @@ function ThemesTab() {
|
|||
refreshOnlineThemes();
|
||||
}
|
||||
|
||||
// This condition is compile time so conditional hook is okay
|
||||
if (IS_WEB) useDropFile(refreshLocalThemes);
|
||||
|
||||
async function refreshOnlineThemes() {
|
||||
const themes = await Promise.all(
|
||||
settings.themeLinks.map(async link => {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ensureSafePath } from "@main/ipcMain";
|
||||
import { DATA_DIR } from "@main/utils/constants";
|
||||
import { ensureSafePath } from "@main/utils/ensureSafePath";
|
||||
import { randomUUID } from "crypto";
|
||||
import { dialog, type IpcMainInvokeEvent } from "electron";
|
||||
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
||||
|
|
|
|||
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { UserAreaButton, UserAreaRenderProps } from "@api/UserArea";
|
||||
import equicordToolbox from "@equicordplugins/equicordToolbox";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Constants, Menu, RestAPI, useEffect, useState } from "@webpack/common";
|
||||
|
||||
let spotifyId: string | null = null;
|
||||
let showActivity = false;
|
||||
let isLoaded = false;
|
||||
let forceUpdate: (() => void) | null = null;
|
||||
|
||||
function SpotifyIcon({ className, enabled }: { className?: string; enabled: boolean; }) {
|
||||
const redLinePath = "M48.54 4.54a2.2 2.2 0 0 0-3.08-3.08l-44 44a2.2 2.2 0 1 0 3.08 3.08Z";
|
||||
const maskBlackPath = "M50.376 8.248 41.752-.376-.376 41.752 8.248 50.376Z";
|
||||
|
||||
return (
|
||||
<svg className={className} width="20" height="20" viewBox="0 0 50 50">
|
||||
<path
|
||||
fill={!enabled ? "var(--status-danger)" : "currentColor"}
|
||||
mask={!enabled ? "url(#spotifyActivityMask)" : void 0}
|
||||
d="M25.009,1.982C12.322,1.982,2,12.304,2,24.991S12.322,48,25.009,48s23.009-10.321,23.009-23.009S37.696,1.982,25.009,1.982z M34.748,35.333c-0.289,0.434-0.765,0.668-1.25,0.668c-0.286,0-0.575-0.081-0.831-0.252C30.194,34.1,26,33,22.5,33.001 c-3.714,0.002-6.498,0.914-6.526,0.923c-0.784,0.266-1.635-0.162-1.897-0.948s0.163-1.636,0.949-1.897 c0.132-0.044,3.279-1.075,7.474-1.077C26,30,30.868,30.944,34.332,33.253C35.022,33.713,35.208,34.644,34.748,35.333z M37.74,29.193 c-0.325,0.522-0.886,0.809-1.459,0.809c-0.31,0-0.624-0.083-0.906-0.26c-4.484-2.794-9.092-3.385-13.062-3.35 c-4.482,0.04-8.066,0.895-8.127,0.913c-0.907,0.258-1.861-0.272-2.12-1.183c-0.259-0.913,0.272-1.862,1.184-2.12 c0.277-0.079,3.854-0.959,8.751-1c4.465-0.037,10.029,0.61,15.191,3.826C37.995,27.328,38.242,28.388,37.74,29.193z M40.725,22.013 C40.352,22.647,39.684,23,38.998,23c-0.344,0-0.692-0.089-1.011-0.275c-5.226-3.068-11.58-3.719-15.99-3.725 c-0.021,0-0.042,0-0.063,0c-5.333,0-9.44,0.938-9.481,0.948c-1.078,0.247-2.151-0.419-2.401-1.495 c-0.25-1.075,0.417-2.149,1.492-2.4C11.729,16.01,16.117,15,21.934,15c0.023,0,0.046,0,0.069,0 c4.905,0.007,12.011,0.753,18.01,4.275C40.965,19.835,41.284,21.061,40.725,22.013z"
|
||||
/>
|
||||
{!enabled && <>
|
||||
<path fill="var(--status-danger)" d={redLinePath} />
|
||||
<mask id="spotifyActivityMask">
|
||||
<rect fill="white" x="0" y="0" width="50" height="50" />
|
||||
<path fill="black" d={maskBlackPath} />
|
||||
</mask>
|
||||
</>}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function SpotifyActivityToggleButton({ iconForeground, hideTooltips, nameplate }: UserAreaRenderProps) {
|
||||
const { location } = settings.use(["location"]);
|
||||
const [, rerender] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
forceUpdate = () => rerender(n => n + 1);
|
||||
return () => { forceUpdate = null; };
|
||||
}, []);
|
||||
|
||||
if (!isLoaded || !spotifyId || location !== "PANEL" && isPluginEnabled(equicordToolbox.name)) return null;
|
||||
|
||||
return (
|
||||
<UserAreaButton
|
||||
tooltipText={hideTooltips ? void 0 : showActivity ? "Turn off Spotify activity" : "Turn on Spotify activity"}
|
||||
icon={<SpotifyIcon className={iconForeground} enabled={showActivity} />}
|
||||
role="switch"
|
||||
aria-checked={showActivity}
|
||||
redGlow={!showActivity}
|
||||
plated={nameplate != null}
|
||||
onClick={async () => {
|
||||
showActivity = !showActivity;
|
||||
forceUpdate?.();
|
||||
|
||||
await RestAPI.patch({
|
||||
url: Constants.Endpoints.CONNECTION("spotify", spotifyId),
|
||||
body: { show_activity: showActivity },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
location: {
|
||||
type: OptionType.SELECT,
|
||||
description: "Where to show the Spotify toggle button.",
|
||||
options: [
|
||||
{ label: "Next to Mute/Deafen", value: "PANEL", default: true },
|
||||
{ label: "Equicord Toolbox", value: "TOOLBOX" }
|
||||
],
|
||||
get hidden() {
|
||||
return !isPluginEnabled(equicordToolbox.name);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "SpotifyActivityToggle",
|
||||
description: "Adds a toggle button for Spotify activity visibility.",
|
||||
dependencies: ["UserAreaAPI"],
|
||||
tags: ["Activity", "Utility"],
|
||||
authors: [Devs.thororen],
|
||||
settings,
|
||||
|
||||
userAreaButton: {
|
||||
icon: (props: { className?: string; }) => <SpotifyIcon {...props} enabled={showActivity} />,
|
||||
render: SpotifyActivityToggleButton
|
||||
},
|
||||
|
||||
toolboxActions() {
|
||||
const { location } = settings.use(["location"]);
|
||||
|
||||
if (!spotifyId || location !== "TOOLBOX") return null;
|
||||
|
||||
return (
|
||||
<Menu.MenuItem
|
||||
id="spotify-activity-toggle-toolbox"
|
||||
label={showActivity ? "Disable Spotify Activity" : "Enable Spotify Activity"}
|
||||
action={async () => {
|
||||
showActivity = !showActivity;
|
||||
|
||||
await RestAPI.patch({
|
||||
url: Constants.Endpoints.CONNECTION("spotify", spotifyId),
|
||||
body: { show_activity: showActivity },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
flux: {
|
||||
async CONNECTION_OPEN() {
|
||||
const { body } = await RestAPI.get({ url: Constants.Endpoints.CONNECTIONS });
|
||||
if (!body) return;
|
||||
|
||||
const spotifyConn = body.find((c: { type: string; }) => c.type === "spotify");
|
||||
if (spotifyConn) {
|
||||
spotifyId = spotifyConn.id;
|
||||
showActivity = spotifyConn.show_activity;
|
||||
}
|
||||
isLoaded = true;
|
||||
forceUpdate?.();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ensureSafePath } from "@main/ipcMain";
|
||||
import { THEMES_DIR } from "@main/utils/constants";
|
||||
import { ensureSafePath } from "@main/utils/ensureSafePath";
|
||||
import { IpcMainInvokeEvent } from "electron";
|
||||
import { existsSync, writeFileSync } from "fs";
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue