Compare commits
1 Commits
b7e5db9de4
...
0bf31a55fd
| Author | SHA1 | Date | |
|---|---|---|---|
| 0bf31a55fd |
@@ -14,15 +14,13 @@ use matrix_sdk::deserialized_responses::{TimelineEvent, TimelineEventKind};
|
|||||||
use matrix_sdk::media::MediaEventContent;
|
use matrix_sdk::media::MediaEventContent;
|
||||||
use matrix_sdk::room::MessagesOptions;
|
use matrix_sdk::room::MessagesOptions;
|
||||||
use matrix_sdk::room::edit::EditedContent;
|
use matrix_sdk::room::edit::EditedContent;
|
||||||
use matrix_sdk::room::reply::{EnforceThread, Reply};
|
|
||||||
use matrix_sdk::ruma::api::client::filter::RoomEventFilter;
|
use matrix_sdk::ruma::api::client::filter::RoomEventFilter;
|
||||||
use matrix_sdk::ruma::api::client::receipt::create_receipt::v3::ReceiptType;
|
use matrix_sdk::ruma::api::client::receipt::create_receipt::v3::ReceiptType;
|
||||||
use matrix_sdk::ruma::events::reaction::ReactionEventContent;
|
use matrix_sdk::ruma::events::reaction::ReactionEventContent;
|
||||||
use matrix_sdk::ruma::events::receipt::ReceiptThread;
|
use matrix_sdk::ruma::events::receipt::ReceiptThread;
|
||||||
use matrix_sdk::ruma::events::relation::{Annotation, InReplyTo};
|
use matrix_sdk::ruma::events::relation::Annotation;
|
||||||
use matrix_sdk::ruma::events::room::message::{
|
use matrix_sdk::ruma::events::room::message::{
|
||||||
MessageType, Relation, RoomMessageEvent, RoomMessageEventContent,
|
MessageType, RoomMessageEvent, RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
|
||||||
RoomMessageEventContentWithoutRelation,
|
|
||||||
};
|
};
|
||||||
use matrix_sdk::ruma::events::{AnyMessageLikeEvent, AnyTimelineEvent};
|
use matrix_sdk::ruma::events::{AnyMessageLikeEvent, AnyTimelineEvent};
|
||||||
use matrix_sdk::ruma::{MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UInt};
|
use matrix_sdk::ruma::{MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UInt};
|
||||||
@@ -124,8 +122,6 @@ pub async fn get_for_room(
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct SendTextMessageRequest {
|
struct SendTextMessageRequest {
|
||||||
content: String,
|
content: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
in_reply_to: Option<OwnedEventId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_text_message(
|
pub async fn send_text_message(
|
||||||
@@ -138,15 +134,8 @@ pub async fn send_text_message(
|
|||||||
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut evt = RoomMessageEventContent::text_plain(req.content);
|
room.send(RoomMessageEventContent::text_plain(req.content))
|
||||||
|
.await?;
|
||||||
if let Some(event_id) = req.in_reply_to {
|
|
||||||
evt.relates_to = Some(Relation::Reply {
|
|
||||||
in_reply_to: InReplyTo::new(event_id),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
room.send(evt).await?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Accepted().finish())
|
Ok(HttpResponse::Accepted().finish())
|
||||||
}
|
}
|
||||||
@@ -157,16 +146,9 @@ pub struct SendFileForm {
|
|||||||
file: actix_multipart::form::tempfile::TempFile,
|
file: actix_multipart::form::tempfile::TempFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
|
||||||
pub struct SendFileQuery {
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
in_reply_to: Option<OwnedEventId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_file(
|
pub async fn send_file(
|
||||||
client: MatrixClientExtractor,
|
client: MatrixClientExtractor,
|
||||||
path: web::Path<RoomIdInPath>,
|
path: web::Path<RoomIdInPath>,
|
||||||
query: web::Query<SendFileQuery>,
|
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> HttpResult {
|
) -> HttpResult {
|
||||||
let Some(payload) = client.auth.payload else {
|
let Some(payload) = client.auth.payload else {
|
||||||
@@ -200,17 +182,8 @@ pub async fn send_file(
|
|||||||
return Ok(HttpResponse::BadRequest().json("File content type must be specified!"));
|
return Ok(HttpResponse::BadRequest().json("File content type must be specified!"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut config = AttachmentConfig::new();
|
|
||||||
|
|
||||||
if let Some(event_id) = query.0.in_reply_to {
|
|
||||||
config.reply = Some(Reply {
|
|
||||||
event_id,
|
|
||||||
enforce_thread: EnforceThread::MaybeThreaded,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do send the file
|
// Do send the file
|
||||||
room.send_attachment(file_name, mime_type, buff, config)
|
room.send_attachment(file_name, mime_type, buff, AttachmentConfig::new())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Accepted().finish())
|
Ok(HttpResponse::Accepted().finish())
|
||||||
@@ -221,25 +194,6 @@ pub struct EventIdInPath {
|
|||||||
pub(crate) event_id: OwnedEventId,
|
pub(crate) event_id: OwnedEventId,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a single event information
|
|
||||||
pub async fn get_event(
|
|
||||||
client: MatrixClientExtractor,
|
|
||||||
path: web::Path<RoomIdInPath>,
|
|
||||||
event_path: web::Path<EventIdInPath>,
|
|
||||||
) -> HttpResult {
|
|
||||||
let Some(room) = client.client.client.get_room(&path.room_id) else {
|
|
||||||
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let event = room.load_or_fetch_event(&event_path.event_id, None).await?;
|
|
||||||
|
|
||||||
Ok(match event.kind {
|
|
||||||
TimelineEventKind::Decrypted(dec) => HttpResponse::Ok().json(dec.event),
|
|
||||||
TimelineEventKind::UnableToDecrypt { event, .. }
|
|
||||||
| TimelineEventKind::PlainText { event } => HttpResponse::Ok().json(event),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn set_text_content(
|
pub async fn set_text_content(
|
||||||
client: MatrixClientExtractor,
|
client: MatrixClientExtractor,
|
||||||
path: web::Path<RoomIdInPath>,
|
path: web::Path<RoomIdInPath>,
|
||||||
|
|||||||
@@ -190,10 +190,6 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/matrix/room/{room_id}/send_file",
|
"/api/matrix/room/{room_id}/send_file",
|
||||||
web::post().to(matrix_event_controller::send_file),
|
web::post().to(matrix_event_controller::send_file),
|
||||||
)
|
)
|
||||||
.route(
|
|
||||||
"/api/matrix/room/{room_id}/event/{event_id}",
|
|
||||||
web::get().to(matrix_event_controller::get_event),
|
|
||||||
)
|
|
||||||
.route(
|
.route(
|
||||||
"/api/matrix/room/{room_id}/event/{event_id}/set_text_content",
|
"/api/matrix/room/{room_id}/event/{event_id}/set_text_content",
|
||||||
web::post().to(matrix_event_controller::set_text_content),
|
web::post().to(matrix_event_controller::set_text_content),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>MatrixGW</title>
|
<title>MatrixGW</title>
|
||||||
<style>body {background-color: black;}</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"@vitejs/plugin-react": "^5.1.4",
|
"@vitejs/plugin-react": "^5.1.4",
|
||||||
"eslint": "^10.0.2",
|
"eslint": "^10.0.2",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.5.2",
|
"eslint-plugin-react-refresh": "^0.4.26",
|
||||||
"globals": "^17.4.0",
|
"globals": "^17.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.56.1",
|
"typescript-eslint": "^8.56.1",
|
||||||
|
|||||||
@@ -96,33 +96,23 @@ export class MatrixApiEvent {
|
|||||||
/**
|
/**
|
||||||
* Send text message
|
* Send text message
|
||||||
*/
|
*/
|
||||||
static async SendTextMessage(
|
static async SendTextMessage(room: Room, content: string): Promise<void> {
|
||||||
room: Room,
|
|
||||||
content: string,
|
|
||||||
in_reply_to?: string | undefined,
|
|
||||||
): Promise<void> {
|
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
uri: `/matrix/room/${room.id}/send_text_message`,
|
uri: `/matrix/room/${room.id}/send_text_message`,
|
||||||
jsonData: { content, in_reply_to },
|
jsonData: { content },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send file message
|
* Send file message
|
||||||
*/
|
*/
|
||||||
static async SendFileMessage(
|
static async SendFileMessage(room: Room, file: Blob): Promise<void> {
|
||||||
room: Room,
|
|
||||||
file: Blob,
|
|
||||||
inReplyTo?: string | undefined,
|
|
||||||
): Promise<void> {
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.set("file", file);
|
formData.set("file", file);
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
uri:
|
uri: `/matrix/room/${room.id}/send_file`,
|
||||||
`/matrix/room/${room.id}/send_file?` +
|
|
||||||
(inReplyTo ? `in_reply_to=${inReplyTo}` : ""),
|
|
||||||
formData,
|
formData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import AddReactionIcon from "@mui/icons-material/AddReaction";
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import DownloadIcon from "@mui/icons-material/Download";
|
import DownloadIcon from "@mui/icons-material/Download";
|
||||||
import EditIcon from "@mui/icons-material/Edit";
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
import ReplyIcon from "@mui/icons-material/Reply";
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@@ -41,7 +40,6 @@ export function RoomMessagesList(p: {
|
|||||||
room: Room;
|
room: Room;
|
||||||
users: UsersMap;
|
users: UsersMap;
|
||||||
manager: RoomEventsManager;
|
manager: RoomEventsManager;
|
||||||
onRequestReplyToMessage: (evt: Message) => void;
|
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ export function RoomMessagesList(p: {
|
|||||||
try {
|
try {
|
||||||
const older = await MatrixApiEvent.GetRoomEvents(
|
const older = await MatrixApiEvent.GetRoomEvents(
|
||||||
p.room,
|
p.room,
|
||||||
p.manager.endToken,
|
p.manager.endToken
|
||||||
);
|
);
|
||||||
p.manager.processNewEvents(older);
|
p.manager.processNewEvents(older);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -178,7 +176,6 @@ export function RoomMessagesList(p: {
|
|||||||
p.manager.messages.find((s) => s.event_id === m.inReplyTo)) ||
|
p.manager.messages.find((s) => s.event_id === m.inReplyTo)) ||
|
||||||
undefined
|
undefined
|
||||||
}
|
}
|
||||||
onRequestReplyToMessage={() => p.onRequestReplyToMessage(m)}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
@@ -195,7 +192,6 @@ function RoomMessage(p: {
|
|||||||
firstMessageOfDay: boolean;
|
firstMessageOfDay: boolean;
|
||||||
receipts?: Receipt[];
|
receipts?: Receipt[];
|
||||||
repliedMessage?: Message;
|
repliedMessage?: Message;
|
||||||
onRequestReplyToMessage: () => void;
|
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const user = useUserInfo();
|
const user = useUserInfo();
|
||||||
@@ -235,7 +231,7 @@ function RoomMessage(p: {
|
|||||||
await MatrixApiEvent.SetTextMessageContent(
|
await MatrixApiEvent.SetTextMessageContent(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
editMessage!,
|
editMessage!
|
||||||
);
|
);
|
||||||
setEditMessage(undefined);
|
setEditMessage(undefined);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -263,7 +259,7 @@ function RoomMessage(p: {
|
|||||||
|
|
||||||
const handleToggleReaction = async (
|
const handleToggleReaction = async (
|
||||||
key: string,
|
key: string,
|
||||||
reaction: MessageReaction | undefined,
|
reaction: MessageReaction | undefined
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
if (!reaction)
|
if (!reaction)
|
||||||
@@ -343,7 +339,7 @@ function RoomMessage(p: {
|
|||||||
{p.repliedMessage && repliedMsgSender && (
|
{p.repliedMessage && repliedMsgSender && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "inline-flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
borderLeft: "1px red solid",
|
borderLeft: "1px red solid",
|
||||||
paddingLeft: "10px",
|
paddingLeft: "10px",
|
||||||
@@ -364,7 +360,7 @@ function RoomMessage(p: {
|
|||||||
src={MatrixApiEvent.GetEventFileURL(
|
src={MatrixApiEvent.GetEventFileURL(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
true,
|
true
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
maxWidth: "200px",
|
maxWidth: "200px",
|
||||||
@@ -379,7 +375,7 @@ function RoomMessage(p: {
|
|||||||
src={MatrixApiEvent.GetEventFileURL(
|
src={MatrixApiEvent.GetEventFileURL(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
false,
|
false
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</audio>
|
</audio>
|
||||||
@@ -392,7 +388,7 @@ function RoomMessage(p: {
|
|||||||
src={MatrixApiEvent.GetEventFileURL(
|
src={MatrixApiEvent.GetEventFileURL(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
false,
|
false
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</video>
|
</video>
|
||||||
@@ -404,7 +400,7 @@ function RoomMessage(p: {
|
|||||||
href={MatrixApiEvent.GetEventFileURL(
|
href={MatrixApiEvent.GetEventFileURL(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
false,
|
false
|
||||||
)}
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener"
|
rel="noopener"
|
||||||
@@ -462,10 +458,6 @@ function RoomMessage(p: {
|
|||||||
<Button onClick={handleAddReaction}>
|
<Button onClick={handleAddReaction}>
|
||||||
<AddReactionIcon />
|
<AddReactionIcon />
|
||||||
</Button>
|
</Button>
|
||||||
{/* Reply to message */}
|
|
||||||
<Button onClick={p.onRequestReplyToMessage}>
|
|
||||||
<ReplyIcon />
|
|
||||||
</Button>
|
|
||||||
{/* Edit text message */}
|
{/* Edit text message */}
|
||||||
{p.message.account === user.info.matrix_user_id &&
|
{p.message.account === user.info.matrix_user_id &&
|
||||||
!p.message.file && (
|
!p.message.file && (
|
||||||
@@ -487,7 +479,7 @@ function RoomMessage(p: {
|
|||||||
{[...p.message.reactions.keys()].map((r) => {
|
{[...p.message.reactions.keys()].map((r) => {
|
||||||
const reactions = p.message.reactions.get(r)!;
|
const reactions = p.message.reactions.get(r)!;
|
||||||
const userReaction = reactions.find(
|
const userReaction = reactions.find(
|
||||||
(r) => r.account === user.info.matrix_user_id,
|
(r) => r.account === user.info.matrix_user_id
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@@ -545,7 +537,7 @@ function RoomMessage(p: {
|
|||||||
src={MatrixApiEvent.GetEventFileURL(
|
src={MatrixApiEvent.GetEventFileURL(
|
||||||
p.room,
|
p.room,
|
||||||
p.message.event_id,
|
p.message.event_id,
|
||||||
false,
|
false
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -615,7 +607,7 @@ function ReactionButton(p: {
|
|||||||
p.message.reactions
|
p.message.reactions
|
||||||
.get(p.emojiKey)
|
.get(p.emojiKey)
|
||||||
?.find(
|
?.find(
|
||||||
(r) => r.key === p.emojiKey && r.account === user.info.matrix_user_id,
|
(r) => r.key === p.emojiKey && r.account === user.info.matrix_user_id
|
||||||
) !== undefined
|
) !== undefined
|
||||||
)
|
)
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
|||||||
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
|
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
|
||||||
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
||||||
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
||||||
import { type Message, RoomEventsManager } from "../../utils/RoomEventsManager";
|
import { RoomEventsManager } from "../../utils/RoomEventsManager";
|
||||||
import { RoomMessagesList } from "./RoomMessagesList";
|
import { RoomMessagesList } from "./RoomMessagesList";
|
||||||
import { SendMessageForm } from "./SendMessageForm";
|
import { SendMessageForm } from "./SendMessageForm";
|
||||||
import { TypingNotice } from "./TypingNotice";
|
import { TypingNotice } from "./TypingNotice";
|
||||||
@@ -17,10 +17,6 @@ export function RoomWidget(p: {
|
|||||||
|
|
||||||
const receiptId = React.useRef<string | undefined>(undefined);
|
const receiptId = React.useRef<string | undefined>(undefined);
|
||||||
|
|
||||||
const [currMessageReply, setCurrMessageReply] = React.useState<
|
|
||||||
Message | undefined
|
|
||||||
>();
|
|
||||||
|
|
||||||
const handleRoomClick = async () => {
|
const handleRoomClick = async () => {
|
||||||
if (p.manager.messages.length === 0) return;
|
if (p.manager.messages.length === 0) return;
|
||||||
const latest = p.manager.messages[p.manager.messages.length - 1];
|
const latest = p.manager.messages[p.manager.messages.length - 1];
|
||||||
@@ -40,13 +36,9 @@ export function RoomWidget(p: {
|
|||||||
style={{ display: "flex", flexDirection: "column", flex: 1 }}
|
style={{ display: "flex", flexDirection: "column", flex: 1 }}
|
||||||
onClick={handleRoomClick}
|
onClick={handleRoomClick}
|
||||||
>
|
>
|
||||||
<RoomMessagesList {...p} onRequestReplyToMessage={setCurrMessageReply} />
|
<RoomMessagesList {...p} />
|
||||||
<TypingNotice {...p} />
|
<TypingNotice {...p} />
|
||||||
<SendMessageForm
|
<SendMessageForm {...p} />
|
||||||
{...p}
|
|
||||||
currMessageReply={currMessageReply}
|
|
||||||
setCurrReplyToMessage={setCurrMessageReply}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,21 @@
|
|||||||
import AddReactionIcon from "@mui/icons-material/AddReaction";
|
|
||||||
import AttachFileIcon from "@mui/icons-material/AttachFile";
|
import AttachFileIcon from "@mui/icons-material/AttachFile";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
|
||||||
import ReplyIcon from "@mui/icons-material/Reply";
|
|
||||||
import SendIcon from "@mui/icons-material/Send";
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
import {
|
import { IconButton, TextField, Tooltip } from "@mui/material";
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
IconButton,
|
|
||||||
Paper,
|
|
||||||
TextField,
|
|
||||||
Tooltip,
|
|
||||||
} from "@mui/material";
|
|
||||||
import EmojiPicker, { EmojiStyle, Theme } from "emoji-picker-react";
|
|
||||||
import React, { type SyntheticEvent } from "react";
|
import React, { type SyntheticEvent } from "react";
|
||||||
import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
||||||
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
||||||
import { ServerApi } from "../../api/ServerApi";
|
|
||||||
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
|
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
|
||||||
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
|
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
|
||||||
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
|
||||||
import { selectFileToUpload } from "../../utils/FilesUtils";
|
import { selectFileToUpload } from "../../utils/FilesUtils";
|
||||||
import type { Message } from "../../utils/RoomEventsManager";
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
|
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
||||||
|
|
||||||
export function SendMessageForm(p: {
|
export function SendMessageForm(p: { room: Room }): React.ReactElement {
|
||||||
room: Room;
|
|
||||||
currMessageReply?: Message;
|
|
||||||
setCurrReplyToMessage: (msg: Message | undefined) => void;
|
|
||||||
}): React.ReactElement {
|
|
||||||
const loadingMessage = useLoadingMessage();
|
const loadingMessage = useLoadingMessage();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const snackbar = useSnackbar();
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
const [text, setText] = React.useState("");
|
const [text, setText] = React.useState("");
|
||||||
const [pickReaction, setPickReaction] = React.useState(false);
|
|
||||||
|
|
||||||
const handleTextSubmit = async (e: SyntheticEvent) => {
|
const handleTextSubmit = async (e: SyntheticEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -42,15 +25,9 @@ export function SendMessageForm(p: {
|
|||||||
loadingMessage.show("Sending message...");
|
loadingMessage.show("Sending message...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await MatrixApiEvent.SendTextMessage(
|
await MatrixApiEvent.SendTextMessage(p.room, text);
|
||||||
p.room,
|
|
||||||
text,
|
|
||||||
p.currMessageReply?.event_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
setText("");
|
setText("");
|
||||||
|
|
||||||
p.setCurrReplyToMessage(undefined);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Failed to send message! ${e}`);
|
console.error(`Failed to send message! ${e}`);
|
||||||
alert(`Failed to send message! ${e}`);
|
alert(`Failed to send message! ${e}`);
|
||||||
@@ -59,13 +36,6 @@ export function SendMessageForm(p: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddReaction = () => setPickReaction(true);
|
|
||||||
const handleCancelAddReaction = () => setPickReaction(false);
|
|
||||||
const handleSelectEmoji = async (key: string) => {
|
|
||||||
setText((t) => t + key);
|
|
||||||
setPickReaction(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFileSubmit = async () => {
|
const handleFileSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const file = await selectFileToUpload({
|
const file = await selectFileToUpload({
|
||||||
@@ -75,15 +45,9 @@ export function SendMessageForm(p: {
|
|||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
loadingMessage.show("Uploading file...");
|
loadingMessage.show("Uploading file...");
|
||||||
await MatrixApiEvent.SendFileMessage(
|
await MatrixApiEvent.SendFileMessage(p.room, file);
|
||||||
p.room,
|
|
||||||
file,
|
|
||||||
p.currMessageReply?.event_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
snackbar("The file was successfully uploaded!");
|
snackbar("The file was successfully uploaded!");
|
||||||
|
|
||||||
p.setCurrReplyToMessage(undefined);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
alert(`Failed to upload file! ${e}`);
|
alert(`Failed to upload file! ${e}`);
|
||||||
@@ -94,31 +58,6 @@ export function SendMessageForm(p: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleTextSubmit}>
|
<form onSubmit={handleTextSubmit}>
|
||||||
{/* Show replied message content */}
|
|
||||||
{p.currMessageReply && (
|
|
||||||
<Paper
|
|
||||||
variant="outlined"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
padding: "5px 10px",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ReplyIcon />
|
|
||||||
<span style={{ flex: 1, marginLeft: "10px" }}>
|
|
||||||
{p.currMessageReply.content}
|
|
||||||
</span>
|
|
||||||
<Button
|
|
||||||
size="large"
|
|
||||||
onClick={() => p.setCurrReplyToMessage(undefined)}
|
|
||||||
>
|
|
||||||
<CloseIcon fontSize="inherit" />
|
|
||||||
</Button>
|
|
||||||
</Paper>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Input form */}
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "10px",
|
padding: "10px",
|
||||||
@@ -137,12 +76,6 @@ export function SendMessageForm(p: {
|
|||||||
onChange={(e) => setText(e.target.value)}
|
onChange={(e) => setText(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: "10px" }}></span>
|
<span style={{ width: "10px" }}></span>
|
||||||
<Tooltip title="Add a reaction">
|
|
||||||
<IconButton size="small" onClick={handleAddReaction}>
|
|
||||||
<AddReactionIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<span style={{ width: "10px" }}></span>
|
|
||||||
<Tooltip title="Send a file">
|
<Tooltip title="Send a file">
|
||||||
<IconButton size="small" onClick={handleFileSubmit}>
|
<IconButton size="small" onClick={handleFileSubmit}>
|
||||||
<AttachFileIcon />
|
<AttachFileIcon />
|
||||||
@@ -157,15 +90,6 @@ export function SendMessageForm(p: {
|
|||||||
<SendIcon />
|
<SendIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Pick reaction dialog */}
|
|
||||||
<Dialog open={pickReaction} onClose={handleCancelAddReaction}>
|
|
||||||
<EmojiPicker
|
|
||||||
emojiStyle={EmojiStyle.NATIVE}
|
|
||||||
theme={Theme.AUTO}
|
|
||||||
onEmojiClick={(emoji) => handleSelectEmoji(emoji.emoji)}
|
|
||||||
/>
|
|
||||||
</Dialog>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user