[Themes] Implement chat background image (#64)
* [Themes] hardcode fuyu chat bg * [Themes > BG] listen to theme file * remove .apply() * some uhh misc changes * readd * how * [Global] Minor changes --------- Co-authored-by: Beef <beefers@riseup.net>
This commit is contained in:
parent
ef0b162d3a
commit
20310db733
5 changed files with 40 additions and 10 deletions
11
src/def.d.ts
vendored
11
src/def.d.ts
vendored
|
@ -124,8 +124,17 @@ interface ThemeData {
|
||||||
description?: string;
|
description?: string;
|
||||||
authors?: Author[];
|
authors?: Author[];
|
||||||
spec: number;
|
spec: number;
|
||||||
semanticColors?: Record<string, string[]>;
|
semanticColors?: Record<string, (string | false)[]>;
|
||||||
rawColors?: Record<string, string>;
|
rawColors?: Record<string, string>;
|
||||||
|
background?: {
|
||||||
|
url: string;
|
||||||
|
blur?: number;
|
||||||
|
/**
|
||||||
|
* The alpha value of the background.
|
||||||
|
* `CHAT_BACKGROUND` of semanticColors alpha value will be ignored when this is specified
|
||||||
|
*/
|
||||||
|
alpha?: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Theme {
|
interface Theme {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { patchLogHook } from "@lib/debug";
|
||||||
import { patchCommands } from "@lib/commands";
|
import { patchCommands } from "@lib/commands";
|
||||||
import { initPlugins } from "@lib/plugins";
|
import { initPlugins } from "@lib/plugins";
|
||||||
import { patchAssets } from "@ui/assets";
|
import { patchAssets } from "@ui/assets";
|
||||||
|
import { patchChatBackground } from "@lib/themes";
|
||||||
import initQuickInstall from "@ui/quickInstall";
|
import initQuickInstall from "@ui/quickInstall";
|
||||||
import initSafeMode from "@ui/safeMode";
|
import initSafeMode from "@ui/safeMode";
|
||||||
import initSettings from "@ui/settings";
|
import initSettings from "@ui/settings";
|
||||||
|
@ -15,6 +16,7 @@ export default async () => {
|
||||||
patchLogHook(),
|
patchLogHook(),
|
||||||
patchAssets(),
|
patchAssets(),
|
||||||
patchCommands(),
|
patchCommands(),
|
||||||
|
patchChatBackground(),
|
||||||
initFixes(),
|
initFixes(),
|
||||||
initSafeMode(),
|
initSafeMode(),
|
||||||
initSettings(),
|
initSettings(),
|
||||||
|
|
|
@ -68,7 +68,7 @@ export async function evalPlugin(plugin: Plugin) {
|
||||||
|
|
||||||
const raw = (0, eval)(pluginString)(vendettaForPlugins);
|
const raw = (0, eval)(pluginString)(vendettaForPlugins);
|
||||||
const ret = typeof raw == "function" ? raw() : raw;
|
const ret = typeof raw == "function" ? raw() : raw;
|
||||||
return ret.default || ret;
|
return ret?.default || ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startPlugin(id: string) {
|
export async function startPlugin(id: string) {
|
||||||
|
@ -83,12 +83,12 @@ export async function startPlugin(id: string) {
|
||||||
pluginRet.onLoad?.();
|
pluginRet.onLoad?.();
|
||||||
}
|
}
|
||||||
plugin.enabled = true;
|
plugin.enabled = true;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
logger.error(`Plugin ${plugin.id} errored whilst loading, and will be unloaded`, e);
|
logger.error(`Plugin ${plugin.id} errored whilst loading, and will be unloaded`, e);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loadedPlugins[plugin.id]?.onUnload?.();
|
loadedPlugins[plugin.id]?.onUnload?.();
|
||||||
} catch(e2) {
|
} catch (e2) {
|
||||||
logger.error(`Plugin ${plugin.id} errored whilst unloading`, e2);
|
logger.error(`Plugin ${plugin.id} errored whilst unloading`, e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +106,10 @@ export function stopPlugin(id: string, disable = true) {
|
||||||
if (!settings.safeMode?.enabled) {
|
if (!settings.safeMode?.enabled) {
|
||||||
try {
|
try {
|
||||||
pluginRet?.onUnload?.();
|
pluginRet?.onUnload?.();
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
logger.error(`Plugin ${plugin.id} errored whilst unloading`, e);
|
logger.error(`Plugin ${plugin.id} errored whilst unloading`, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete loadedPlugins[id];
|
delete loadedPlugins[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Theme, ThemeData } from "@types";
|
import { Theme, ThemeData } from "@types";
|
||||||
import { findByProps } from "@metro/filters";
|
|
||||||
import { ReactNative, chroma } from "@metro/common";
|
import { ReactNative, chroma } from "@metro/common";
|
||||||
|
import { findByName, findByProps } from "@metro/filters";
|
||||||
import { instead } from "@lib/patcher";
|
import { instead } from "@lib/patcher";
|
||||||
import { createFileBackend, createMMKVBackend, createStorage, wrapSync, awaitSyncWrapper } from "@lib/storage";
|
import { createFileBackend, createMMKVBackend, createStorage, wrapSync, awaitSyncWrapper } from "@lib/storage";
|
||||||
import { safeFetch } from "@utils";
|
import { safeFetch } from "@utils";
|
||||||
|
@ -19,6 +19,21 @@ async function writeTheme(theme: Theme | {}) {
|
||||||
await createFileBackend("vendetta_theme.json").set(theme);
|
await createFileBackend("vendetta_theme.json").set(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function patchChatBackground() {
|
||||||
|
const currentTheme = getCurrentTheme()?.data?.background;
|
||||||
|
if (!currentTheme) return;
|
||||||
|
|
||||||
|
const MessagesWrapperConnected = findByName("MessagesWrapperConnected", false);
|
||||||
|
if (!MessagesWrapperConnected) return;
|
||||||
|
|
||||||
|
return instead("default", MessagesWrapperConnected, (args, orig) => React.createElement(ReactNative.ImageBackground, {
|
||||||
|
style: { flex: 1, height: "100%" },
|
||||||
|
source: { uri: currentTheme.url },
|
||||||
|
blurRadius: currentTheme.blur,
|
||||||
|
children: orig(...args),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeToHex(colorString: string): string {
|
function normalizeToHex(colorString: string): string {
|
||||||
if (chroma.valid(colorString)) return chroma(colorString).hex();
|
if (chroma.valid(colorString)) return chroma(colorString).hex();
|
||||||
|
|
||||||
|
@ -39,7 +54,7 @@ function processData(data: ThemeData) {
|
||||||
|
|
||||||
for (const key in semanticColors) {
|
for (const key in semanticColors) {
|
||||||
for (const index in semanticColors[key]) {
|
for (const index in semanticColors[key]) {
|
||||||
semanticColors[key][index] = normalizeToHex(semanticColors[key][index]);
|
semanticColors[key][index] &&= normalizeToHex(semanticColors[key][index] as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +173,10 @@ export async function initThemes() {
|
||||||
const themeIndex = theme === "amoled" ? 2 : theme === "light" ? 1 : 0;
|
const themeIndex = theme === "amoled" ? 2 : theme === "light" ? 1 : 0;
|
||||||
|
|
||||||
const semanticColorVal = selectedTheme.data?.semanticColors?.[name]?.[themeIndex];
|
const semanticColorVal = selectedTheme.data?.semanticColors?.[name]?.[themeIndex];
|
||||||
|
if (name === "CHAT_BACKGROUND" && typeof selectedTheme.data?.background?.alpha === "number") {
|
||||||
|
return chroma(semanticColorVal || "black").alpha(1 - selectedTheme.data.background.alpha).hex();
|
||||||
|
}
|
||||||
|
|
||||||
if (semanticColorVal) return semanticColorVal;
|
if (semanticColorVal) return semanticColorVal;
|
||||||
|
|
||||||
const rawValue = selectedTheme.data?.rawColors?.[colorDef.raw];
|
const rawValue = selectedTheme.data?.rawColors?.[colorDef.raw];
|
||||||
|
|
|
@ -62,7 +62,7 @@ interface Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs: Tab[] = [
|
const tabs: Tab[] = [
|
||||||
{ id: "message",title: "Message" },
|
{ id: "message", title: "Message" },
|
||||||
{ id: "stack", title: "Stack Trace" },
|
{ id: "stack", title: "Stack Trace" },
|
||||||
{ id: "componentStack", title: "Component", trimWhitespace: true },
|
{ id: "componentStack", title: "Component", trimWhitespace: true },
|
||||||
];
|
];
|
||||||
|
@ -74,7 +74,7 @@ export default () => after("render", ErrorBoundary.prototype, function (this: an
|
||||||
this.state.activeTab ??= "message";
|
this.state.activeTab ??= "message";
|
||||||
const tabData = tabs.find(t => t.id === this.state.activeTab);
|
const tabData = tabs.find(t => t.id === this.state.activeTab);
|
||||||
const errorText: string = this.state.error[this.state.activeTab];
|
const errorText: string = this.state.error[this.state.activeTab];
|
||||||
|
|
||||||
// This is in the patch and not outside of it so that we can use `this`, e.g. for setting state
|
// This is in the patch and not outside of it so that we can use `this`, e.g. for setting state
|
||||||
const buttons: Button[] = [
|
const buttons: Button[] = [
|
||||||
{ text: "Restart Discord", onPress: this.handleReload },
|
{ text: "Restart Discord", onPress: this.handleReload },
|
||||||
|
|
Loading…
Reference in a new issue