rust_voice_chat_room/client/src/gui.rs

173 lines
5.4 KiB
Rust
Raw Normal View History

use std::sync::{Arc, RwLock};
use iced::{
Alignment::Center,
Element, Task, Theme,
widget::{button, column, row},
};
use protocol::BUFFER_LENGTH;
use tokio::sync::{
broadcast::{self},
oneshot,
};
use crate::{ClientConfig, stream::connect, voice::record};
#[derive(Debug, Default)]
struct Signal {
microphone: Option<oneshot::Sender<bool>>,
// speaker: Option<oneshot::Sender<bool>>,
connection: Option<oneshot::Sender<bool>>,
}
#[derive(Debug)]
struct Channel {
microphone: broadcast::Sender<f32>,
// speaker: (broadcast::Sender<f32>, broadcast::Receiver<f32>),
}
impl Channel {
fn new() -> Self {
Self {
microphone: broadcast::channel(BUFFER_LENGTH).0,
// speaker: broadcast::channel(BUFFER_LENGTH),
}
}
}
#[derive(Debug, Default, Clone, Copy)]
struct GUIStatus {
room: State,
microphone: State,
}
#[derive(Debug, Clone, Copy)]
pub enum State {
Active,
Passive,
Loading,
}
impl Default for State {
fn default() -> Self {
State::Passive
}
}
#[derive(Debug, Clone, Copy)]
pub enum Message {
State,
JoinRoom,
LeaveRoom,
UnmuteMicrophone,
MuteMicrophone,
}
#[derive(Debug)]
pub struct App {
client_config: Arc<ClientConfig>,
gui_status: Arc<RwLock<GUIStatus>>,
channel: Channel,
signal: Signal,
}
impl App {
pub fn theme(&self) -> Theme {
Theme::Dark
}
pub fn new() -> Self {
App {
client_config: ClientConfig::new().into(),
gui_status: RwLock::new(GUIStatus::default()).into(),
channel: Channel::new(),
signal: Signal::default(),
}
}
pub fn view(&self) -> Element<'_, Message> {
let join_room_button = match self.gui_status.read().unwrap().room {
State::Active => button("Leave Room").on_press(Message::LeaveRoom),
State::Passive => button("Join Room").on_press(Message::JoinRoom),
State::Loading => button("Loading"),
};
let microphone_button = match self.gui_status.read().unwrap().microphone {
State::Active => button("Mute").on_press(Message::MuteMicrophone),
State::Passive => button("Unmute").on_press(Message::UnmuteMicrophone),
State::Loading => button("Loading"),
};
column![
row![join_room_button, microphone_button]
.spacing(20)
.align_y(Center)
]
.align_x(Center)
.into()
}
pub fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::State => Task::none(),
Message::JoinRoom => {
self.gui_status.write().unwrap().room = State::Loading;
let client_config = self.client_config.clone();
let gui_status = self.gui_status.clone();
let microphone_receiver = self.channel.microphone.subscribe();
let connection_signal = oneshot::channel();
self.signal.connection = Some(connection_signal.0);
Task::perform(
connect(connection_signal.1, microphone_receiver, client_config),
move |result| match result {
Ok(_) => gui_status.write().unwrap().room = State::Active,
Err(err_val) => {
eprintln!("Error: Join Room | {}", err_val);
gui_status.write().unwrap().room = State::Passive;
}
},
)
.map(|_| Message::State)
}
Message::LeaveRoom => {
self.gui_status.write().unwrap().room = State::Loading;
if let Some(connection_signal) = &self.signal.connection {
if !connection_signal.is_closed() {
self.signal
.connection
.take()
.expect("Never")
.send(true)
.unwrap();
self.signal.connection = None;
self.gui_status.write().unwrap().room = State::Passive;
}
}
Task::none()
}
Message::UnmuteMicrophone => {
self.gui_status.write().unwrap().microphone = State::Active;
let microphone_sender = self.channel.microphone.clone();
let microphone_stop_signal = oneshot::channel();
self.signal.microphone = Some(microphone_stop_signal.0);
Task::perform(record(microphone_sender, microphone_stop_signal.1), |_| {
Message::State
})
}
Message::MuteMicrophone => {
self.gui_status.write().unwrap().microphone = State::Loading;
if let Some(microphone_signal) = &self.signal.microphone {
if !microphone_signal.is_closed() {
self.signal
.microphone
.take()
.expect("Never")
.send(true)
.unwrap();
self.signal.microphone = None;
self.gui_status.write().unwrap().microphone = State::Passive;
}
}
Task::none()
}
}
}
}