mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-27 07:24:55 -04:00
Settings API: add support for custom objects / arrays (#3154)
This commit is contained in:
parent
317121fc08
commit
5c8ba6e542
13 changed files with 420 additions and 355 deletions
|
@ -7,11 +7,10 @@
|
|||
import { classNameFactory } from "@api/Styles";
|
||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModalLazy } from "@utils/modal";
|
||||
import { extractAndLoadChunksLazy, findComponentByCodeLazy, findExportedComponentLazy } from "@webpack";
|
||||
import { Button, Forms, Text, TextInput, Toasts, useEffect, useState } from "@webpack/common";
|
||||
import { Button, Forms, Text, TextInput, Toasts, useMemo, useState } from "@webpack/common";
|
||||
|
||||
import { DEFAULT_COLOR, SWATCHES } from "../constants";
|
||||
import { categories, Category, createCategory, getCategory, updateCategory } from "../data";
|
||||
import { forceUpdate } from "../index";
|
||||
import { categoryLen, createCategory, getCategory } from "../data";
|
||||
|
||||
interface ColorPickerProps {
|
||||
color: number | null;
|
||||
|
@ -39,45 +38,45 @@ const cl = classNameFactory("vc-pindms-modal-");
|
|||
|
||||
interface Props {
|
||||
categoryId: string | null;
|
||||
initalChannelId: string | null;
|
||||
initialChannelId: string | null;
|
||||
modalProps: ModalProps;
|
||||
}
|
||||
|
||||
function useCategory(categoryId: string | null, initalChannelId: string | null) {
|
||||
const [category, setCategory] = useState<Category | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (categoryId)
|
||||
setCategory(getCategory(categoryId)!);
|
||||
else if (initalChannelId)
|
||||
setCategory({
|
||||
const category = useMemo(() => {
|
||||
if (categoryId) {
|
||||
return getCategory(categoryId);
|
||||
} else if (initalChannelId) {
|
||||
return {
|
||||
id: Toasts.genId(),
|
||||
name: `Pin Category ${categories.length + 1}`,
|
||||
name: `Pin Category ${categoryLen() + 1}`,
|
||||
color: DEFAULT_COLOR,
|
||||
collapsed: false,
|
||||
channels: [initalChannelId]
|
||||
});
|
||||
};
|
||||
}
|
||||
}, [categoryId, initalChannelId]);
|
||||
|
||||
return {
|
||||
category,
|
||||
setCategory
|
||||
};
|
||||
return category;
|
||||
}
|
||||
|
||||
export function NewCategoryModal({ categoryId, modalProps, initalChannelId }: Props) {
|
||||
const { category, setCategory } = useCategory(categoryId, initalChannelId);
|
||||
|
||||
export function NewCategoryModal({ categoryId, modalProps, initialChannelId }: Props) {
|
||||
const category = useCategory(categoryId, initialChannelId);
|
||||
if (!category) return null;
|
||||
|
||||
const onSave = async (e: React.FormEvent<HTMLFormElement> | React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
if (!categoryId)
|
||||
await createCategory(category);
|
||||
else
|
||||
await updateCategory(category);
|
||||
const [name, setName] = useState(category.name);
|
||||
const [color, setColor] = useState(category.color);
|
||||
|
||||
const onSave = (e: React.FormEvent<HTMLFormElement> | React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
|
||||
category.name = name;
|
||||
category.color = color;
|
||||
|
||||
if (!categoryId) {
|
||||
createCategory(category);
|
||||
}
|
||||
|
||||
forceUpdate();
|
||||
modalProps.onClose();
|
||||
};
|
||||
|
||||
|
@ -93,25 +92,25 @@ export function NewCategoryModal({ categoryId, modalProps, initalChannelId }: Pr
|
|||
<Forms.FormSection>
|
||||
<Forms.FormTitle>Name</Forms.FormTitle>
|
||||
<TextInput
|
||||
value={category.name}
|
||||
onChange={e => setCategory({ ...category, name: e })}
|
||||
value={name}
|
||||
onChange={e => setName(e)}
|
||||
/>
|
||||
</Forms.FormSection>
|
||||
<Forms.FormDivider />
|
||||
<Forms.FormSection>
|
||||
<Forms.FormTitle>Color</Forms.FormTitle>
|
||||
<ColorPickerWithSwatches
|
||||
key={category.name}
|
||||
key={category.id}
|
||||
defaultColor={DEFAULT_COLOR}
|
||||
colors={SWATCHES}
|
||||
onChange={c => setCategory({ ...category, color: c! })}
|
||||
value={category.color}
|
||||
onChange={c => setColor(c!)}
|
||||
value={color}
|
||||
renderDefaultButton={() => null}
|
||||
renderCustomButton={() => (
|
||||
<ColorPicker
|
||||
color={category.color}
|
||||
onChange={c => setCategory({ ...category, color: c! })}
|
||||
key={category.name}
|
||||
color={color}
|
||||
onChange={c => setColor(c!)}
|
||||
key={category.id}
|
||||
showEyeDropper={false}
|
||||
/>
|
||||
)}
|
||||
|
@ -119,7 +118,7 @@ export function NewCategoryModal({ categoryId, modalProps, initalChannelId }: Pr
|
|||
</Forms.FormSection>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Button type="submit" onClick={onSave} disabled={!category.name}>{categoryId ? "Save" : "Create"}</Button>
|
||||
<Button type="submit" onClick={onSave} disabled={!name}>{categoryId ? "Save" : "Create"}</Button>
|
||||
</ModalFooter>
|
||||
</form>
|
||||
</ModalRoot>
|
||||
|
@ -129,6 +128,6 @@ export function NewCategoryModal({ categoryId, modalProps, initalChannelId }: Pr
|
|||
export const openCategoryModal = (categoryId: string | null, channelId: string | null) =>
|
||||
openModalLazy(async () => {
|
||||
await requireSettingsMenu();
|
||||
return modalProps => <NewCategoryModal categoryId={categoryId} modalProps={modalProps} initalChannelId={channelId} />;
|
||||
return modalProps => <NewCategoryModal categoryId={categoryId} modalProps={modalProps} initialChannelId={channelId} />;
|
||||
});
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
||||
import { addChannelToCategory, canMoveChannelInDirection, categories, isPinned, moveChannel, removeChannelFromCategory } from "../data";
|
||||
import { forceUpdate, PinOrder, settings } from "../index";
|
||||
import { addChannelToCategory, canMoveChannelInDirection, currentUserCategories, isPinned, moveChannel, removeChannelFromCategory } from "../data";
|
||||
import { PinOrder, settings } from "../index";
|
||||
import { openCategoryModal } from "./CreateCategoryModal";
|
||||
|
||||
function createPinMenuItem(channelId: string) {
|
||||
|
@ -31,12 +31,12 @@ function createPinMenuItem(channelId: string) {
|
|||
<Menu.MenuSeparator />
|
||||
|
||||
{
|
||||
categories.map(category => (
|
||||
currentUserCategories.map(category => (
|
||||
<Menu.MenuItem
|
||||
key={category.id}
|
||||
id={`pin-category-${category.id}`}
|
||||
label={category.name}
|
||||
action={() => addChannelToCategory(channelId, category.id).then(forceUpdate)}
|
||||
action={() => addChannelToCategory(channelId, category.id)}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ function createPinMenuItem(channelId: string) {
|
|||
id="unpin-dm"
|
||||
label="Unpin DM"
|
||||
color="danger"
|
||||
action={() => removeChannelFromCategory(channelId).then(forceUpdate)}
|
||||
action={() => removeChannelFromCategory(channelId)}
|
||||
/>
|
||||
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ function createPinMenuItem(channelId: string) {
|
|||
<Menu.MenuItem
|
||||
id="move-up"
|
||||
label="Move Up"
|
||||
action={() => moveChannel(channelId, -1).then(forceUpdate)}
|
||||
action={() => moveChannel(channelId, -1)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ function createPinMenuItem(channelId: string) {
|
|||
<Menu.MenuItem
|
||||
id="move-down"
|
||||
label="Move Down"
|
||||
action={() => moveChannel(channelId, 1).then(forceUpdate)}
|
||||
action={() => moveChannel(channelId, 1)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { DEFAULT_COLOR } from "./constants";
|
||||
import { forceUpdate, PinOrder, PrivateChannelSortStore, settings } from "./index";
|
||||
import { PinOrder, PrivateChannelSortStore, settings } from "./index";
|
||||
|
||||
export interface Category {
|
||||
id: string;
|
||||
|
@ -24,104 +24,92 @@ const CATEGORY_MIGRATED_PINDMS_KEY = "PinDMsMigratedPinDMs";
|
|||
const CATEGORY_MIGRATED_KEY = "PinDMsMigratedOldCategories";
|
||||
const OLD_CATEGORY_KEY = "BetterPinDMsCategories-";
|
||||
|
||||
|
||||
export let categories: Category[] = [];
|
||||
|
||||
export async function saveCats(cats: Category[]) {
|
||||
const { id } = UserStore.getCurrentUser();
|
||||
await DataStore.set(CATEGORY_BASE_KEY + id, cats);
|
||||
}
|
||||
let forceUpdateDms: (() => void) | undefined = undefined;
|
||||
export let currentUserCategories: Category[] = [];
|
||||
|
||||
export async function init() {
|
||||
const id = UserStore.getCurrentUser()?.id;
|
||||
await initCategories(id);
|
||||
await migrateData(id);
|
||||
forceUpdate();
|
||||
await migrateData();
|
||||
|
||||
const userId = UserStore.getCurrentUser()?.id;
|
||||
if (userId == null) return;
|
||||
|
||||
currentUserCategories = settings.store.userBasedCategoryList[userId] ??= [];
|
||||
forceUpdateDms?.();
|
||||
}
|
||||
|
||||
export async function initCategories(userId: string) {
|
||||
categories = await DataStore.get<Category[]>(CATEGORY_BASE_KEY + userId) ?? [];
|
||||
export function usePinnedDms() {
|
||||
forceUpdateDms = useForceUpdater();
|
||||
settings.use(["pinOrder", "canCollapseDmSection", "dmSectionCollapsed", "userBasedCategoryList"]);
|
||||
}
|
||||
|
||||
export function getCategory(id: string) {
|
||||
return categories.find(c => c.id === id);
|
||||
return currentUserCategories.find(c => c.id === id);
|
||||
}
|
||||
|
||||
export async function createCategory(category: Category) {
|
||||
categories.push(category);
|
||||
await saveCats(categories);
|
||||
export function getCategoryByIndex(index: number) {
|
||||
return currentUserCategories[index];
|
||||
}
|
||||
|
||||
export async function updateCategory(category: Category) {
|
||||
const index = categories.findIndex(c => c.id === category.id);
|
||||
if (index === -1) return;
|
||||
|
||||
categories[index] = category;
|
||||
await saveCats(categories);
|
||||
export function createCategory(category: Category) {
|
||||
currentUserCategories.push(category);
|
||||
}
|
||||
|
||||
export async function addChannelToCategory(channelId: string, categoryId: string) {
|
||||
const category = categories.find(c => c.id === categoryId);
|
||||
if (!category) return;
|
||||
export function addChannelToCategory(channelId: string, categoryId: string) {
|
||||
const category = currentUserCategories.find(c => c.id === categoryId);
|
||||
if (category == null) return;
|
||||
|
||||
if (category.channels.includes(channelId)) return;
|
||||
|
||||
category.channels.push(channelId);
|
||||
await saveCats(categories);
|
||||
|
||||
}
|
||||
|
||||
export async function removeChannelFromCategory(channelId: string) {
|
||||
const category = categories.find(c => c.channels.includes(channelId));
|
||||
if (!category) return;
|
||||
export function removeChannelFromCategory(channelId: string) {
|
||||
const category = currentUserCategories.find(c => c.channels.includes(channelId));
|
||||
if (category == null) return;
|
||||
|
||||
category.channels = category.channels.filter(c => c !== channelId);
|
||||
await saveCats(categories);
|
||||
}
|
||||
|
||||
export async function removeCategory(categoryId: string) {
|
||||
const catagory = categories.find(c => c.id === categoryId);
|
||||
if (!catagory) return;
|
||||
export function removeCategory(categoryId: string) {
|
||||
const categoryIndex = currentUserCategories.findIndex(c => c.id === categoryId);
|
||||
if (categoryIndex === -1) return;
|
||||
|
||||
// catagory?.channels.forEach(c => removeChannelFromCategory(c));
|
||||
categories = categories.filter(c => c.id !== categoryId);
|
||||
await saveCats(categories);
|
||||
currentUserCategories.splice(categoryIndex, 1);
|
||||
}
|
||||
|
||||
export async function collapseCategory(id: string, value = true) {
|
||||
const category = categories.find(c => c.id === id);
|
||||
if (!category) return;
|
||||
export function collapseCategory(id: string, value = true) {
|
||||
const category = currentUserCategories.find(c => c.id === id);
|
||||
if (category == null) return;
|
||||
|
||||
category.collapsed = value;
|
||||
await saveCats(categories);
|
||||
}
|
||||
|
||||
// utils
|
||||
// Utils
|
||||
export function isPinned(id: string) {
|
||||
return categories.some(c => c.channels.includes(id));
|
||||
return currentUserCategories.some(c => c.channels.includes(id));
|
||||
}
|
||||
|
||||
export function categoryLen() {
|
||||
return categories.length;
|
||||
return currentUserCategories.length;
|
||||
}
|
||||
|
||||
export function getAllUncollapsedChannels() {
|
||||
if (settings.store.pinOrder === PinOrder.LastMessage) {
|
||||
const sortedChannels = PrivateChannelSortStore.getPrivateChannelIds();
|
||||
return categories.filter(c => !c.collapsed).flatMap(c => sortedChannels.filter(channel => c.channels.includes(channel)));
|
||||
return currentUserCategories.filter(c => !c.collapsed).flatMap(c => sortedChannels.filter(channel => c.channels.includes(channel)));
|
||||
}
|
||||
|
||||
return categories.filter(c => !c.collapsed).flatMap(c => c.channels);
|
||||
return currentUserCategories.filter(c => !c.collapsed).flatMap(c => c.channels);
|
||||
}
|
||||
|
||||
export function getSections() {
|
||||
return categories.reduce((acc, category) => {
|
||||
return currentUserCategories.reduce((acc, category) => {
|
||||
acc.push(category.channels.length === 0 ? 1 : category.channels.length);
|
||||
return acc;
|
||||
}, [] as number[]);
|
||||
}
|
||||
|
||||
// move categories
|
||||
// Move categories
|
||||
export const canMoveArrayInDirection = (array: any[], index: number, direction: -1 | 1) => {
|
||||
const a = array[index];
|
||||
const b = array[index + direction];
|
||||
|
@ -130,18 +118,18 @@ export const canMoveArrayInDirection = (array: any[], index: number, direction:
|
|||
};
|
||||
|
||||
export const canMoveCategoryInDirection = (id: string, direction: -1 | 1) => {
|
||||
const index = categories.findIndex(m => m.id === id);
|
||||
return canMoveArrayInDirection(categories, index, direction);
|
||||
const categoryIndex = currentUserCategories.findIndex(m => m.id === id);
|
||||
return canMoveArrayInDirection(currentUserCategories, categoryIndex, direction);
|
||||
};
|
||||
|
||||
export const canMoveCategory = (id: string) => canMoveCategoryInDirection(id, -1) || canMoveCategoryInDirection(id, 1);
|
||||
|
||||
export const canMoveChannelInDirection = (channelId: string, direction: -1 | 1) => {
|
||||
const category = categories.find(c => c.channels.includes(channelId));
|
||||
if (!category) return false;
|
||||
const category = currentUserCategories.find(c => c.channels.includes(channelId));
|
||||
if (category == null) return false;
|
||||
|
||||
const index = category.channels.indexOf(channelId);
|
||||
return canMoveArrayInDirection(category.channels, index, direction);
|
||||
const channelIndex = category.channels.indexOf(channelId);
|
||||
return canMoveArrayInDirection(category.channels, channelIndex, direction);
|
||||
};
|
||||
|
||||
|
||||
|
@ -150,70 +138,44 @@ function swapElementsInArray(array: any[], index1: number, index2: number) {
|
|||
[array[index1], array[index2]] = [array[index2], array[index1]];
|
||||
}
|
||||
|
||||
// stolen from PinDMs
|
||||
export async function moveCategory(id: string, direction: -1 | 1) {
|
||||
const a = categories.findIndex(m => m.id === id);
|
||||
export function moveCategory(id: string, direction: -1 | 1) {
|
||||
const a = currentUserCategories.findIndex(m => m.id === id);
|
||||
const b = a + direction;
|
||||
|
||||
swapElementsInArray(categories, a, b);
|
||||
|
||||
await saveCats(categories);
|
||||
swapElementsInArray(currentUserCategories, a, b);
|
||||
}
|
||||
|
||||
export async function moveChannel(channelId: string, direction: -1 | 1) {
|
||||
const category = categories.find(c => c.channels.includes(channelId));
|
||||
if (!category) return;
|
||||
export function moveChannel(channelId: string, direction: -1 | 1) {
|
||||
const category = currentUserCategories.find(c => c.channels.includes(channelId));
|
||||
if (category == null) return;
|
||||
|
||||
const a = category.channels.indexOf(channelId);
|
||||
const b = a + direction;
|
||||
|
||||
swapElementsInArray(category.channels, a, b);
|
||||
|
||||
await saveCats(categories);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// migrate data
|
||||
const getPinDMsPins = () => (Settings.plugins.PinDMs.pinnedDMs || void 0)?.split(",") as string[] | undefined;
|
||||
|
||||
async function migratePinDMs() {
|
||||
if (categories.some(m => m.id === "oldPins")) {
|
||||
return await DataStore.set(CATEGORY_MIGRATED_PINDMS_KEY, true);
|
||||
// TODO: Remove DataStore PinnedDms migration once enough time has passed
|
||||
async function migrateData() {
|
||||
if (Settings.plugins.PinDMs.dmSectioncollapsed != null) {
|
||||
settings.store.dmSectionCollapsed = Settings.plugins.PinDMs.dmSectioncollapsed;
|
||||
delete Settings.plugins.PinDMs.dmSectioncollapsed;
|
||||
}
|
||||
|
||||
const pindmspins = getPinDMsPins();
|
||||
const dataStoreKeys = await DataStore.keys();
|
||||
const pinDmsKeys = dataStoreKeys.map(key => String(key)).filter(key => key.startsWith(CATEGORY_BASE_KEY));
|
||||
|
||||
// we dont want duplicate pins
|
||||
const difference = [...new Set(pindmspins)]?.filter(m => !categories.some(c => c.channels.includes(m)));
|
||||
if (difference?.length) {
|
||||
categories.push({
|
||||
id: "oldPins",
|
||||
name: "Pins",
|
||||
color: DEFAULT_COLOR,
|
||||
channels: difference
|
||||
});
|
||||
if (pinDmsKeys.length === 0) return;
|
||||
|
||||
for (const pinDmsKey of pinDmsKeys) {
|
||||
const categories = await DataStore.get<Category[]>(pinDmsKey);
|
||||
if (categories == null) continue;
|
||||
|
||||
const userId = pinDmsKey.replace(CATEGORY_BASE_KEY, "");
|
||||
settings.store.userBasedCategoryList[userId] = categories;
|
||||
|
||||
await DataStore.del(pinDmsKey);
|
||||
}
|
||||
|
||||
await DataStore.set(CATEGORY_MIGRATED_PINDMS_KEY, true);
|
||||
}
|
||||
|
||||
async function migrateOldCategories(userId: string) {
|
||||
const oldCats = await DataStore.get<Category[]>(OLD_CATEGORY_KEY + userId);
|
||||
// dont want to migrate if the user has already has categories.
|
||||
if (categories.length === 0 && oldCats?.length) {
|
||||
categories.push(...(oldCats.filter(m => m.id !== "oldPins")));
|
||||
}
|
||||
await DataStore.set(CATEGORY_MIGRATED_KEY, true);
|
||||
}
|
||||
|
||||
export async function migrateData(userId: string) {
|
||||
const m1 = await DataStore.get(CATEGORY_MIGRATED_KEY), m2 = await DataStore.get(CATEGORY_MIGRATED_PINDMS_KEY);
|
||||
if (m1 && m2) return;
|
||||
|
||||
// want to migrate the old categories first and then slove any conflicts with the PinDMs pins
|
||||
if (!m1) await migrateOldCategories(userId);
|
||||
if (!m2) await migratePinDMs();
|
||||
|
||||
await saveCats(categories);
|
||||
await Promise.all([DataStore.del(CATEGORY_MIGRATED_PINDMS_KEY), DataStore.del(CATEGORY_MIGRATED_KEY), DataStore.del(OLD_CATEGORY_KEY)]);
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import { Devs } from "@utils/constants";
|
|||
import { classes } from "@utils/misc";
|
||||
import definePlugin, { OptionType, StartAt } from "@utils/types";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common";
|
||||
import { Clickable, ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common";
|
||||
import { Channel } from "discord-types/general";
|
||||
|
||||
import { contextMenus } from "./components/contextMenu";
|
||||
import { openCategoryModal, requireSettingsMenu } from "./components/CreateCategoryModal";
|
||||
import { DEFAULT_CHUNK_SIZE } from "./constants";
|
||||
import { canMoveCategory, canMoveCategoryInDirection, categories, Category, categoryLen, collapseCategory, getAllUncollapsedChannels, getSections, init, isPinned, moveCategory, removeCategory } from "./data";
|
||||
import { canMoveCategory, canMoveCategoryInDirection, Category, categoryLen, collapseCategory, getAllUncollapsedChannels, getCategoryByIndex, getSections, init, isPinned, moveCategory, removeCategory, usePinnedDms } from "./data";
|
||||
|
||||
interface ChannelComponentProps {
|
||||
children: React.ReactNode,
|
||||
|
@ -26,13 +26,11 @@ interface ChannelComponentProps {
|
|||
selected: boolean;
|
||||
}
|
||||
|
||||
|
||||
const headerClasses = findByPropsLazy("privateChannelsHeaderContainer");
|
||||
|
||||
export const PrivateChannelSortStore = findStoreLazy("PrivateChannelSortStore") as { getPrivateChannelIds: () => string[]; };
|
||||
|
||||
export let instance: any;
|
||||
export const forceUpdate = () => instance?.props?._forceUpdate?.();
|
||||
|
||||
export const enum PinOrder {
|
||||
LastMessage,
|
||||
|
@ -46,21 +44,28 @@ export const settings = definePluginSettings({
|
|||
options: [
|
||||
{ label: "Most recent message", value: PinOrder.LastMessage, default: true },
|
||||
{ label: "Custom (right click channels to reorder)", value: PinOrder.Custom }
|
||||
],
|
||||
onChange: () => forceUpdate()
|
||||
]
|
||||
},
|
||||
|
||||
dmSectioncollapsed: {
|
||||
canCollapseDmSection: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Collapse DM sections",
|
||||
description: "Allow uncategorised DMs section to be collapsable",
|
||||
default: false
|
||||
},
|
||||
dmSectionCollapsed: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Collapse DM section",
|
||||
default: false,
|
||||
onChange: () => forceUpdate()
|
||||
hidden: true
|
||||
},
|
||||
userBasedCategoryList: {
|
||||
type: OptionType.CUSTOM,
|
||||
default: {} as Record<string, Category[]>
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "PinDMs",
|
||||
description: "Allows you to pin private channels to the top of your DM list. To pin/unpin or reorder pins, right click DMs",
|
||||
description: "Allows you to pin private channels to the top of your DM list. To pin/unpin or re-order pins, right click DMs",
|
||||
authors: [Devs.Ven, Devs.Aria],
|
||||
settings,
|
||||
contextMenus,
|
||||
|
@ -124,8 +129,8 @@ export default definePlugin({
|
|||
{
|
||||
find: ".FRIENDS},\"friends\"",
|
||||
replacement: {
|
||||
match: /let{showLibrary:\i,.+?showDMHeader:.+?,/,
|
||||
replace: "let forceUpdate = Vencord.Util.useForceUpdater();$&_forceUpdate:forceUpdate,"
|
||||
match: /let{showLibrary:\i,/,
|
||||
replace: "$self.usePinnedDms();$&"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -149,6 +154,7 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
],
|
||||
|
||||
sections: null as number[] | null,
|
||||
|
||||
set _instance(i: any) {
|
||||
|
@ -162,6 +168,7 @@ export default definePlugin({
|
|||
CONNECTION_OPEN: init,
|
||||
},
|
||||
|
||||
usePinnedDms,
|
||||
isPinned,
|
||||
categoryLen,
|
||||
getSections,
|
||||
|
@ -186,11 +193,11 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
makeSpanProps() {
|
||||
return {
|
||||
return settings.store.canCollapseDmSection ? {
|
||||
onClick: () => this.collapseDMList(),
|
||||
role: "button",
|
||||
style: { cursor: "pointer" }
|
||||
};
|
||||
} : undefined;
|
||||
},
|
||||
|
||||
getChunkSize() {
|
||||
|
@ -210,30 +217,27 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
isChannelIndex(sectionIndex: number, channelIndex: number) {
|
||||
if (settings.store.dmSectioncollapsed && sectionIndex !== 0)
|
||||
if (settings.store.canCollapseDmSection && settings.store.dmSectionCollapsed && sectionIndex !== 0) {
|
||||
return true;
|
||||
const cat = categories[sectionIndex - 1];
|
||||
return this.isCategoryIndex(sectionIndex) && (cat?.channels?.length === 0 || cat?.channels[channelIndex]);
|
||||
},
|
||||
}
|
||||
|
||||
isDMSectioncollapsed() {
|
||||
return settings.store.dmSectioncollapsed;
|
||||
const category = getCategoryByIndex(sectionIndex - 1);
|
||||
return this.isCategoryIndex(sectionIndex) && (category?.channels?.length === 0 || category?.channels[channelIndex]);
|
||||
},
|
||||
|
||||
collapseDMList() {
|
||||
settings.store.dmSectioncollapsed = !settings.store.dmSectioncollapsed;
|
||||
forceUpdate();
|
||||
settings.store.dmSectionCollapsed = !settings.store.dmSectionCollapsed;
|
||||
},
|
||||
|
||||
isChannelHidden(categoryIndex: number, channelIndex: number) {
|
||||
if (categoryIndex === 0) return false;
|
||||
|
||||
if (settings.store.dmSectioncollapsed && this.getSections().length + 1 === categoryIndex)
|
||||
if (settings.store.canCollapseDmSection && settings.store.dmSectionCollapsed && this.getSections().length + 1 === categoryIndex)
|
||||
return true;
|
||||
|
||||
if (!this.instance || !this.isChannelIndex(categoryIndex, channelIndex)) return false;
|
||||
|
||||
const category = categories[categoryIndex - 1];
|
||||
const category = getCategoryByIndex(categoryIndex - 1);
|
||||
if (!category) return false;
|
||||
|
||||
return category.collapsed && this.instance.props.selectedChannelId !== this.getCategoryChannels(category)[channelIndex];
|
||||
|
@ -251,18 +255,12 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
renderCategory: ErrorBoundary.wrap(({ section }: { section: number; }) => {
|
||||
const category = categories[section - 1];
|
||||
|
||||
const category = getCategoryByIndex(section - 1);
|
||||
if (!category) return null;
|
||||
|
||||
return (
|
||||
<h2
|
||||
className={classes(headerClasses.privateChannelsHeaderContainer, "vc-pindms-section-container", category.collapsed ? "vc-pindms-collapsed" : "")}
|
||||
style={{ color: `#${category.color.toString(16).padStart(6, "0")}` }}
|
||||
onClick={async () => {
|
||||
await collapseCategory(category.id, !category.collapsed);
|
||||
forceUpdate();
|
||||
}}
|
||||
<Clickable
|
||||
onClick={() => collapseCategory(category.id, !category.collapsed)}
|
||||
onContextMenu={e => {
|
||||
ContextMenuApi.openContextMenu(e, () => (
|
||||
<Menu.Menu
|
||||
|
@ -284,14 +282,14 @@ export default definePlugin({
|
|||
canMoveCategoryInDirection(category.id, -1) && <Menu.MenuItem
|
||||
id="vc-pindms-move-category-up"
|
||||
label="Move Up"
|
||||
action={() => moveCategory(category.id, -1).then(() => forceUpdate())}
|
||||
action={() => moveCategory(category.id, -1)}
|
||||
/>
|
||||
}
|
||||
{
|
||||
canMoveCategoryInDirection(category.id, 1) && <Menu.MenuItem
|
||||
id="vc-pindms-move-category-down"
|
||||
label="Move Down"
|
||||
action={() => moveCategory(category.id, 1).then(() => forceUpdate())}
|
||||
action={() => moveCategory(category.id, 1)}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
|
@ -304,7 +302,7 @@ export default definePlugin({
|
|||
id="vc-pindms-delete-category"
|
||||
color="danger"
|
||||
label="Delete Category"
|
||||
action={() => removeCategory(category.id).then(() => forceUpdate())}
|
||||
action={() => removeCategory(category.id)}
|
||||
/>
|
||||
|
||||
|
||||
|
@ -312,13 +310,18 @@ export default definePlugin({
|
|||
));
|
||||
}}
|
||||
>
|
||||
<span className={headerClasses.headerText}>
|
||||
{category?.name ?? "uh oh"}
|
||||
</span>
|
||||
<svg className="vc-pindms-collapse-icon" aria-hidden="true" role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M9.3 5.3a1 1 0 0 0 0 1.4l5.29 5.3-5.3 5.3a1 1 0 1 0 1.42 1.4l6-6a1 1 0 0 0 0-1.4l-6-6a1 1 0 0 0-1.42 0Z"></path>
|
||||
</svg>
|
||||
</h2>
|
||||
<h2
|
||||
className={classes(headerClasses.privateChannelsHeaderContainer, "vc-pindms-section-container", category.collapsed ? "vc-pindms-collapsed" : "")}
|
||||
style={{ color: `#${category.color.toString(16).padStart(6, "0")}` }}
|
||||
>
|
||||
<span className={headerClasses.headerText}>
|
||||
{category?.name ?? "uh oh"}
|
||||
</span>
|
||||
<svg className="vc-pindms-collapse-icon" aria-hidden="true" role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M9.3 5.3a1 1 0 0 0 0 1.4l5.29 5.3-5.3 5.3a1 1 0 1 0 1.42 1.4l6-6a1 1 0 0 0 0-1.4l-6-6a1 1 0 0 0-1.42 0Z"></path>
|
||||
</svg>
|
||||
</h2>
|
||||
</Clickable>
|
||||
);
|
||||
}, { noop: true }),
|
||||
|
||||
|
@ -341,7 +344,7 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
getChannel(sectionIndex: number, index: number, channels: Record<string, Channel>) {
|
||||
const category = categories[sectionIndex - 1];
|
||||
const category = getCategoryByIndex(sectionIndex - 1);
|
||||
if (!category) return { channel: null, category: null };
|
||||
|
||||
const channelId = this.getCategoryChannels(category)[index];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue