From 7a59ec3f8c0854f13ddd2a508d7cbbc4bfb44f20 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 27 May 2023 23:47:51 +0200 Subject: [PATCH] GH-29: Minor improvements - User comments are now shown in profile cards - Empty user comment images are now animated - replaced join channel with change user state --- .gitignore | 3 +- src-tauri/src/commands/mod.rs | 25 ++++++--------- src-tauri/src/connection/mod.rs | 31 ------------------- src-tauri/src/main.rs | 6 ++-- src-tauri/src/manager/user.rs | 2 +- .../src/utils/audio/audio_device_manager.rs | 29 +++++++++++++++++ src-tauri/src/utils/audio/mod.rs | 1 + src-tauri/src/utils/audio/player.rs | 1 - src/components/ChannelSearch.tsx | 3 +- src/components/ChannelViewer.tsx | 2 +- src/components/CurrentUserInfo.tsx | 4 ++- src/components/UserInfo.tsx | 16 ++++++---- src/components/settings/Audio.tsx | 19 ++++++++++++ src/components/styles/CurrentUserInfo.css | 4 +-- src/components/styles/UserInfo.css | 5 +++ src/components/styles/common.css | 17 ++++++++++ src/helper/ChatMessage.ts | 2 +- src/helper/UserInfoHelper.ts | 12 ++++++- src/routes/Settings.tsx | 3 +- src/store/features/users/userSlice.ts | 2 +- 20 files changed, 119 insertions(+), 68 deletions(-) create mode 100644 src-tauri/src/utils/audio/audio_device_manager.rs create mode 100644 src/components/settings/Audio.tsx create mode 100644 src/components/styles/common.css diff --git a/.gitignore b/.gitignore index c3474bc..a22c351 100644 --- a/.gitignore +++ b/.gitignore @@ -106,4 +106,5 @@ dist-ssr *.sw? src-tauri/data -src-tauri/src/proto/Mumble.proto \ No newline at end of file +src-tauri/src/proto/Mumble.proto +src-tauri/gen \ No newline at end of file diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index d19dc21..e7c54b7 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -130,21 +130,6 @@ pub async fn like_message( Ok(()) } -#[tauri::command] -pub async fn join_channel( - channel_id: u32, - state: State<'_, ConnectionState>, -) -> Result<(), String> { - let guard = state.connection.lock().await; - if let Some(guard) = guard.as_ref() { - if let Err(e) = guard.join_channel(channel_id) { - return Err(format!("{e:?}")); - } - } - - Ok(()) -} - #[tauri::command] pub async fn set_user_image( image_path: &str, @@ -180,3 +165,13 @@ pub async fn change_user_state( Ok(()) } + +#[tauri::command] +pub async fn get_audio_devices(state: State<'_, ConnectionState>) -> Result, String> { + let connection = &state.connection; + let guard = connection.lock().await; + + if let Some(guard) = guard.as_ref() {} + + Err("Failed to get audio devices".to_string()) +} diff --git a/src-tauri/src/connection/mod.rs b/src-tauri/src/connection/mod.rs index d479a14..a62f392 100644 --- a/src-tauri/src/connection/mod.rs +++ b/src-tauri/src/connection/mod.rs @@ -201,37 +201,6 @@ impl Connection { Ok(()) } - pub fn join_channel(&self, channel_id: u32) -> AnyError<()> { - let join_channel = mumble::proto::UserState { - session: None, - actor: None, - name: None, - user_id: None, - channel_id: Some(channel_id), - mute: None, - deaf: None, - suppress: None, - self_mute: None, - self_deaf: None, - texture: None, - plugin_context: None, - plugin_identity: None, - comment: None, - hash: None, - comment_hash: None, - texture_hash: None, - priority_speaker: None, - recording: None, - temporary_access_tokens: Vec::new(), - listening_channel_add: Vec::new(), - listening_channel_remove: Vec::new(), - listening_volume_adjustment: Vec::new(), - }; - self.tx_out.send(message_builder(&join_channel))?; - - Ok(()) - } - pub fn update_user_info(&self, user: &mut UpdateableUserState) -> AnyError<()> { let updated_state = mumble::proto::UserState { session: None, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 27c5b94..53d52f2 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -24,7 +24,7 @@ use tracing::Level; use tracing_subscriber::fmt; use crate::commands::{ - change_user_state, connect_to_server, join_channel, like_message, logout, send_message, + change_user_state, connect_to_server, get_audio_devices, like_message, logout, send_message, set_user_image, }; @@ -61,9 +61,9 @@ fn main() { send_message, logout, like_message, - join_channel, set_user_image, - change_user_state + change_user_state, + get_audio_devices ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/manager/user.rs b/src-tauri/src/manager/user.rs index 2334232..7d2149a 100644 --- a/src-tauri/src/manager/user.rs +++ b/src-tauri/src/manager/user.rs @@ -48,7 +48,7 @@ pub struct User { #[allow(clippy::struct_excessive_bools)] #[derive(Debug, Default, Serialize, Deserialize)] pub struct UpdateableUserState { - pub id: u32, + pub id: Option, pub name: Option, pub channel_id: Option, pub mute: Option, diff --git a/src-tauri/src/utils/audio/audio_device_manager.rs b/src-tauri/src/utils/audio/audio_device_manager.rs new file mode 100644 index 0000000..725f653 --- /dev/null +++ b/src-tauri/src/utils/audio/audio_device_manager.rs @@ -0,0 +1,29 @@ +use std::collections::HashMap; + +use rodio::{ + cpal::{self, traits::HostTrait}, + Device, +}; + +use crate::errors::AnyError; + +struct AudioDeviceManager { + pub audio_device: Option, + pub audio_device_list: HashMap, +} + +impl AudioDeviceManager { + pub fn new() -> Self { + Self { + audio_device: None, + audio_device_list: HashMap::new(), + } + } + + pub fn get_audio_device(&self) -> AnyError> { + let host = cpal::default_host(); + let devices = host.input_devices()?; + + Ok(devices.collect()) + } +} diff --git a/src-tauri/src/utils/audio/mod.rs b/src-tauri/src/utils/audio/mod.rs index cc35269..93040e8 100644 --- a/src-tauri/src/utils/audio/mod.rs +++ b/src-tauri/src/utils/audio/mod.rs @@ -1,3 +1,4 @@ +pub mod audio_device_manager; pub mod decoder; pub mod player; pub mod recorder; diff --git a/src-tauri/src/utils/audio/player.rs b/src-tauri/src/utils/audio/player.rs index d86cd47..75e3e14 100644 --- a/src-tauri/src/utils/audio/player.rs +++ b/src-tauri/src/utils/audio/player.rs @@ -33,7 +33,6 @@ impl Player { pub fn start(&mut self) -> AnyError<()> { if self.playing.swap(true, Ordering::Relaxed) || self.audio_thread.is_some() { - error!("Audio thread already started"); return Err("Audio thread already started".into()); } diff --git a/src/components/ChannelSearch.tsx b/src/components/ChannelSearch.tsx index ff25995..4c1af7a 100644 --- a/src/components/ChannelSearch.tsx +++ b/src/components/ChannelSearch.tsx @@ -3,7 +3,6 @@ import SearchIcon from '@mui/icons-material/Search'; import React from "react"; import { useSelector } from "react-redux"; import { RootState } from "../store/store"; -import { getChannelImageFromDescription } from "../helper/ChannelInfoHelper"; import { invoke } from "@tauri-apps/api"; import './styles/ChannelSearch.css'; import Fuse from 'fuse.js'; @@ -46,7 +45,7 @@ function ChannelSearch() { const joinChannel = (channelId: number) => (event: any) => { event?.stopPropagation(); - invoke('join_channel', { channelId: channelId }); + invoke('change_user_state', { userState: { channel_id: channelId }}); } diff --git a/src/components/ChannelViewer.tsx b/src/components/ChannelViewer.tsx index d256fb9..eab84ee 100644 --- a/src/components/ChannelViewer.tsx +++ b/src/components/ChannelViewer.tsx @@ -34,7 +34,7 @@ function ChannelViewer() { } function joinChannel(channelId: number) { - invoke('join_channel', { channelId: channelId }); + invoke('change_user_state', { userState: { channel_id: channelId }}); } function displayUserInfo(user: UsersState): ReactNode { diff --git a/src/components/CurrentUserInfo.tsx b/src/components/CurrentUserInfo.tsx index 8286995..9fc6d87 100644 --- a/src/components/CurrentUserInfo.tsx +++ b/src/components/CurrentUserInfo.tsx @@ -10,6 +10,7 @@ import MicOffIcon from '@mui/icons-material/MicOff'; import './styles/CurrentUserInfo.css' import { invoke } from "@tauri-apps/api"; import { UpdateableUserState, UsersState, updateUser, updateUserFromUpdateable } from "../store/features/users/userSlice"; +import "./styles/common.css" function CurrentUserInfo() { const dispatch = useDispatch(); @@ -58,7 +59,8 @@ function CurrentUserInfo() { display: 'flex', padding: '0 10px', backgroundSize: 'cover', - }}> + }} + className={userBackground ? "" : "animated-background"}> state.reducer.userInfo.currentUser); const background = getBackgroundFromComment(props.userInfo, false); + const profileText = getTextFromcomment(props.userInfo); const [chatMessage, setChatMessage] = useState(""); const dispatch = useDispatch(); @@ -28,7 +29,7 @@ function UserInfo(props: UserInfoProps) { let deafenedText = props.userInfo?.deafenedSince ? dayjs(props.userInfo?.deafenedSince).fromNow() : ''; function generateCardMedia() { - if (!background.startsWith("#")) { + if (background) { return ( + ); } } @@ -57,7 +58,7 @@ function UserInfo(props: UserInfoProps) { function keyDownHandler(e: React.KeyboardEvent) { if (e && e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); - chatMessageHandler.sendPrivateMessage(chatMessage, currentUser, props.userInfo?.id || 0); + chatMessageHandler.sendPrivateMessage(chatMessage, props.userInfo?.id || 0); } } @@ -97,6 +98,10 @@ function UserInfo(props: UserInfoProps) { {showStatusBox("Muted", mutedText)} {showStatusBox("Deafened", deafenedText)} + + + + setChatMessage(e.target.value)} onKeyDown={keyDownHandler} value={chatMessage} - multiline /> diff --git a/src/components/settings/Audio.tsx b/src/components/settings/Audio.tsx new file mode 100644 index 0000000..516202c --- /dev/null +++ b/src/components/settings/Audio.tsx @@ -0,0 +1,19 @@ +import { Container, Typography } from "@mui/material"; +import { invoke } from "@tauri-apps/api"; + +function AudioSettings() { + function getAudioDevices() { + invoke('get_audio_devices') + .then((devices: any) => { + console.log(devices); + }) + } + + return ( + + Audio + + ) +} + +export default AudioSettings; \ No newline at end of file diff --git a/src/components/styles/CurrentUserInfo.css b/src/components/styles/CurrentUserInfo.css index 8cb2ffd..5b28e2a 100644 --- a/src/components/styles/CurrentUserInfo.css +++ b/src/components/styles/CurrentUserInfo.css @@ -1,3 +1,3 @@ .small_icon { - transform: scale(0.7); - } \ No newline at end of file + transform: scale(0.7); +} \ No newline at end of file diff --git a/src/components/styles/UserInfo.css b/src/components/styles/UserInfo.css index 4ce0261..fc6a22b 100644 --- a/src/components/styles/UserInfo.css +++ b/src/components/styles/UserInfo.css @@ -15,4 +15,9 @@ justify-content: space-between; align-items: center; margin: 5px 0; +} + +.user-profile-content { + max-height: 200px; + overflow: auto; } \ No newline at end of file diff --git a/src/components/styles/common.css b/src/components/styles/common.css new file mode 100644 index 0000000..0adb7c3 --- /dev/null +++ b/src/components/styles/common.css @@ -0,0 +1,17 @@ +.animated-background { + animation: gradient 40s ease infinite; + background: linear-gradient(137.42deg, #BF247A 0%, #812B8C 25%, #2A2359 50%, #D9731A 75%, #BF3939 100%); + background-size: 300% 300% !important; + } + + @keyframes gradient { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } + } \ No newline at end of file diff --git a/src/helper/ChatMessage.ts b/src/helper/ChatMessage.ts index 183a771..4a70997 100644 --- a/src/helper/ChatMessage.ts +++ b/src/helper/ChatMessage.ts @@ -32,7 +32,7 @@ export class ChatMessageHandler { this.setChatMessage(""); } - public sendPrivateMessage(data: string, userInfo: UsersState | undefined, reciever: number) { + public sendPrivateMessage(data: string, reciever: number) { invoke('send_message', { chatMessage: data, reciever: reciever }); this.setChatMessage(""); } diff --git a/src/helper/UserInfoHelper.ts b/src/helper/UserInfoHelper.ts index 1e32cde..3ba2162 100644 --- a/src/helper/UserInfoHelper.ts +++ b/src/helper/UserInfoHelper.ts @@ -4,7 +4,7 @@ import { useSelector } from "react-redux"; import { RootState } from "../store/store"; export function getBackgroundFromComment(user: UsersState | undefined, withUrl: boolean = true) { - let defaultColor = "#0057b7"; + let defaultColor = undefined; if (!user || !user.comment) { return defaultColor; @@ -23,6 +23,16 @@ export function getBackgroundFromComment(user: UsersState | undefined, withUrl: } +export function getTextFromcomment(user: UsersState | undefined) { + if (!user || !user.comment) { + return ""; + } + + let cleanMessage = DOMPurify.sanitize(user.comment, {ALLOWED_TAGS: ['b', 'ul', 'li', 'i', 'br', 'span', 'div', 'p']}); + + return cleanMessage; +} + export function getProfileImage(user_id: number) { const userList = useSelector((state: RootState) => state.reducer.userInfo); diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx index 6ebeeb0..ec7fad9 100644 --- a/src/routes/Settings.tsx +++ b/src/routes/Settings.tsx @@ -6,6 +6,7 @@ import PersonIcon from '@mui/icons-material/Person'; import KeyIcon from '@mui/icons-material/Key'; import SecurityIcon from '@mui/icons-material/Security'; import Profile from "../components/settings/Profile"; +import AudioSettings from "../components/settings/Audio"; function Settings() { const navigate = useNavigate(); @@ -63,7 +64,7 @@ function Settings() { - {selectedIndex === 0 &&
Audio
} + {selectedIndex === 0 && } {selectedIndex === 1 && } {selectedIndex === 2 &&
Additional Features
} {selectedIndex === 3 &&
Privacy
} diff --git a/src/store/features/users/userSlice.ts b/src/store/features/users/userSlice.ts index e01b8b5..b663066 100644 --- a/src/store/features/users/userSlice.ts +++ b/src/store/features/users/userSlice.ts @@ -3,7 +3,7 @@ import type { PayloadAction } from '@reduxjs/toolkit' export interface UpdateableUserState { - id: number + id?: number channel_id?: number, comment?: string, deaf?: boolean,