mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-07 13:43:03 -04:00
add wallpaperFree (#262)
* add wallpaperFree * fix lint ???????? * fix lint again * Fixes --------- Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
1c24c4d173
commit
78209ef7bf
7 changed files with 453 additions and 1 deletions
|
@ -98,7 +98,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
- JumpToStart by Samwich
|
||||
- KeyboardSounds by HypedDomi
|
||||
- KeywordNotify by camila314 & x3rt
|
||||
- - LastActive by Crxa
|
||||
- LastActive by Crxa
|
||||
- LimitMiddleClickPaste by no dev listed
|
||||
- LoginWithQR by nexpid
|
||||
- MediaPlaybackSpeed by D3SOX
|
||||
|
@ -177,6 +177,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
|
|||
- ViewRawVariant by Kyuuhachi
|
||||
- VoiceChatUtilities by D3SOX
|
||||
- VoiceJoinMessages by Sqaaakoi & maintained by thororen
|
||||
- WallpaperFree by Joona
|
||||
- WebpackTarball by Kyuuhachi
|
||||
- WhitelistedEmojis by Creations
|
||||
- WhosWatching by fres
|
||||
|
|
67
src/equicordplugins/wallpaperFree/components/ctxmenu.tsx
Normal file
67
src/equicordplugins/wallpaperFree/components/ctxmenu.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { ChannelStore, FluxDispatcher, Menu } from "@webpack/common";
|
||||
|
||||
import { SetCustomWallpaperModal, SetDiscordWallpaperModal } from "./modal";
|
||||
import { ChatWallpaperStore, fetchWallpapers } from "./util";
|
||||
|
||||
|
||||
const addWallpaperMenu = (channelId?: string, guildId?: string) => {
|
||||
const setWallpaper = (url?: string) => {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "VC_WALLPAPER_FREE_CHANGE",
|
||||
channelId,
|
||||
guildId,
|
||||
url,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Menu.MenuItem label="Wallpaper Free" key="vc-wpfree-menu" id="vc-wpfree-menu">
|
||||
<Menu.MenuItem
|
||||
label="Set custom wallpaper"
|
||||
id="vc-wpfree-set-custom"
|
||||
action={() => openModal(props => <SetCustomWallpaperModal props={props} onSelect={setWallpaper} />)}
|
||||
/>
|
||||
<Menu.MenuItem
|
||||
label="Set a Discord wallpaper"
|
||||
id="vc-wpfree-set-discord"
|
||||
action={async () => {
|
||||
ChatWallpaperStore.shouldFetchWallpapers && await fetchWallpapers();
|
||||
openModal(props => <SetDiscordWallpaperModal props={props} onSelect={setWallpaper} />);
|
||||
}}
|
||||
/>
|
||||
<Menu.MenuSeparator />
|
||||
<Menu.MenuItem
|
||||
label="Remove Custom Wallpaper"
|
||||
id="vc-wpfree-remove"
|
||||
color="danger"
|
||||
action={() => setWallpaper(void 0)}
|
||||
/>
|
||||
</Menu.MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
const UserContextPatch: NavContextMenuPatchCallback = (children, args) => {
|
||||
if (!args.user) return;
|
||||
const dmChannelId = ChannelStore.getDMFromUserId(args.user.id);
|
||||
children.push(addWallpaperMenu(dmChannelId));
|
||||
};
|
||||
|
||||
const ChannelContextPatch: NavContextMenuPatchCallback = (children, args) => {
|
||||
if (!args.channel) return;
|
||||
children.push(addWallpaperMenu(args.channel.id));
|
||||
};
|
||||
|
||||
const GuildContextPatch: NavContextMenuPatchCallback = (children, args) => {
|
||||
if (!args.guild) return;
|
||||
children.push(addWallpaperMenu(void 0, args.guild.id));
|
||||
};
|
||||
|
||||
export { ChannelContextPatch, GuildContextPatch, UserContextPatch };
|
116
src/equicordplugins/wallpaperFree/components/modal.tsx
Normal file
116
src/equicordplugins/wallpaperFree/components/modal.tsx
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
|
||||
import { Button, lodash, Text, TextInput, useState, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { ChatWallpaperStore, Wallpaper } from "./util";
|
||||
|
||||
interface Props {
|
||||
props: ModalProps;
|
||||
onSelect: (url: string) => void;
|
||||
}
|
||||
|
||||
export function SetCustomWallpaperModal({ props, onSelect }: Props) {
|
||||
const [url, setUrl] = useState("");
|
||||
|
||||
return (
|
||||
<ModalRoot {...props} size={ModalSize.SMALL}>
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/normal" style={{ marginBottom: 8 }}>
|
||||
Set a custom wallpaper
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||
|
||||
<TextInput
|
||||
placeholder="The image url"
|
||||
value={url}
|
||||
onChange={setUrl}
|
||||
autoFocus
|
||||
/>
|
||||
{url && (
|
||||
<img
|
||||
src={url}
|
||||
alt="Wallpaper preview"
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
objectFit: "cover",
|
||||
border: "1px solid var(--background-modifier-accent)",
|
||||
borderRadius: 8
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
|
||||
<Button onClick={props.onClose}>Cancel</Button>
|
||||
<Button
|
||||
color={Button.Colors.BRAND}
|
||||
onClick={() => {
|
||||
onSelect(url);
|
||||
props.onClose();
|
||||
}}
|
||||
disabled={!url}
|
||||
>Apply</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalContent>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export function SetDiscordWallpaperModal({ props, onSelect }: Props) {
|
||||
const discordWallpapers: Wallpaper[] = useStateFromStores([ChatWallpaperStore], () => ChatWallpaperStore.wallpapers);
|
||||
|
||||
return (
|
||||
<ModalRoot {...props} size={ModalSize.MEDIUM}>
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/normal" style={{ marginBottom: 8 }}>
|
||||
Choose a Discord Wallpaper
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalContent>
|
||||
<div className="vc-wpfree-discord-wp-modal">
|
||||
{lodash.chunk(discordWallpapers, 2).map(group => {
|
||||
const main = group[0];
|
||||
return (
|
||||
<div key={main.id} className="vc-wpfree-discord-wp-icon-container">
|
||||
<figure style={{ margin: 0, textAlign: "center" }}>
|
||||
<img
|
||||
className="vc-wpfree-discord-wp-icon-img"
|
||||
src={`https://cdn.discordapp.com/assets/content/${main.default.icon}`}
|
||||
alt={main.label}
|
||||
/>
|
||||
<figcaption>
|
||||
<Text variant="text-md/normal">{main.label}</Text>
|
||||
</figcaption>
|
||||
</figure>
|
||||
<div className="vc-wpfree-discord-set-buttons">
|
||||
{group.map(wp => (
|
||||
<Button
|
||||
key={wp.id}
|
||||
size={Button.Sizes.SMALL}
|
||||
color={Button.Colors.BRAND}
|
||||
onClick={() => {
|
||||
onSelect(`https://cdn.discordapp.com/assets/content/${wp.default.asset}`);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
{wp.isBlurred ? "Blurred" : "Normal"}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ModalContent>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
|
70
src/equicordplugins/wallpaperFree/components/util.tsx
Normal file
70
src/equicordplugins/wallpaperFree/components/util.tsx
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { openModal } from "@utils/modal";
|
||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||
import { Button, FluxDispatcher } from "@webpack/common";
|
||||
|
||||
import { SetCustomWallpaperModal, SetDiscordWallpaperModal } from "./modal";
|
||||
|
||||
export const ChatWallpaperStore = findStoreLazy("ChatWallpaperStore");
|
||||
export const fetchWallpapers = findByCodeLazy('type:"FETCH_CHAT_WALLPAPERS_SUCCESS"');
|
||||
|
||||
export function GlobalDefaultComponent() {
|
||||
const setGlobal = (url?: string) => {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "VC_WALLPAPER_FREE_CHANGE_GLOBAL",
|
||||
url,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => {
|
||||
openModal(props => <SetCustomWallpaperModal props={props} onSelect={setGlobal} />);
|
||||
}}>Set a global custom wallpaper</Button>
|
||||
|
||||
<Button onClick={async () => {
|
||||
ChatWallpaperStore.shouldFetchWallpapers && await fetchWallpapers();
|
||||
openModal(props => <SetDiscordWallpaperModal props={props} onSelect={setGlobal} />);
|
||||
}}>Set a global Discord wallpaper</Button>
|
||||
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
onClick={() => setGlobal(void 0)}
|
||||
>Remove global default wallpaper</Button>
|
||||
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
onClick={() => {
|
||||
// @ts-ignore
|
||||
FluxDispatcher.dispatch({ type: "VC_WALLPAPER_FREE_RESET" });
|
||||
}}
|
||||
>Reset wallpaper data</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export interface Wallpaper {
|
||||
id: string;
|
||||
label: string;
|
||||
default: Default;
|
||||
variants: Variants;
|
||||
isBlurred: boolean;
|
||||
designGroupId: string;
|
||||
}
|
||||
|
||||
export interface Default {
|
||||
asset: string;
|
||||
icon: string;
|
||||
thumbhash: string;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export interface Variants {
|
||||
dark: Default;
|
||||
}
|
86
src/equicordplugins/wallpaperFree/index.tsx
Normal file
86
src/equicordplugins/wallpaperFree/index.tsx
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { useStateFromStores } from "@webpack/common";
|
||||
import { Channel } from "discord-types/general";
|
||||
|
||||
import { ChannelContextPatch, GuildContextPatch, UserContextPatch } from "./components/ctxmenu";
|
||||
import { GlobalDefaultComponent, Wallpaper } from "./components/util";
|
||||
import { WallpaperFreeStore } from "./store";
|
||||
|
||||
|
||||
const settings = definePluginSettings({
|
||||
forceReplace: {
|
||||
description: "If a dm wallpaper is already set, your custom wallpaper will be used instead.",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
},
|
||||
globalDefault: {
|
||||
description: "Set a global default wallpaper for all channels.",
|
||||
type: OptionType.COMPONENT,
|
||||
component: GlobalDefaultComponent
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "WallpaperFree",
|
||||
authors: [Devs.Joona],
|
||||
description: "Use the DM wallpapers anywhere or set a custom wallpaper",
|
||||
patches: [
|
||||
{
|
||||
find: ".wallpaperContainer,",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
match: /return null==(\i).+?\?null:/,
|
||||
replace: "const vcWpFreeCustom = $self.customWallpaper(arguments[0].channel,$1);return !($1||vcWpFreeCustom)?null:"
|
||||
},
|
||||
{
|
||||
match: /,{chatWallpaperState:/,
|
||||
replace: "$&vcWpFreeCustom||"
|
||||
},
|
||||
{
|
||||
match: /(\i=)(.{1,50}""\))/,
|
||||
replace: "$1arguments[0].chatWallpaperState.vcWallpaperUrl||$2"
|
||||
},
|
||||
{
|
||||
match: /(\i\.isViewable&&)(null!=\i)/,
|
||||
replace: "$1($2||arguments[0].chatWallpaperState.vcWallpaperUrl)"
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
settings,
|
||||
contextMenus: {
|
||||
"user-context": UserContextPatch,
|
||||
"channel-context": ChannelContextPatch,
|
||||
"thread-context": ChannelContextPatch,
|
||||
"guild-context": GuildContextPatch,
|
||||
"gdm-context": ChannelContextPatch,
|
||||
},
|
||||
customWallpaper(channel: Channel, wp: Wallpaper | undefined) {
|
||||
const { forceReplace } = settings.use(["forceReplace"]);
|
||||
const url = useStateFromStores([WallpaperFreeStore], () => WallpaperFreeStore.getUrl(channel));
|
||||
|
||||
if (!forceReplace && wp?.id)
|
||||
return wp;
|
||||
|
||||
if (url) {
|
||||
return {
|
||||
wallpaperId: "id",
|
||||
vcWallpaperUrl: url,
|
||||
isViewable: true,
|
||||
};
|
||||
}
|
||||
|
||||
return void 0;
|
||||
},
|
||||
});
|
82
src/equicordplugins/wallpaperFree/store.ts
Normal file
82
src/equicordplugins/wallpaperFree/store.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { FluxDispatcher } from "@webpack/common";
|
||||
import { FluxEmitter, FluxStore } from "@webpack/types";
|
||||
import { Channel } from "discord-types/general";
|
||||
|
||||
interface IFlux {
|
||||
PersistedStore: typeof FluxStore;
|
||||
Emitter: FluxEmitter;
|
||||
}
|
||||
const Flux: IFlux = findByPropsLazy("connectStores");
|
||||
|
||||
export const WallpaperFreeStore = proxyLazy(() => {
|
||||
const wallpaperChannelMap: Map<string, string> = new Map();
|
||||
const wallpaperGuildMap: Map<string, string> = new Map();
|
||||
let globalDefault: string | undefined;
|
||||
|
||||
class WallpaperFreeStore extends Flux.PersistedStore {
|
||||
static persistKey = "WallpaperFreeStore";
|
||||
|
||||
// @ts-ignore
|
||||
initialize(previous: { guildMap: Map<string, string>, channelMap: Map<string, string>, globalDefault: string; } | undefined) {
|
||||
if (!previous)
|
||||
return;
|
||||
|
||||
wallpaperGuildMap.clear();
|
||||
wallpaperChannelMap.clear();
|
||||
for (const [channel, url] of previous.channelMap) {
|
||||
wallpaperChannelMap.set(channel, url);
|
||||
}
|
||||
|
||||
for (const [guild, url] of previous.guildMap) {
|
||||
wallpaperGuildMap.set(guild, url);
|
||||
}
|
||||
globalDefault = previous.globalDefault;
|
||||
}
|
||||
|
||||
getState() {
|
||||
return { guildMap: Array.from(wallpaperGuildMap), channelMap: Array.from(wallpaperChannelMap), globalDefault };
|
||||
}
|
||||
|
||||
getUrl(channel: Channel): string | undefined {
|
||||
return (
|
||||
wallpaperChannelMap.get(channel.id) ??
|
||||
wallpaperGuildMap.get(channel.guild_id) ??
|
||||
globalDefault
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const store = new WallpaperFreeStore(FluxDispatcher, {
|
||||
// @ts-ignore
|
||||
VC_WALLPAPER_FREE_CHANGE({ guildId, channelId, url }: { guildId: string | undefined, channelId: string | undefined, url: string; }) {
|
||||
if (guildId) {
|
||||
wallpaperGuildMap.set(guildId, url);
|
||||
} else if (channelId) {
|
||||
wallpaperChannelMap.set(channelId, url);
|
||||
}
|
||||
store.emitChange();
|
||||
},
|
||||
|
||||
VC_WALLPAPER_FREE_CHANGE_GLOBAL({ url }: { url: string | undefined; }) {
|
||||
globalDefault = url;
|
||||
store.emitChange();
|
||||
},
|
||||
|
||||
VC_WALLPAPER_FREE_RESET() {
|
||||
wallpaperChannelMap.clear();
|
||||
wallpaperGuildMap.clear();
|
||||
globalDefault = void 0;
|
||||
store.emitChange();
|
||||
}
|
||||
});
|
||||
|
||||
return store;
|
||||
});
|
30
src/equicordplugins/wallpaperFree/styles.css
Normal file
30
src/equicordplugins/wallpaperFree/styles.css
Normal file
|
@ -0,0 +1,30 @@
|
|||
.vc-wpfree-discord-wp-modal {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 24px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.vc-wpfree-discord-wp-icon-container {
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.vc-wpfree-discord-wp-icon-img {
|
||||
width: 120px;
|
||||
height: 68px;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
border: 1px solid var(--background-modifier-accent);
|
||||
}
|
||||
|
||||
.vc-wpfree-discord-set-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 12px
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue