Skip to content

Commit

Permalink
GH-59: Add basic support for private messages
Browse files Browse the repository at this point in the history
  • Loading branch information
SetZero committed May 26, 2023
1 parent feef7f5 commit e0d8079
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 40 deletions.
3 changes: 2 additions & 1 deletion src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ pub async fn connect_to_server(
pub async fn send_message(
chat_message: String,
channel_id: Option<u32>,
reciever: Option<u32>,
state: State<'_, ConnectionState>,
) -> Result<(), String> {
let guard = state.connection.lock().await;
if let Some(guard) = guard.as_ref() {
if let Err(e) = guard.send_message(channel_id, &chat_message) {
if let Err(e) = guard.send_message(channel_id, reciever, &chat_message) {
return Err(format!("{e:?}"));
}
}
Expand Down
9 changes: 8 additions & 1 deletion src-tauri/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct MessageChannels {
pub struct TextMessage {
message: String,
channel_id: Option<u32>,
reciever: Option<u32>,
}

pub struct Connection {
Expand Down Expand Up @@ -133,10 +134,16 @@ impl Connection {
Ok(())
}

pub fn send_message(&self, channel_id: Option<u32>, message: &str) -> AnyError<()> {
pub fn send_message(
&self,
channel_id: Option<u32>,
reciever: Option<u32>,
message: &str,
) -> AnyError<()> {
self.tx_message_channel.send(TextMessage {
message: message.to_string(),
channel_id,
reciever,
})?;

Ok(())
Expand Down
6 changes: 4 additions & 2 deletions src-tauri/src/connection/threads/output_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::atomic::Ordering;
use crate::{connection::Connection, mumble, utils::messages::message_builder};
use tokio::select;
use tokio::time;
use tracing::trace;
use tracing::{debug, error};

use super::{ConnectionThread, OutputThread, DEADMAN_INTERVAL};
Expand All @@ -29,11 +30,12 @@ impl OutputThread for Connection {
debug!("Sending text message to channel: {:?}", result.channel_id);
let message = mumble::proto::TextMessage {
actor: None,
session: Vec::new(),
channel_id: vec![result.channel_id.unwrap_or(0)],
session: result.reciever.iter().copied().collect(),
channel_id: result.channel_id.iter().copied().collect(),
tree_id: Vec::new(),
message: result.message,
};
trace!("Sending message: {:?}", message);
let buffer = message_builder(&message);

if let Err(error) = tx_out.send(buffer) {
Expand Down
24 changes: 22 additions & 2 deletions src/components/UserInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Typography, Popover, Card, Avatar, CardMedia, CardContent, Paper, IconButton, InputBase, Divider, Box } from "@mui/material";
import { UsersState } from "../store/features/users/userSlice";
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { getBackgroundFromComment, getProfileImage } from "../helper/UserInfoHelper";
import SendIcon from '@mui/icons-material/Send';
import "./styles/UserInfo.css";
import dayjs from "dayjs";
import MessageParser from "../helper/MessageParser";
import { ChatMessageHandler } from "../helper/ChatMessage";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../store/store";

interface UserInfoProps {
anchorEl: HTMLElement | null;
Expand All @@ -13,7 +17,12 @@ interface UserInfoProps {
}

function UserInfo(props: UserInfoProps) {
const currentUser = useSelector((state: RootState) => state.reducer.userInfo.currentUser);
const background = getBackgroundFromComment(props.userInfo, false);
const [chatMessage, setChatMessage] = useState("");

const dispatch = useDispatch();
const chatMessageHandler = new ChatMessageHandler(dispatch, setChatMessage);

let mutedText = props.userInfo?.mutedSince ? dayjs(props.userInfo?.mutedSince).fromNow() : '';
let deafenedText = props.userInfo?.deafenedSince ? dayjs(props.userInfo?.deafenedSince).fromNow() : '';
Expand Down Expand Up @@ -45,6 +54,13 @@ function UserInfo(props: UserInfoProps) {
}
}

function keyDownHandler(e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) {
if (e && e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
chatMessageHandler.sendPrivateMessage(chatMessage, currentUser, props.userInfo?.id || 0);
}
}

return (
<Popover
open={Boolean(props.anchorEl)}
Expand Down Expand Up @@ -88,8 +104,12 @@ function UserInfo(props: UserInfoProps) {
>
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder={"Send a message to " + props.userInfo?.name}
placeholder={"write " + props.userInfo?.name + "..."}
inputProps={{ 'aria-label': 'search google maps' }}
onChange={e => setChatMessage(e.target.value)}
onKeyDown={keyDownHandler}
value={chatMessage}
multiline
/>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton color="primary" sx={{ p: '10px' }} aria-label="directions">
Expand Down
48 changes: 48 additions & 0 deletions src/helper/ChatMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { invoke } from "@tauri-apps/api";
import { TextMessage, addChatMessage } from "../store/features/users/chatMessageSlice";
import { UsersState } from "../store/features/users/userSlice";
import MessageParser from "./MessageParser";
import { Dispatch } from "react";
import { AnyAction } from "@reduxjs/toolkit";

export class ChatMessageHandler {

constructor(private dispatch: Dispatch<AnyAction>, private setChatMessage: any) {

}

pushChatMessage(message: TextMessage) {
this.dispatch(addChatMessage(message));
}

public sendCustomChatMessage(data: string, userInfo: UsersState | undefined) {
invoke('send_message', { chatMessage: data, channelId: userInfo?.channel_id });
console.log("customChatMessage", data);
this.pushChatMessage({
actor: userInfo?.id || 0,
sender: {
user_id: userInfo?.id || 0,
user_name: userInfo?.name || 'unknown'
},
channel_id: [0],
tree_id: [0],
message: data,
timestamp: Date.now()
})
this.setChatMessage("");
}

public sendPrivateMessage(data: string, userInfo: UsersState | undefined, reciever: number) {
invoke('send_message', { chatMessage: data, reciever: reciever });
this.setChatMessage("");
}

public sendChatMessage(chatMessage: string, userInfo: UsersState | undefined) {
let message = new MessageParser(chatMessage)
.parseLinks()
.parseCommands()
.parseMarkdown()
.buildString();
this.sendCustomChatMessage(message, userInfo);
}
}
40 changes: 7 additions & 33 deletions src/routes/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useDispatch, useSelector } from 'react-redux';
import { TextMessage, addChatMessage } from '../store/features/users/chatMessageSlice';
import { formatBytes } from '../helper/Fomat';
import MessageParser from '../helper/MessageParser';
import { UserInfoState, UsersState } from '../store/features/users/userSlice';
import { ChatMessageHandler } from '../helper/ChatMessage';

function Chat() {
const [chatMessage, setChatMessage] = useState("");
Expand All @@ -26,40 +28,12 @@ function Chat() {

const currentChannel = channelInfo.find(e => e.channel_id === userInfo.currentUser?.channel_id)?.name;

function pushChatMessage(message: TextMessage) {
dispatch(addChatMessage(message));
}

function customChatMessage(data: string) {
invoke('send_message', { chatMessage: data, channelId: userInfo.currentUser?.channel_id });
console.log("customChatMessage", data);
pushChatMessage({
actor: userInfo.currentUser?.id || 0,
sender: {
user_id: userInfo.currentUser?.id || 0,
user_name: userInfo.currentUser?.name || 'unknown'
},
channel_id: [0],
tree_id: [0],
message: data,
timestamp: Date.now()
})
setChatMessage("");
}

function sendChatMessage(e: any) {
let message = new MessageParser(chatMessage)
.parseLinks()
.parseCommands()
.parseMarkdown()
.buildString();
customChatMessage(message);
}
const chatMessageHandler = new ChatMessageHandler(dispatch, setChatMessage);

function keyDownHandler(e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) {
if (e && e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendChatMessage({});
chatMessageHandler.sendChatMessage(chatMessage, userInfo.currentUser);
}
}

Expand All @@ -81,11 +55,11 @@ function Chat() {
reader.readAsDataURL(file);
reader.onload = function () {
if (reader.result && (reader.result as string).length > 0x7fffff) {
customChatMessage("[[ Image too large ( " + formatBytes((reader.result as string).length) + " out of " + formatBytes(0x7fffff) + ") ]]");
chatMessageHandler.sendCustomChatMessage("[[ Image too large ( " + formatBytes((reader.result as string).length) + " out of " + formatBytes(0x7fffff) + ") ]]", userInfo.currentUser);
return;
}
let img = '<img src="' + reader.result + '" />';
customChatMessage(img);
chatMessageHandler.sendCustomChatMessage(img, userInfo.currentUser);
};
}
}
Expand Down Expand Up @@ -119,7 +93,7 @@ function Chat() {
<GifIcon />
</IconButton>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton sx={{ p: '10px' }} aria-label="Send Message" onClick={sendChatMessage}>
<IconButton sx={{ p: '10px' }} aria-label="Send Message" onClick={() => chatMessageHandler.sendChatMessage(chatMessage, userInfo.currentUser)}>
<SendIcon />
</IconButton>
</Paper>
Expand Down
2 changes: 1 addition & 1 deletion src/store/features/users/userSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface UserDataUpdate {
data: any
}

interface UserInfoState {
export interface UserInfoState {
currentUser: UsersState | undefined,
users: UsersState[],
connected: boolean,
Expand Down

0 comments on commit e0d8079

Please sign in to comment.