CopyRoleColor: copy gradient roles as JSON, not just the flattened hex
This commit is contained in:
parent
3e72269c10
commit
19cfaac538
1 changed files with 28 additions and 7 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { logger } from "@vendetta";
|
import { logger } from "@vendetta";
|
||||||
import { findByName } from "@vendetta/metro";
|
import { findByName, findByStoreName } from "@vendetta/metro";
|
||||||
import { after } from "@vendetta/patcher";
|
import { after } from "@vendetta/patcher";
|
||||||
import { findInReactTree } from "@vendetta/utils";
|
import { findInReactTree } from "@vendetta/utils";
|
||||||
import { clipboard } from "@vendetta/metro/common";
|
import { clipboard } from "@vendetta/metro/common";
|
||||||
|
|
@ -8,6 +8,17 @@ import { showToast } from "@vendetta/ui/toasts";
|
||||||
import { applyPatches } from "@shared/lib/patcher";
|
import { applyPatches } from "@shared/lib/patcher";
|
||||||
import { registerTypeDetector, registerIntercept, patchCreateElement } from "@shared/lib/createElementIntercept";
|
import { registerTypeDetector, registerIntercept, patchCreateElement } from "@shared/lib/createElementIntercept";
|
||||||
|
|
||||||
|
// A gradient role's real colors live at role.colorStrings ({primaryColor, secondaryColor,
|
||||||
|
// tertiaryColor}), not the flattened colorString - copying that exact JSON back into Discord's own
|
||||||
|
// role color picker recreates the gradient. A solid-color role only has primaryColor set, so this
|
||||||
|
// falls back to the plain hex for those, keeping the existing single-color behavior unchanged.
|
||||||
|
function getClipboardValue(colorStrings: any, fallbackColor?: string | null): string | null {
|
||||||
|
if (colorStrings?.primaryColor && colorStrings?.secondaryColor) {
|
||||||
|
return JSON.stringify(colorStrings);
|
||||||
|
}
|
||||||
|
return colorStrings?.primaryColor ?? fallbackColor ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
function patchRolePill(): () => void {
|
function patchRolePill(): () => void {
|
||||||
// Confirmed against decompiled current-build Discord source: the component is now just
|
// Confirmed against decompiled current-build Discord source: the component is now just
|
||||||
// "RolePill" (at app/components_native/common/RolePill.tsx) - "ThemedRolePill" doesn't exist
|
// "RolePill" (at app/components_native/common/RolePill.tsx) - "ThemedRolePill" doesn't exist
|
||||||
|
|
@ -15,6 +26,8 @@ function patchRolePill(): () => void {
|
||||||
const RolePillComponent = findByName("RolePill", false) ?? findByName("ThemedRolePill", false);
|
const RolePillComponent = findByName("RolePill", false) ?? findByName("ThemedRolePill", false);
|
||||||
if (!RolePillComponent) return () => {};
|
if (!RolePillComponent) return () => {};
|
||||||
|
|
||||||
|
const GuildRoleStore = findByStoreName("GuildRoleStore");
|
||||||
|
|
||||||
return after("default", RolePillComponent, (_args: any[], res: any) => {
|
return after("default", RolePillComponent, (_args: any[], res: any) => {
|
||||||
try {
|
try {
|
||||||
if (!res?.props?.onPress) return;
|
if (!res?.props?.onPress) return;
|
||||||
|
|
@ -27,8 +40,16 @@ function patchRolePill(): () => void {
|
||||||
const color = roleIcon?.props?.style?.[1]?.backgroundColor ?? verifiedIcon?.props?.roleColor;
|
const color = roleIcon?.props?.style?.[1]?.backgroundColor ?? verifiedIcon?.props?.roleColor;
|
||||||
if (!color) return;
|
if (!color) return;
|
||||||
|
|
||||||
|
// The pill only gives us a flattened color from its rendered style - fetching the real
|
||||||
|
// role record (if guildId/roleId are present on it) is what actually exposes the gradient.
|
||||||
|
const guildId = res.props?.guildId;
|
||||||
|
const roleId = res.props?.roleId ?? res.props?.role?.id;
|
||||||
|
const role = guildId && roleId ? GuildRoleStore?.getRole?.(guildId, roleId) : null;
|
||||||
|
const value = getClipboardValue(role?.colorStrings, color);
|
||||||
|
if (!value) return;
|
||||||
|
|
||||||
res.props.onLongPress = () => {
|
res.props.onLongPress = () => {
|
||||||
clipboard.setString(color);
|
clipboard.setString(value);
|
||||||
showToast("Copied role color to clipboard", getAssetIDByName("ic_message_copy"));
|
showToast("Copied role color to clipboard", getAssetIDByName("ic_message_copy"));
|
||||||
};
|
};
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -40,8 +61,8 @@ function patchRolePill(): () => void {
|
||||||
// Covers the role pills in a full profile's Roles section - a different render path from
|
// Covers the role pills in a full profile's Roles section - a different render path from
|
||||||
// patchRolePill above (that one's for role mentions in message text). This section renders
|
// patchRolePill above (that one's for role mentions in message text). This section renders
|
||||||
// UserProfileRolesCard -> RolesList -> RoleItem, none of which are top-level exports, so we need
|
// UserProfileRolesCard -> RolesList -> RoleItem, none of which are top-level exports, so we need
|
||||||
// createElementIntercept to catch RoleItem's reference. It hands us the role object directly with
|
// createElementIntercept to catch RoleItem's reference. It hands us the role object directly, with
|
||||||
// role.colorString already a hex string, so no need to guess at it from rendered styles.
|
// both colorStrings and colorString on it already, so no need to guess at it from rendered styles.
|
||||||
function patchProfileRoleItem(): () => void {
|
function patchProfileRoleItem(): () => void {
|
||||||
const cleanups: (() => void)[] = [];
|
const cleanups: (() => void)[] = [];
|
||||||
patchCreateElement(cleanups);
|
patchCreateElement(cleanups);
|
||||||
|
|
@ -54,12 +75,12 @@ function patchProfileRoleItem(): () => void {
|
||||||
const ret = RoleItem(props);
|
const ret = RoleItem(props);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const color = props?.role?.colorString;
|
const value = getClipboardValue(props?.role?.colorStrings, props?.role?.colorString);
|
||||||
if (color && ret && typeof ret === "object") {
|
if (value && ret && typeof ret === "object") {
|
||||||
ret.props = {
|
ret.props = {
|
||||||
...ret.props,
|
...ret.props,
|
||||||
onLongPress: () => {
|
onLongPress: () => {
|
||||||
clipboard.setString(color);
|
clipboard.setString(value);
|
||||||
showToast("Copied role color to clipboard", getAssetIDByName("ic_message_copy"));
|
showToast("Copied role color to clipboard", getAssetIDByName("ic_message_copy"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue