use dioxus::prelude::*;
use crate::room::call::call_state::{CallStatus, CallType};
use crate::room::call::element_call::build_element_call_url;
use crate::state::app_state::AppState;
#[component]
pub fn CallButtons(room_id: String) -> Element {
let mut state = use_context::<Signal<AppState>>();
let call_active = state.read().call_state.is_active();
let call_in_this_room = state
.read()
.call_state
.room_id
.as_ref()
.map(|r| r.to_string() == room_id)
.unwrap_or(false);
let rid_voice = room_id.clone();
let rid_video = room_id.clone();
rsx! {
div {
class: "call-buttons",
button {
class: if call_in_this_room { "room-header__action-btn room-header__action-btn--active" } else { "room-header__action-btn" },
title: "Voice call",
disabled: call_active && !call_in_this_room,
onclick: move |_| {
if call_in_this_room {
hang_up_call(&mut state);
} else {
start_call(&mut state, &rid_voice, CallType::Voice);
}
},
"📞"
}
button {
class: if call_in_this_room && state.read().call_state.is_video_enabled {
"room-header__action-btn room-header__action-btn--active"
} else {
"room-header__action-btn"
},
title: "Video call",
disabled: call_active && !call_in_this_room,
onclick: move |_| {
if call_in_this_room {
hang_up_call(&mut state);
} else {
start_call(&mut state, &rid_video, CallType::Video);
}
},
"📹"
}
}
}
}
fn start_call(state: &mut Signal<AppState>, room_id: &str, call_type: CallType) {
if let Ok(rid) = matrix_sdk::ruma::OwnedRoomId::try_from(room_id) {
let call_id = uuid::Uuid::new_v4().to_string();
let is_video = matches!(call_type, CallType::Video);
let widget_url = state
.read()
.client
.as_ref()
.map(|client| build_element_call_url(client, rid.as_ref()));
let mut s = state.write();
s.call_state.status = CallStatus::Connecting;
s.call_state.room_id = Some(rid.clone());
s.call_state.call_type = call_type;
s.call_state.call_id = Some(call_id.clone());
s.call_state.is_video_enabled = is_video;
s.call_state.duration_secs = 0;
s.call_state.is_muted = false;
s.call_state.is_screen_sharing = false;
s.call_state.is_on_hold = false;
s.call_state.is_group_call = true;
s.call_state.widget_url = widget_url;
drop(s);
let client = { state.read().client.clone() };
spawn(async move {
if let Some(client) = client {
if let Some(room) = client.get_room(&rid) {
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
let msg = RoomMessageEventContent::notice_plain(
format!(
"Started a {type_str} call in Element Call",
type_str = if is_video { "video" } else { "voice" }
)
);
if let Err(e) = room.send(msg).await {
tracing::error!("Failed to send call notification: {e}");
}
tracing::info!("Element Call initiated in room {rid}, call_id={call_id}");
}
}
});
}
}
fn hang_up_call(state: &mut Signal<AppState>) {
use crate::room::call::call_state::CallEndReason;
let room_id = state.read().call_state.room_id.clone();
let call_id = state.read().call_state.call_id.clone();
let client = state.read().client.clone();
let mut state_copy = *state;
{
let mut s = state.write();
s.call_state.status = CallStatus::Ended(CallEndReason::HungUp);
s.call_state.is_on_hold = false;
}
if let (Some(rid), Some(_cid)) = (room_id, call_id) {
spawn(async move {
if let Some(client) = client {
if let Some(room) = client.get_room(&rid) {
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
let msg = RoomMessageEventContent::notice_plain("Call ended");
let _ = room.send(msg).await;
}
}
});
}
spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
let mut s = state_copy.write();
s.call_state = Default::default();
});
}