Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ircColors: fix ColorDot/RoleColorsEverywhere/maybe smth else #3169

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from
73 changes: 43 additions & 30 deletions src/plugins/ircColors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,31 @@ import { definePluginSettings } from "@api/Settings";
import { hash as h64 } from "@intrnl/xxhash64";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { useMemo } from "@webpack/common";
import { ChannelStore, GuildMemberStore, SelectedChannelStore } from "@webpack/common";

// Calculate a CSS color string based on the user ID
function calculateNameColorForUser(id?: string) {
const { lightness } = settings.use(["lightness"]);
const idHash = useMemo(() => id ? h64(id) : null, [id]);
function calculateHSLforId(id: string) {
// No hooks here because it breaks RoleColorsEverywhere
// There is a condition to use this function, so react will refure to render the component
// If we remove the condition, then the hash will be calculated even if this plugin is disabled
// And everything would seem fine except mentions, those are still under some condition inside of discord code
return {
hue: Number(h64(id) % 360n),
saturation: 100,
lightness: settings.store.lightness
};
}

return idHash && `hsl(${idHash % 360n}, 100%, ${lightness}%)`;
// https://stackoverflow.com/a/44134328
// Role Color Everywhere expects colorString to be hex, so...
function hslToHex(hue, saturation, lightness) {
lightness /= 100;
const a = saturation * Math.min(lightness, 1 - lightness) / 100;
const f = n => {
const k = (n + hue / 30) % 12;
const color = lightness - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color).toString(16).padStart(2, "0"); // convert to Hex and prefix "0" if needed
};
return `#${f(0)}${f(8)}${f(4)}`;
}

const settings = definePluginSettings({
Expand Down Expand Up @@ -59,15 +76,15 @@ const settings = definePluginSettings({
export default definePlugin({
name: "IrcColors",
description: "Makes username colors in chat unique, like in IRC clients",
authors: [Devs.Grzesiek11, Devs.jamesbt365],
authors: [Devs.Grzesiek11, Devs.jamesbt365, Devs.hen],
settings,

patches: [
{
find: '="SYSTEM_TAG"',
find: '"Result cannot be null because the message is not null"',
replacement: {
match: /(?<=className:\i\.username,style:.{0,50}:void 0,)/,
replace: "style:{color:$self.calculateNameColorForMessageContext(arguments[0])},"
match: /let (\i)=\i\(\i\);(?=.{1,25}"Result cannot be null because the message is not null")/,
replace: "$&$1.colorString=$self.calculateNameColorForMessageContext(arguments[0],$1.colorString);"
}
},
{
Expand All @@ -79,31 +96,27 @@ export default definePlugin({
predicate: () => settings.store.memberListColors
}
],
// Propped to be used in TypingTweaks/RoleColorsEverywhere
calculateHSLforId,
resolveUserColor(userId: string) {
const channelId = SelectedChannelStore.getChannelId();
const channel = ChannelStore.getChannel(channelId);
const colorString = GuildMemberStore.getMember(channel.guild_id, userId)?.colorString;

calculateNameColorForMessageContext(context: any) {
const id = context?.message?.author?.id;
const colorString = context?.author?.colorString;
const color = calculateNameColorForUser(id);
if (settings.store.applyColorOnlyInDms && !channel?.isPrivate()) return colorString;
if (settings.store.applyColorOnlyToUsersWithoutColor && colorString) return colorString;

if (settings.store.applyColorOnlyInDms && !context?.channel?.isPrivate()) {
return colorString;
}
const { hue, lightness, saturation } = calculateHSLforId(userId);

return hslToHex(hue, saturation, lightness);
},
calculateNameColorForMessageContext(message: any, colorString: string) {
const id = message?.author?.id;
return id && this.resolveUserColor(id);

return (!settings.store.applyColorOnlyToUsersWithoutColor || !colorString)
? color
: colorString;
},
calculateNameColorForListContext(context: any) {
const id = context?.user?.id;
const colorString = context?.colorString;
const color = calculateNameColorForUser(id);

if (settings.store.applyColorOnlyInDms && !context?.channel?.isPrivate()) {
return colorString;
}

return (!settings.store.applyColorOnlyToUsersWithoutColor || !colorString)
? color
: colorString;
return id && this.resolveUserColor(id);
}
});
8 changes: 7 additions & 1 deletion src/plugins/roleColorEverywhere/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import definePlugin, { OptionType } from "@utils/types";
import { findByCodeLazy } from "@webpack";
import { ChannelStore, GuildMemberStore, GuildStore } from "@webpack/common";

import IrcColors from "../ircColors";

const useMessageAuthor = findByCodeLazy('"Result cannot be null because the message is not null"');

const settings = definePluginSettings({
Expand Down Expand Up @@ -161,8 +163,12 @@ export default definePlugin({
predicate: () => settings.store.colorChatMessages
}
],

getColorString(userId: string, channelOrGuildId: string) {
if (Vencord.Plugins.isPluginEnabled("IrcColors")) {
const color = IrcColors.resolveUserColor(userId);
if (color) return color;
}

try {
const guildId = ChannelStore.getChannel(channelOrGuildId)?.guild_id ?? GuildStore.getGuild(channelOrGuildId)?.id;
if (guildId == null) return null;
Expand Down
12 changes: 11 additions & 1 deletion src/plugins/typingTweaks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { Avatar, GuildMemberStore, React, RelationshipStore } from "@webpack/com
import { User } from "discord-types/general";
import { PropsWithChildren } from "react";

import IrcColors from "../ircColors";

const settings = definePluginSettings({
showAvatars: {
type: OptionType.BOOLEAN,
Expand Down Expand Up @@ -57,6 +59,14 @@ interface Props {
guildId: string;
}

const getUserColor = (userId: string, guildId: string) => {
if (Vencord.Plugins.isPluginEnabled("IrcColors")) {
const color = IrcColors.resolveUserColor(userId);
if (color) return color;
}

return GuildMemberStore.getMember(guildId, userId)?.colorString;
};
const TypingUser = ErrorBoundary.wrap(function ({ user, guildId }: Props) {
return (
<strong
Expand All @@ -68,7 +78,7 @@ const TypingUser = ErrorBoundary.wrap(function ({ user, guildId }: Props) {
display: "grid",
gridAutoFlow: "column",
gap: "4px",
color: settings.store.showRoleColors ? GuildMemberStore.getMember(guildId, user.id)?.colorString : undefined,
color: settings.store.showRoleColors ? getUserColor(user?.id, guildId) : undefined,
cursor: "pointer"
}}
>
Expand Down
4 changes: 4 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "jamesbt365",
id: 158567567487795200n,
},
hen: {
id: 279266228151779329n,
name: "Hen"
},
} satisfies Record<string, Dev>);

// iife so #__PURE__ works correctly
Expand Down