1
0
mirror of https://github.com/spacebarchat/client.git synced 2024-11-22 10:22:30 +01:00

fix upload progress

This commit is contained in:
Puyodead1 2023-09-02 22:43:05 -04:00
parent 3bf5f11f78
commit b1a6f318be
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
10 changed files with 84 additions and 59 deletions

View File

@ -1,6 +1,7 @@
import { observer } from "mobx-react-lite";
import styled from "styled-components";
import { QueuedMessage } from "../../stores/MessageQueue";
import { useAppStore } from "../../stores/AppStore";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import Icon from "../Icon";
import IconButton from "../IconButton";
@ -41,7 +42,7 @@ interface Props {
}
function AttachmentUploadProgress({ message }: Props) {
console.log(message.progress);
const app = useAppStore();
return (
<Container>
@ -49,7 +50,14 @@ function AttachmentUploadProgress({ message }: Props) {
<div>{message.files!.length === 1 ? message.files![0].name : `${message.files!.length} files`}</div>
<Progress value={message.progress} max={100} />
</Wrapper>
<IconButton variant="blank">
<IconButton
variant="blank"
onClick={() => {
message.abort();
// remove the message from the queue
app.queue.remove(message.id);
}}
>
<CustomIcon icon="mdiClose" size="24px" />
</IconButton>
</Container>

View File

@ -6,8 +6,8 @@ import Moment from "react-moment";
import styled from "styled-components";
import { ContextMenuContext } from "../../contexts/ContextMenuContext";
import useLogger from "../../hooks/useLogger";
import { QueuedMessage } from "../../stores/MessageQueue";
import { default as MessageObject } from "../../stores/objects/Message";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import { calculateImageRatio, calculateScaledDimensions } from "../../utils/Message";
import { calendarStrings } from "../../utils/i18n";
import Avatar from "../Avatar";
@ -183,8 +183,6 @@ function Message({ message, isHeader, isSending, isFailed }: Props) {
);
}, []);
if (message instanceof QueuedMessage) console.log(`progress at msg`, message.progress);
// construct the context menu options
// React.useEffect(() => {
// // if the message is queued, we don't need a context menu

View File

@ -1,8 +1,9 @@
import { observer } from "mobx-react-lite";
import React from "react";
import styled from "styled-components";
import { QueuedMessage, QueuedMessageStatus } from "../../stores/MessageQueue";
import { QueuedMessageStatus } from "../../stores/MessageQueue";
import { default as MessageObject } from "../../stores/objects/Message";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import Message from "./Message";
const Container = styled.div`
@ -18,7 +19,6 @@ interface Props {
*/
function MessageGroup({ messages }: Props) {
const renderMessage = React.useCallback((message: MessageObject | QueuedMessage, index: number) => {
if (message instanceof QueuedMessage) console.log(`progress at msg group`, message.progress);
return (
<Message
key={message.id}

View File

@ -123,7 +123,6 @@ function MessageInput(props: Props) {
const shouldSend = !app.experiments.isTreatmentEnabled("message_queue", 1);
const canSend = props.channel.canSendMessage(content, attachments);
console.log(`canSendMessage`, canSend);
if (!canSend && !shouldFail) return;
const nonce = Snowflake.generate();
@ -147,8 +146,8 @@ function MessageInput(props: Props) {
} else {
body = { content, nonce };
}
props.channel.sendMessage(body, msg.progressCallback).catch((error) => {
app.queue.error(nonce, error as string);
props.channel.sendMessage(body, msg).catch((error) => {
if (error) app.queue.error(nonce, error as string);
});
}

View File

@ -5,10 +5,10 @@ import PulseLoader from "react-spinners/PulseLoader";
import styled from "styled-components";
import useLogger from "../../hooks/useLogger";
import { useAppStore } from "../../stores/AppStore";
import { QueuedMessage } from "../../stores/MessageQueue";
import Channel from "../../stores/objects/Channel";
import Guild from "../../stores/objects/Guild";
import Message from "../../stores/objects/Message";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import { Permissions } from "../../utils/Permissions";
import { HorizontalDivider } from "../Divider";
import MessageGroup from "./MessageGroup";
@ -66,6 +66,7 @@ function MessageList({ guild, channel }: Props) {
// get last group
const lastGroup = channel.messages.grouped[channel.messages.grouped.length - 1];
// ignore queued messages
if ("status" in lastGroup) return;
// get first message in the group to use as before
const before = lastGroup[0].id;
@ -112,7 +113,9 @@ function MessageList({ guild, channel }: Props) {
</EndMessageContainer>
}
>
{channel.messages.grouped.map((group, index) => renderMessageGroup(group, index))}
{channel.messages.grouped.map((group, index) => (
<MessageGroup key={index} messages={group} />
))}
</InfiniteScroll>
) : (
<div

View File

@ -1,9 +1,9 @@
import type { APIMessage } from "@spacebarchat/spacebar-api-types/v9";
import { MessageType } from "@spacebarchat/spacebar-api-types/v9";
import { action, computed, makeAutoObservable, observable } from "mobx";
import type { IObservableArray } from "mobx";
import Snowflake from "../utils/Snowflake";
import QueuedMessage from "./objects/QueuedMessage";
import User from "./objects/User";
export enum QueuedMessageStatus {
@ -19,46 +19,6 @@ export type QueuedMessageData = {
files?: File[];
};
// export interface QueuedMessage extends QueuedMessageData {
// status: QueuedMessageStatus;
// error?: string;
// timestamp: Date;
// type: MessageType;
// }
export class QueuedMessage implements QueuedMessageData {
id: string;
channel: string;
author: User;
content: string;
files?: File[];
@observable progress: number;
status: QueuedMessageStatus;
error?: string;
timestamp: Date;
type: MessageType;
constructor(data: QueuedMessageData) {
this.id = data.id;
this.channel = data.channel;
this.author = data.author;
this.content = data.content;
this.files = data.files;
this.progress = 0;
this.status = QueuedMessageStatus.SENDING;
this.timestamp = new Date();
this.type = MessageType.Default;
makeAutoObservable(this);
}
@action
progressCallback(e: ProgressEvent) {
this.progress = Math.round((e.loaded / e.total) * 100);
console.log(this.progress);
}
}
export default class MessageQueue {
@observable private readonly messages: IObservableArray<QueuedMessage>;

View File

@ -4,8 +4,8 @@ import { action, computed, makeObservable, observable } from "mobx";
import useLogger from "../hooks/useLogger";
import Logger from "../utils/Logger";
import AppStore from "./AppStore";
import { QueuedMessage } from "./MessageQueue";
import Message from "./objects/Message";
import QueuedMessage from "./objects/QueuedMessage";
export default class MessageStore {
private readonly app: AppStore;

View File

@ -19,6 +19,7 @@ import Logger from "../../utils/Logger";
import { APIError } from "../../utils/interfaces/api";
import AppStore from "../AppStore";
import MessageStore from "../MessageStore";
import QueuedMessage from "./QueuedMessage";
export default class Channel {
private readonly logger: Logger = new Logger("Channel");
@ -198,13 +199,13 @@ export default class Channel {
}
@action
async sendMessage(data: RESTPostAPIChannelMessageJSONBody | FormData, cb?: (e: ProgressEvent) => void) {
async sendMessage(data: RESTPostAPIChannelMessageJSONBody | FormData, msg?: QueuedMessage) {
if (data instanceof FormData)
return this.app.rest.postFormData<RESTPostAPIChannelMessageResult>(
Routes.channelMessages(this.id),
data,
undefined,
cb,
msg,
);
return this.app.rest.post<RESTPostAPIChannelMessageJSONBody, RESTPostAPIChannelMessageResult>(
Routes.channelMessages(this.id),

View File

@ -0,0 +1,46 @@
import { MessageType } from "@spacebarchat/spacebar-api-types/v9";
import { action, makeAutoObservable, observable } from "mobx";
import { QueuedMessageData, QueuedMessageStatus } from "../MessageQueue";
import User from "./User";
export default class QueuedMessage {
id: string;
channel: string;
author: User;
content: string;
files?: File[];
@observable progress = 0;
status: QueuedMessageStatus;
error?: string;
timestamp: Date;
type: MessageType;
abortCallback?: () => void;
constructor(data: QueuedMessageData) {
this.id = data.id;
this.channel = data.channel;
this.author = data.author;
this.content = data.content;
this.files = data.files;
this.status = QueuedMessageStatus.SENDING;
this.timestamp = new Date();
this.type = MessageType.Default;
makeAutoObservable(this);
}
@action
updateProgress(e: ProgressEvent) {
this.progress = Math.round((e.loaded / e.total) * 100);
}
setAbortCallback(cb: () => void) {
this.abortCallback = cb;
}
abort() {
if (this.abortCallback) {
this.abortCallback();
}
}
}

View File

@ -3,6 +3,7 @@
// import {DomainStore} from '../stores/DomainStore';
import AppStore from "../stores/AppStore";
import QueuedMessage from "../stores/objects/QueuedMessage";
import { Globals, RouteSettings } from "./Globals";
import Logger from "./Logger";
@ -142,13 +143,22 @@ export default class REST {
body: FormData,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryParams: Record<string, any> = {},
progressCb?: (ev: ProgressEvent) => void,
msg?: QueuedMessage,
): Promise<U> {
return new Promise((resolve, reject) => {
const url = REST.makeAPIUrl(path, queryParams);
this.logger.debug(`POST ${url}; payload:`, body);
const xhr = new XMLHttpRequest();
if (progressCb) xhr.upload.addEventListener("progress", progressCb);
if (msg) {
// add abort callback
msg.setAbortCallback(() => {
this.logger.debug("[PostFormData]: Message called abort");
xhr.abort();
reject("aborted");
});
// add progress listener
xhr.upload.addEventListener("progress", (e: ProgressEvent) => msg.updateProgress(e));
}
xhr.addEventListener("loadend", () => {
// if success, resolve text or json
if (xhr.status >= 200 && xhr.status < 300) {