From 1eeed0f8b9bbd4bd2cc91dc444f9dc9aa7a89b74 Mon Sep 17 00:00:00 2001 From: pylixonly <82711525+pylixonly@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:46:26 +0800 Subject: [PATCH] refactor: introduce colors preferences and some cleanups --- src/core/vendetta/storage.ts | 6 ++++- src/index.ts | 18 +------------- src/lib/addons/themes/colors/parser.ts | 3 ++- .../themes/colors/patches/background.tsx | 12 ++++------ .../addons/themes/colors/patches/resolver.ts | 2 +- src/lib/addons/themes/colors/preferences.ts | 18 ++++++++++++++ src/lib/addons/themes/index.ts | 24 +++++++++++++++---- 7 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 src/lib/addons/themes/colors/preferences.ts diff --git a/src/core/vendetta/storage.ts b/src/core/vendetta/storage.ts index 19ce87c..f49451b 100644 --- a/src/core/vendetta/storage.ts +++ b/src/core/vendetta/storage.ts @@ -142,7 +142,8 @@ export function wrapSync>(store: T): Awaited { export function awaitStorage(...stores: any[]) { return Promise.all( - stores.map(store => new Promise(res => store[syncAwaitSymbol](res))) + stores.map(store => + new Promise(res => store[syncAwaitSymbol](res))) ); } @@ -150,11 +151,14 @@ export interface StorageBackend { get: () => unknown | Promise; set: (data: unknown) => void | Promise; } + const ILLEGAL_CHARS_REGEX = /[<>:"/\\|?*]/g; + const filePathFixer = (file: string): string => Platform.select({ default: file, ios: FileManager.saveFileToGallery ? file : `Documents/${file}`, }); + const getMMKVPath = (name: string): string => { if (ILLEGAL_CHARS_REGEX.test(name)) { // Replace forbidden characters with hyphens diff --git a/src/index.ts b/src/index.ts index 2845790..55ec53b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,32 +10,16 @@ import { initThemes } from "@lib/addons/themes"; import { patchCommands } from "@lib/api/commands"; import { patchLogHook } from "@lib/api/debug"; import { injectFluxInterceptor } from "@lib/api/flux"; -import { writeFile } from "@lib/api/native/fs"; -import { isPyonLoader, isThemeSupported } from "@lib/api/native/loader"; import { patchJsx } from "@lib/api/react/jsx"; import { logger } from "@lib/utils/logger"; import { patchSettings } from "@ui/settings"; import * as lib from "./lib"; -function maybeLoadThemes() { - if (!isThemeSupported()) return; - - try { - if (isPyonLoader()) { - writeFile("../vendetta_theme.json", "null"); - } - initThemes(); - } catch (e) { - console.error("Failed to initialize themes", e); - } -} - export default async () => { - maybeLoadThemes(); - // Load everything in parallel await Promise.all([ + initThemes(), injectFluxInterceptor(), patchSettings(), patchLogHook(), diff --git a/src/lib/addons/themes/colors/parser.ts b/src/lib/addons/themes/colors/parser.ts index c8c1bb4..fd32653 100644 --- a/src/lib/addons/themes/colors/parser.ts +++ b/src/lib/addons/themes/colors/parser.ts @@ -3,12 +3,13 @@ import chroma from "chroma-js"; import { omit } from "es-toolkit"; import { Platform, processColor } from "react-native"; +import { colorsPref } from "./preferences"; import { ColorManifest, InternalColorDefinition } from "./types"; const tokenRef = findByProps("SemanticColor"); export function parseColorManifest(manifest: ColorManifest): InternalColorDefinition { - const resolveType = (type = "dark") => /* (ColorManager.preferences.type ?? type) */ type === "dark" ? "darker" : "light"; + const resolveType = (type = "dark") => (colorsPref.type ?? type) === "dark" ? "darker" : "light"; if (manifest.spec === 3) { const semanticColorDefinitions: InternalColorDefinition["semantic"] = {}; diff --git a/src/lib/addons/themes/colors/patches/background.tsx b/src/lib/addons/themes/colors/patches/background.tsx index fd809eb..ee62986 100644 --- a/src/lib/addons/themes/colors/patches/background.tsx +++ b/src/lib/addons/themes/colors/patches/background.tsx @@ -1,5 +1,7 @@ +import { colorsPref } from "@lib/addons/themes/colors/preferences"; import { _colorRef } from "@lib/addons/themes/colors/updater"; import { after } from "@lib/api/patcher"; +import { useObservable } from "@lib/api/storage"; import { findInReactTree } from "@lib/utils"; import { lazyDestructure } from "@lib/utils/lazy"; import { findByNameLazy, findByProps } from "@metro"; @@ -12,11 +14,8 @@ const { MessagesWrapper } = lazyDestructure(() => findByProps("MessagesWrapper") export default function patchChatBackground() { const patches = [ after("default", MessagesWrapperConnected, (_, ret) => { - // TODO: support custom preferences - // useObservable([ColorManager.preferences]); - // if (!_colorRef.current || ColorManager.preferences.customBackground === "hidden") return ret; - - if (!_colorRef.current || !_colorRef.current.background?.url) return ret; + useObservable([colorsPref]); + if (!_colorRef.current || !_colorRef.current.background?.url || colorsPref.customBackground === "hidden") return ret; return {ret} ; - } - ), + }), after("render", MessagesWrapper.prototype, (_, ret) => { if (!_colorRef.current || !_colorRef.current.background?.url) return; const messagesComponent = findInReactTree( diff --git a/src/lib/addons/themes/colors/patches/resolver.ts b/src/lib/addons/themes/colors/patches/resolver.ts index 7af7940..17d541c 100644 --- a/src/lib/addons/themes/colors/patches/resolver.ts +++ b/src/lib/addons/themes/colors/patches/resolver.ts @@ -49,7 +49,7 @@ export default function patchDefinitionAndResolver() { const [name, colorDef] = extractInfo(_colorRef.current!.reference, args[1]); let semanticDef = _colorRef.current.semantic[name]; - if (!semanticDef && _colorRef.current?.spec === 2 && name in SEMANTIC_FALLBACK_MAP) { + if (!semanticDef && _colorRef.current.spec === 2 && name in SEMANTIC_FALLBACK_MAP) { semanticDef = _colorRef.current.semantic[SEMANTIC_FALLBACK_MAP[name]]; } diff --git a/src/lib/addons/themes/colors/preferences.ts b/src/lib/addons/themes/colors/preferences.ts new file mode 100644 index 0000000..ba5eb1c --- /dev/null +++ b/src/lib/addons/themes/colors/preferences.ts @@ -0,0 +1,18 @@ +import { createStorage } from "@lib/api/storage"; + +interface BunnyColorPreferencesStorage { + selected: string | null; + type?: "dark" | "light" | null; + customBackground: "hidden" | null; + per?: Record; +} + +export const colorsPref = createStorage( + "themes/colors/preferences.json", + { + dflt: { + selected: null, + customBackground: null + } + } +); diff --git a/src/lib/addons/themes/index.ts b/src/lib/addons/themes/index.ts index fd5502d..dcae18d 100644 --- a/src/lib/addons/themes/index.ts +++ b/src/lib/addons/themes/index.ts @@ -1,10 +1,12 @@ import { awaitStorage, createFileBackend, createMMKVBackend, createStorage, wrapSync } from "@core/vendetta/storage"; -import { getStoredTheme, getThemeFilePath } from "@lib/api/native/loader"; +import { writeFile } from "@lib/api/native/fs"; +import { getStoredTheme, getThemeFilePath, isPyonLoader, isThemeSupported } from "@lib/api/native/loader"; import { safeFetch } from "@lib/utils"; import { Platform } from "react-native"; import initColors from "./colors"; import { applyAndroidAlphaKeys, normalizeToHex } from "./colors/parser"; +import { colorsPref } from "./colors/preferences"; import { VendettaThemeManifest } from "./colors/types"; import { updateBunnyColor } from "./colors/updater"; @@ -123,9 +125,21 @@ export function getThemeFromLoader(): VdThemeInfo | null { /** * @internal */ -export function initThemes() { - const currentTheme = getThemeFromLoader(); - initColors(currentTheme?.data ?? null); +export async function initThemes() { + if (!isThemeSupported()) return; - updateThemes().catch(e => console.error("Failed to update themes", e)); + try { + if (isPyonLoader()) { + writeFile("../vendetta_theme.json", "null"); + } + + await awaitStorage(colorsPref); + + const currentTheme = getThemeFromLoader(); + initColors(currentTheme?.data ?? null); + + updateThemes().catch(e => console.error("Failed to update themes", e)); + } catch (e) { + console.error("Failed to initialize themes", e); + } }