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

feat(plugin): Relationship Indicator #2656

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/plugins/relationshipIndicators/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Relationship Indicators

## Description
Adds a display to the badges, messages, and member list to indicate your relationship with the user.


### Friend Indicator
![friend indicator in chat](https://github.com/Vendicated/Vencord/assets/97131358/10a33c55-cbe5-4369-bb49-6f3aee59059c)
![friend indicator in member list](https://github.com/Vendicated/Vencord/assets/97131358/614653e6-b51b-4082-998d-d123fbac595f)
![friend indicator in profile (badge)](https://github.com/Vendicated/Vencord/assets/97131358/270c6667-e810-40a6-861a-40984f575aa6)

### Blocked Indicator

![blocked indicator in chat](https://github.com/Vendicated/Vencord/assets/97131358/bfdebf30-6b5c-480f-94fd-acc5cd736d9b)
![blocked indicator in member list](https://github.com/Vendicated/Vencord/assets/97131358/5054729a-e30c-4104-945b-8652df6cf71c)
![blocked indicator in profile (badge)](https://github.com/Vendicated/Vencord/assets/97131358/f0ee1279-ffa0-464d-b62a-3ff7d8d3a646)
49 changes: 49 additions & 0 deletions src/plugins/relationshipIndicators/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/

// uhh... can i put this in Icons.tsx?
import { Tooltip } from "@webpack/common";

type IconProps = {
tooltip?: string,
paths: { fill: string, path: string }[]
viewBox?: string
}

function Icon(iconProps: IconProps) {
return (
<Tooltip text={iconProps.tooltip??""}>
{props => (
<svg aria-hidden="true" role="img" width="1em" height="1em"
{...props}
fill="none" viewBox={iconProps.viewBox??"0 0 24 24"}>
{iconProps.paths.map(path => (
<path fill={path.fill} d={path.path} />
))}
</svg>
)}
</Tooltip>

);
}

export function FriendIcon() {
return (
<Icon tooltip={"Friend"} paths={[
{ fill: "#00ff00", path: "M13 10a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" },
{ fill: "#00ff00", path: "M3 5v-.75C3 3.56 3.56 3 4.25 3s1.24.56 1.33 1.25C6.12 8.65 9.46 12 13 12h1a8 8 0 0 1 8 8 2 2 0 0 1-2 2 .21.21 0 0 1-.2-.15 7.65 7.65 0 0 0-1.32-2.3c-.15-.2-.42-.06-.39.17l.25 2c.02.15-.1.28-.25.28H9a2 2 0 0 1-2-2v-2.22c0-1.57-.67-3.05-1.53-4.37A15.85 15.85 0 0 1 3 5Z" }
]}/>
);
}

export function BlockedIcon() {
return (
<Icon tooltip={"Blocked"} paths={[
{ fill: "#a32e2e", path: "M13 10a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" },
{ fill: "#a32e2e", path: "M3 5v-.75C3 3.56 3.56 3 4.25 3s1.24.56 1.33 1.25C6.12 8.65 9.46 12 13 12h1a8 8 0 0 1 8 8 2 2 0 0 1-2 2 .21.21 0 0 1-.2-.15 7.65 7.65 0 0 0-1.32-2.3c-.15-.2-.42-.06-.39.17l.25 2c.02.15-.1.28-.25.28H9a2 2 0 0 1-2-2v-2.22c0-1.57-.67-3.05-1.53-4.37A15.85 15.85 0 0 1 3 5Z" }
]}/>
);
}
85 changes: 85 additions & 0 deletions src/plugins/relationshipIndicators/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/

import {
addBadge,
BadgePosition,
ProfileBadge,
removeBadge
} from "@api/Badges";
import { addDecorator, removeDecorator } from "@api/MemberListDecorators";
import { addDecoration, removeDecoration } from "@api/MessageDecorations";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";

import { getBadges, RelationshipIndicator } from "./utils";

const indicatorLocations = {
list: {
description: "In the member list",
onEnable: () => addDecorator("friend-indicator", props =>
<ErrorBoundary noop>
<RelationshipIndicator user={props.user} />
</ErrorBoundary>
),
onDisable: () => removeDecorator("friend-indicator")
},
badges: {
description: "In user profiles, as badges",
onEnable: () => addBadge(badge),
onDisable: () => removeBadge(badge)
},
messages: {
description: "Inside messages",
onEnable: () => addDecoration("friend-indicator", props =>
<ErrorBoundary noop>
<RelationshipIndicator user={props.message?.author} wantTopMargin={true} />
</ErrorBoundary>
),
onDisable: () => removeDecoration("friend-indicator")
}
};

const badge: ProfileBadge = {
getBadges,
position: BadgePosition.START
};

const settings = definePluginSettings({
...Object.fromEntries(
Object.entries(indicatorLocations).map(([key, value]) => {
return [key, {
type: OptionType.BOOLEAN,
description: `Show indicators ${value.description.toLowerCase()}`,
// onChange doesn't give any way to know which setting was changed, so restart required
restartNeeded: true,
default: true
}];
})
),
});

export default definePlugin({
name: "RelationshipIndicators",
authors: [Devs.Scyye],
settings,
description: "Adds icons to indicate relationships with users.",
start() {
Object.entries(indicatorLocations).forEach(([key, value]) => {
if (settings.store[key]) value.onEnable();
});
},
stop() {
Object.entries(indicatorLocations).forEach(([key, value]) => {
if (settings.store[key]) value.onDisable();
});
},
});



52 changes: 52 additions & 0 deletions src/plugins/relationshipIndicators/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/

import { BadgeUserArgs, ProfileBadge } from "@api/Badges";
import { RelationshipStore, UserStore } from "@webpack/common";
import { User } from "discord-types/general";

import { BlockedIcon, FriendIcon } from "./icons";

const shouldShowIndicator = (user?: User|null) => {
return user && !user.bot && (RelationshipStore.isFriend(user.id) || RelationshipStore.isBlocked(user.id));
};

export const RelationshipIndicator = ({ user, wantMargin = true, wantTopMargin = false }: { user: User; wantMargin?: boolean; wantTopMargin?: boolean; }) => {
if (!shouldShowIndicator(user)) return null;

return (
<span
className="vc-friend-indicator"
style={{
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
marginLeft: wantMargin ? 4 : 0,
verticalAlign: "top",
position: "relative",
top: wantTopMargin ? 2 : 0,
padding: !wantMargin ? 1 : 0,
gap: 2
}}
>
{RelationshipStore.isFriend(user.id)? <FriendIcon /> : <BlockedIcon />}
</span>
);
};

export function getBadges({ userId }: BadgeUserArgs): ProfileBadge[] {
const user = UserStore.getUser(userId);
if (!shouldShowIndicator(user)) return [];

return [{
component: () => (
<span className="vc-relationship-indicator">
<RelationshipIndicator user={user} />
</span>
),
key: `vc-${RelationshipStore.isFriend(userId)?"friend":"blocked"}-indicator`,
}];
}
4 changes: 4 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
Antti: {
name: "Antti",
id: 312974985876471810n
},
Scyye: {
name: "Scyye",
id: 553652308295155723n
}
} satisfies Record<string, Dev>);

Expand Down