From 6326b57d6fc13e68d73d6a496fdceaa334d71c02 Mon Sep 17 00:00:00 2001
From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com>
Date: Tue, 18 Apr 2023 22:34:23 +0800
Subject: [PATCH] explosions
- update deps
- major RichPresence rework
---
package.json | 24 ++--
plugins/RichPresence/src/ConfigEditor.tsx | 159 +++++++++++++++++++++
plugins/RichPresence/src/Settings.tsx | 166 ++--------------------
plugins/RichPresence/src/index.ts | 105 ++++++--------
plugins/RichPresence/src/utils.ts | 25 ++++
plugins/defs.d.ts | 9 +-
6 files changed, 255 insertions(+), 233 deletions(-)
create mode 100644 plugins/RichPresence/src/ConfigEditor.tsx
create mode 100644 plugins/RichPresence/src/utils.ts
diff --git a/package.json b/package.json
index a81d176..085ff83 100644
--- a/package.json
+++ b/package.json
@@ -5,22 +5,22 @@
"lint": "eslint plugins"
},
"devDependencies": {
- "@rollup/plugin-commonjs": "^24.0.1",
- "@rollup/plugin-node-resolve": "^15.0.1",
- "@swc/core": "^1.3.42",
- "@types/react": "^18.0.28",
- "@types/react-native": "^0.70.12",
- "@typescript-eslint/eslint-plugin": "^5.56.0",
- "@typescript-eslint/parser": "^5.56.0",
- "esbuild": "^0.17.12",
- "eslint": "^8.36.0",
+ "@rollup/plugin-commonjs": "^24.1.0",
+ "@rollup/plugin-node-resolve": "^15.0.2",
+ "@swc/core": "^1.3.51",
+ "@types/react": "^18.0.37",
+ "@types/react-native": "^0.70.13",
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
+ "@typescript-eslint/parser": "^5.59.0",
+ "esbuild": "^0.17.17",
+ "eslint": "^8.38.0",
"eslint-plugin-react": "^7.32.2",
- "rollup": "^3.20.1",
+ "rollup": "^3.20.6",
"rollup-plugin-esbuild": "^5.0.0",
"typescript": "^4.9.5",
- "vendetta-types": "^2.4.0"
+ "vendetta-types": "^2.4.18"
},
"dependencies": {
- "@swc/helpers": "^0.4.14"
+ "@swc/helpers": "^0.5.0"
}
}
diff --git a/plugins/RichPresence/src/ConfigEditor.tsx b/plugins/RichPresence/src/ConfigEditor.tsx
new file mode 100644
index 0000000..1fac69d
--- /dev/null
+++ b/plugins/RichPresence/src/ConfigEditor.tsx
@@ -0,0 +1,159 @@
+import { React, stylesheet } from "@vendetta/metro/common";
+import { storage } from "@vendetta/plugin";
+import { useProxy } from "@vendetta/storage";
+import { semanticColors } from "@vendetta/ui";
+import { Forms } from "@vendetta/ui/components";
+
+import { ScrollView } from "react-native";
+
+const { FormSection, FormInput, FormRow, FormSwitch, FormText } = Forms;
+
+const styles = stylesheet.createThemedStyleSheet({
+ subText: {
+ fontSize: 14,
+ marginLeft: 16,
+ marginRight: 16,
+ color: semanticColors.TEXT_MUTED
+ },
+ textLink: {
+ color: semanticColors.TEXT_LINK,
+ }
+});
+
+export default function ConfigEditor({ selection }: { selection: string }) {
+ const settings = useProxy(storage.selections[selection]) as Activity;
+
+ return (
+
+
+ settings.name = v}
+ />
+ settings.application_id = v}
+ keyboardType="numeric"
+ />
+ settings.type = v}
+ keyboardType="numeric"
+ />
+ settings.details = v}
+ />
+ settings.state = v}
+ />
+
+
+ settings.assets.large_image = v}
+ />
+ settings.assets.large_text = v}
+ />
+ settings.assets.small_image = v}
+ />
+ settings.assets.small_text = v}
+ />
+
+
+ {"Image assets key can be either a Discord app asset's name or a URL to an image."}
+
+
+ settings.timestamps._enabled = v}
+ />}
+ />
+ settings.timestamps.start = v}
+ keyboardType="numeric"
+ />
+ settings.timestamps.end = v}
+ keyboardType="numeric"
+ />
+ settings.timestamps.start = String(Date.now())}
+ trailing={FormRow.Arrow}
+ />
+
+ Leaving start timestamp blank will use the time the Discord started.
+
+
+
+ settings.buttons[0].label = v}
+ />
+ settings.buttons[0].url = v}
+ />
+ settings.buttons[1].label = v}
+ />
+ settings.buttons[1].url = v}
+ />
+
+
+ );
+}
diff --git a/plugins/RichPresence/src/Settings.tsx b/plugins/RichPresence/src/Settings.tsx
index 8e703c1..c4cbc6d 100644
--- a/plugins/RichPresence/src/Settings.tsx
+++ b/plugins/RichPresence/src/Settings.tsx
@@ -1,159 +1,11 @@
-import { React, stylesheet } from "@vendetta/metro/common";
-import { storage } from "@vendetta/plugin";
-import { useProxy } from "@vendetta/storage";
-import { semanticColors } from "@vendetta/ui";
-import { Forms } from "@vendetta/ui/components";
+import plugin from "@vendetta/plugin";
+import ConfigEditor from "./ConfigEditor";
-import { ScrollView } from "react-native";
+const storage = plugin.storage as typeof plugin.storage & {
+ selected: string;
+ selections: Record;
+};
-const { FormSection, FormInput, FormRow, FormSwitch, FormText } = Forms;
-
-const styles = stylesheet.createThemedStyleSheet({
- subText: {
- fontSize: 14,
- marginLeft: 16,
- marginRight: 16,
- color: semanticColors.TEXT_MUTED
- },
- textLink: {
- color: semanticColors.TEXT_LINK,
- }
-});
-
-export default function Settings() {
- const settings = useProxy(storage) as { [key: string]: any };
-
- return (
-
-
- settings.app_name = v}
- />
- settings.application_id = v}
- keyboardType="numeric"
- />
- settings.type = v}
- keyboardType="numeric"
- />
- settings.details = v}
- />
- settings.state = v}
- />
-
-
- settings.large_image = v}
- />
- settings.large_image_text = v}
- />
- settings.small_image = v}
- />
- settings.small_image_text = v}
- />
-
- {"Image assets key can be either a Discord app asset's name or a URL to an image."}
-
-
-
- settings.enable_timestamps = v}
- />}
- />
- settings.start_timestamp = v}
- keyboardType="numeric"
- />
- settings.end_timestamp = v}
- keyboardType="numeric"
- />
- settings.start_timestamp = String(Date.now())}
- trailing={FormRow.Arrow}
- />
-
- Leaving start timestamp blank will use the time the Discord started.
-
-
-
- settings.button1_text = v}
- />
- settings.button1_URL = v}
- />
- settings.button2_text = v}
- />
- settings.button2_URL = v}
- />
-
-
- );
-}
+export default () => (
+
+)
diff --git a/plugins/RichPresence/src/index.ts b/plugins/RichPresence/src/index.ts
index c33783b..9fe6eb2 100644
--- a/plugins/RichPresence/src/index.ts
+++ b/plugins/RichPresence/src/index.ts
@@ -1,10 +1,8 @@
-import { logger } from "@vendetta";
+import { logger, plugin } from "@vendetta";
import { findByProps } from "@vendetta/metro";
import { FluxDispatcher } from "@vendetta/metro/common";
-import { storage } from "@vendetta/plugin";
import Settings from "./Settings";
-
-const AssetManager = findByProps("getAssetIds");
+import { cloneAndFilter } from "./utils";
enum ActivityTypes {
PLAYING = 0,
@@ -15,59 +13,52 @@ enum ActivityTypes {
COMPETING = 5
}
-// :nyaboom:
-function constructActivity() {
- const activity: Activity = {
- name: storage.app_name || "Discord",
- application_id: storage.application_id || "1054951789318909972",
+const AssetManager = findByProps("getAssetIds");
+const pluginStartSince = Date.now();
+
+const storage = plugin.storage as typeof plugin.storage & {
+ selected: string;
+ selections: Record;
+};
+
+if (!storage.selected) {
+ Object.assign(storage, {
+ selected: "default",
+ selections: {
+ default: createDefaultSelection()
+ }
+ });
+}
+
+function createDefaultSelection(): Activity {
+ return {
+ name: "Discord",
+ application_id: "1054951789318909972",
flags: 0,
- type: ActivityTypes.PLAYING, // PLAYING
- state: storage.state,
- details: storage.details
+ type: ActivityTypes.PLAYING,
+ timestamps: {
+ _enabled: false,
+ start: pluginStartSince
+ },
+ assets: {},
+ // @ts-ignore
+ buttons: [{}, {}]
};
-
- // Construct timestamps
- if (storage.enable_timestamps) {
- const timestamps = {} as any;
-
- timestamps.start = Number(storage.start_timestamp) || Date.now();
- if (!isNaN(storage.end_timestamp)) timestamps.end = Number(storage.end_timestamp);
-
- activity.timestamps = timestamps;
- }
-
- // Construct assets
- const assets = {} as ActivityAssets;
-
- if (storage.large_image) {
- assets.large_image = storage.large_image;
- if (storage.large_image_text) assets.large_text = storage.large_image_text;
- }
-
- if (storage.small_image) {
- assets.small_image = storage.small_image;
- if (storage.small_image_text) assets.small_text = storage.small_image_text;
- }
-
- if (Object.keys(assets).length) activity.assets = assets;
-
- // Construct buttons
- if (storage.button1_text && storage.button1_URL) {
- activity.buttons = [
- { label: storage.button1_text, url: storage.button1_URL }
- ];
- }
-
- if (storage.button2_text && storage.button2_URL) {
- (activity.buttons ??= []).push({ label: storage.button2_text, url: storage.button2_URL });
- }
-
- return activity;
}
async function sendRequest(activity: Activity | null): Promise {
if (typeof activity !== "object") throw new Error("Invalid activity");
+ const timestampEnabled = activity?.timestamps?._enabled;
+ activity = cloneAndFilter(activity);
+
+ if (timestampEnabled) {
+ delete activity.timestamps._enabled;
+ activity.timestamps.start ||= pluginStartSince;
+ } else {
+ delete activity.timestamps;
+ }
+
if (activity?.assets) {
const [largeImage, smallImage] = await AssetManager.getAssetIds(activity.application_id, [activity.assets.large_image, activity.assets.small_image]);
activity.assets.large_image = largeImage;
@@ -76,20 +67,12 @@ async function sendRequest(activity: Activity | null): Promise {
if (activity?.buttons?.length) {
activity.buttons = activity.buttons.filter(x => x.label && x.url);
- Object.assign(activity, {
+ activity.buttons.length && Object.assign(activity, {
metadata: { button_urls: activity.buttons.map(x => x.url) },
buttons: activity.buttons.map(x => x.label)
});
}
- // validate activity
- for (const k in activity) {
- if (activity[k] === undefined || activity[k] === null) delete activity[k];
- if (typeof activity[k].length === "number" && activity[k].length === 0) delete activity[k];
- if (typeof activity[k] === "object" && Object.keys(activity[k]).length === 0) delete activity[k];
- if (typeof activity[k] === "object" && activity[k].length === 0) delete activity[k];
- }
-
FluxDispatcher.dispatch({
type: "LOCAL_ACTIVITY_UPDATE",
activity: activity
@@ -101,7 +84,9 @@ async function sendRequest(activity: Activity | null): Promise {
export default new class RichPresence {
onLoad() {
logger.log("Sending RPC request");
- sendRequest(constructActivity()).catch().then(x => {
+
+ const currentActivity = storage.selections[storage.selected];
+ sendRequest(currentActivity).catch().then(x => {
logger.log("RPC request sent");
console.log(x);
});
diff --git a/plugins/RichPresence/src/utils.ts b/plugins/RichPresence/src/utils.ts
new file mode 100644
index 0000000..97e1c9a
--- /dev/null
+++ b/plugins/RichPresence/src/utils.ts
@@ -0,0 +1,25 @@
+function isValid(val: any) {
+ if (val && typeof val.length === "number") return val.length > 0;
+ return val || val === 0 || val === false;
+}
+
+// Deep clone and filter empty objects/values or keys starting with "_"
+export function cloneAndFilter(obj: T): T {
+ const filter = (k: PropertyKey, v: any) => {
+ if (v === obj) return v;
+ if (typeof k === "string" && k.startsWith("_")) return undefined;
+
+ switch (typeof v) {
+ case "object": {
+ if (Array.isArray(v) && v.length === 0) return undefined;
+
+ const filteredEntries = Object.entries(v).filter((e) => isValid(e[1]));
+ return filteredEntries.length > 0 ? Object.fromEntries(filteredEntries) : undefined;
+ }
+ default:
+ return isValid(v) ? v : undefined;
+ }
+ };
+
+ return JSON.parse(JSON.stringify(obj, filter));
+}
diff --git a/plugins/defs.d.ts b/plugins/defs.d.ts
index 1587215..dc372e7 100644
--- a/plugins/defs.d.ts
+++ b/plugins/defs.d.ts
@@ -6,11 +6,12 @@ type Activity = {
details?: string;
state?: string;
timestamps?: {
- start: number;
- end?: number;
+ _enabled: boolean;
+ start: number | string;
+ end?: number | string;
};
- assets?: ActivityAssets;
- buttons?: ActivityButton[];
+ assets: ActivityAssets;
+ buttons: ActivityButton[];
};
type ActivityButton = {