improve various types (#3663)

Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: John Davis <70701251+gobuster@users.noreply.github.com>
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
This commit is contained in:
V 2025-09-09 01:48:53 +02:00 committed by GitHub
parent 84957b0e88
commit c38aac23fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 128 additions and 40 deletions

View file

@ -17,7 +17,7 @@
*/
import { Logger } from "@utils/Logger";
import type { Channel, CustomEmoji, Message } from "@vencord/discord-types";
import type { Channel, CloudUpload, CustomEmoji, Message } from "@vencord/discord-types";
import { MessageStore } from "@webpack/common";
import type { Promisable } from "type-fest";
@ -30,30 +30,6 @@ export interface MessageObject {
tts: boolean;
}
export interface Upload {
classification: string;
currentSize: number;
description: string | null;
filename: string;
id: string;
isImage: boolean;
isVideo: boolean;
item: {
file: File;
platform: number;
};
loaded: number;
mimeType: string;
preCompressionSize: number;
responseUrl: string;
sensitive: boolean;
showLargeMessageDialog: boolean;
spoiler: boolean;
status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED";
uniqueId: string;
uploadedFilename: string;
}
export interface MessageReplyOptions {
messageReference: Message["messageReference"];
allowedMentions?: {
@ -64,7 +40,7 @@ export interface MessageReplyOptions {
export interface MessageOptions {
stickers?: string[];
uploads?: Upload[];
uploads?: CloudUpload[];
replyOptions: MessageReplyOptions;
content: string;
channel: Channel;

View file

@ -16,7 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import ErrorBoundary from "@components/ErrorBoundary";
import { isPrimitiveReactNode } from "@utils/react";
import { waitFor } from "@webpack";
import { ReactNode } from "react";
let NoticesModule: any;
waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m);
@ -36,7 +39,11 @@ export function nextNotice() {
}
}
export function showNotice(message: string, buttonText: string, onOkClick: () => void) {
noticesQueue.push(["GENERIC", message, buttonText, onOkClick]);
export function showNotice(message: ReactNode, buttonText: string, onOkClick: () => void) {
const notice = isPrimitiveReactNode(message)
? message
: <ErrorBoundary fallback={() => "Error Showing Notice"}>{message}</ErrorBoundary>;
noticesQueue.push(["GENERIC", notice, buttonText, onOkClick]);
if (!currentNotice) nextNotice();
}

View file

@ -16,11 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Upload } from "@api/MessageEvents";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { CloudUpload } from "@vencord/discord-types";
import { findByCodeLazy } from "@webpack";
import { useState } from "@webpack/common";
@ -89,7 +89,7 @@ export default definePlugin({
},
],
AnonymiseUploadButton: ErrorBoundary.wrap(({ upload }: { upload: Upload; }) => {
AnonymiseUploadButton: ErrorBoundary.wrap(({ upload }: { upload: CloudUpload; }) => {
const [anonymise, setAnonymise] = useState(upload[ANONYMISE_UPLOAD_SYMBOL] ?? settings.store.anonymiseByDefault);
function onToggleAnonymise() {
@ -110,7 +110,7 @@ export default definePlugin({
);
}, { noop: true }),
anonymise(upload: Upload) {
anonymise(upload: CloudUpload) {
if ((upload[ANONYMISE_UPLOAD_SYMBOL] ?? settings.store.anonymiseByDefault) === false) {
return;
}

View file

@ -20,7 +20,7 @@ import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
import { generateId, sendBotMessage } from "@api/Commands";
import { Devs } from "@utils/constants";
import definePlugin, { StartAt } from "@utils/types";
import { MessageAttachment } from "@vencord/discord-types";
import { CloudUpload, MessageAttachment } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { DraftStore, DraftType, SelectedChannelStore, UserStore, useStateFromStores } from "@webpack/common";
@ -45,7 +45,7 @@ const getImageBox = (url: string): Promise<{ width: number, height: number; } |
const getAttachments = async (channelId: string) =>
await Promise.all(
UploadStore.getUploads(channelId, DraftType.ChannelMessage)
.map(async (upload: any) => {
.map(async (upload: CloudUpload) => {
const { isImage, filename, spoiler, item: { file } } = upload;
const url = URL.createObjectURL(file);
const attachment: MessageAttachment = {
@ -53,7 +53,7 @@ const getAttachments = async (channelId: string) =>
filename: spoiler ? "SPOILER_" + filename : filename,
// weird eh? if i give it the normal content type the preview doenst work
content_type: undefined,
size: await upload.getSize(),
size: upload.getSize(),
spoiler,
// discord adds query params to the url, so we need to add a hash to prevent that
url: url + "#",

View file

@ -27,6 +27,8 @@ import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModa
import { useAwaiter } from "@utils/react";
import definePlugin from "@utils/types";
import { chooseFile } from "@utils/web";
import { CloudUpload as TCloudUpload } from "@vencord/discord-types";
import { CloudUploadPlatform } from "@vencord/discord-types/enums";
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
import { Button, Card, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
import { ComponentType } from "react";
@ -37,7 +39,7 @@ import { cl } from "./utils";
import { VoicePreview } from "./VoicePreview";
import { VoiceRecorderWeb } from "./WebRecorder";
const CloudUpload = findLazy(m => m.prototype?.trackUploadFinished);
const CloudUpload: typeof TCloudUpload = findLazy(m => m.prototype?.trackUploadFinished);
const PendingReplyStore = findStoreLazy("PendingReplyStore");
const OptionClasses = findByPropsLazy("optionName", "optionIcon", "optionLabel");
@ -92,8 +94,8 @@ function sendAudio(blob: Blob, meta: AudioMetadata) {
const upload = new CloudUpload({
file: new File([blob], "voice-message.ogg", { type: "audio/ogg; codecs=opus" }),
isThumbnail: false,
platform: 1,
}, channelId, false, 0);
platform: CloudUploadPlatform.WEB,
}, channelId);
upload.on("complete", () => {
RestAPI.post({

View file

@ -17,7 +17,7 @@
*/
import { MessageObject } from "@api/MessageEvents";
import { Channel, Guild, GuildFeatures, Message, User } from "@vencord/discord-types";
import { Channel, CloudUpload, Guild, GuildFeatures, Message, User } from "@vencord/discord-types";
import { ChannelActionCreators, ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, i18n, IconUtils, InviteActions, MessageActions, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common";
import { Except } from "type-fest";
@ -117,6 +117,20 @@ interface MessageOptions {
replied_user: boolean;
};
stickerIds: string[];
attachmentsToUpload: CloudUpload[];
poll: {
allow_multiselect: boolean;
answers: Array<{
poll_media: {
text: string;
attachment_ids?: unknown;
emoji?: { name: string; id?: string; };
};
}>;
duration: number;
layout_type: number;
question: { text: string; };
};
}
export function sendMessage(

View file

@ -17,7 +17,7 @@
*/
import { React, useEffect, useMemo, useReducer, useState } from "@webpack/common";
import { ActionDispatch } from "react";
import { ActionDispatch, ReactNode } from "react";
import { checkIntersecting } from "./misc";
@ -25,6 +25,14 @@ export * from "./lazyReact";
export const NoopComponent = () => null;
/**
* Check if a React node is a primitive (string, number, bigint, boolean, undefined)
*/
export function isPrimitiveReactNode(node: ReactNode): boolean {
const t = typeof node;
return t === "string" || t === "number" || t === "bigint" || t === "boolean" || t === "undefined";
}
/**
* Check if an element is on screen
* @param intersectOnly If `true`, will only update the state when the element comes into view