Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e63fa38
refactored a bit
Jul 22, 2025
160eea1
exclude .swg files (vi)
Jul 22, 2025
1726e5a
tweaks to list repo to key components
Jul 22, 2025
47d1a8a
debug and trace flags for yew-ui
Jul 22, 2025
a8f0165
add git-all image after update
Jul 22, 2025
f7e7ba9
tailwind
Jul 23, 2025
67010ea
relax logging
Jul 23, 2025
20f5df6
concept car title
Jul 23, 2025
e2a9856
show display name at top
Jul 23, 2025
fedccc0
cleanup
Jul 23, 2025
c2d41ab
Merge pull request #1 from labs-projects/p7cc-poc
Jul 23, 2025
06cfb4d
revert --rm containers
Jul 23, 2025
2a0be9d
Merge pull request #2 from labs-projects/p7cc-poc
Jul 23, 2025
305fb02
Merge branch 'main' of github01.hclpnp.com:labs-projects/videocall
Aug 14, 2025
2acf9f1
Merge branch 'main' of github.com:security-union/videocall-rs
Sep 26, 2025
8e67bac
Merge branch 'main' of github.com:security-union/videocall-rs
Oct 21, 2025
fd3f2ed
self shows in the attendee grid
Oct 23, 2025
ea13cfe
remove artificially adding self to peer list since it is already an a…
Oct 23, 2025
85dd07e
Merge branch 'main' of github.com:security-union/videocall-rs into se…
Oct 24, 2025
38e32f5
refactor canvas tile generator
Oct 27, 2025
9e112fb
update host name button on canvas
Oct 28, 2025
9d6647d
edit host name button consistent look on canvas
Oct 28, 2025
dc9e8f0
remove box shadow
Oct 28, 2025
341ea04
remove change host name from host panel
Oct 28, 2025
c3e8e49
style host device controls container
Oct 29, 2025
07e192f
warning unused variable
Oct 31, 2025
40238fb
linted code
Oct 31, 2025
e02e017
Merge branch 'main' into feature/host-video-in-canvas
testradav Oct 31, 2025
3bf8365
Enhance GitHub link and add corner ribbon
testradav Oct 31, 2025
a4e04b2
Apply suggestions from code review
testradav Oct 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ Carthage/Build/
.com.apple.timemachine.donotpresent


deployment-**.log
deployment-**.log
8 changes: 8 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,19 @@ graph TD

## Key Components

- **actix-api:** Rust-based backend server using Actix Web framework
- **videocall-types:** Shared data types and protocol definitions

### 1. Client Applications

- **Web Client**: Built with Yew (Rust-to-WebAssembly framework)
- **`yew-ui`** Web frontend built with the Yew framework and compiled to WebAssembly
- **`tailwind-yew`** css
- **`videocall-client`** Client library for native integration
- **CLI Client**: Native Rust client for headless devices
- **`videocall-cli`** Command-line interface for headless video streaming
- **Mobile Clients**: Native mobile applications (in development)
- **`videocall-sdk`**

### 2. Transport Servers

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ check:

clean:
docker compose -f docker/docker-compose.yaml down --remove-orphans \
--volumes --rmi all
--volumes --rmi all
3 changes: 2 additions & 1 deletion docker/Dockerfile.website
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ RUN apt-get update && apt-get install -y \
libssl-dev \
pkg-config \
g++ \
git-all \
&& rm -rf /var/lib/apt/lists/*

RUN cargo install --locked cargo-leptos@0.2.29
Expand All @@ -34,4 +35,4 @@ ENV LEPTOS_SITE_ADDR="0.0.0.0:8080"
ENV LEPTOS_SITE_ROOT="site"
EXPOSE 8080

CMD ["/app/leptos_website"]
CMD ["/app/leptos_website"]
1 change: 1 addition & 0 deletions docker/Dockerfile.website.dev
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y \
libssl-dev \
pkg-config \
g++ \
git-all \
&& rm -rf /var/lib/apt/lists/*

RUN cargo install --locked cargo-leptos@0.2.29
Expand Down
1 change: 1 addition & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ services:
- LOGIN_URL=http://localhost:${ACTIX_PORT:-8080}/login
- RUSTFLAGS=--cfg=web_sys_unstable_apis
- RUST_BACKTRACE=1
- RUST_LOG=debug
- WEBTRANSPORT_ENABLED=${WEBTRANSPORT_ENABLED:-false}
- E2EE_ENABLED=${E2EE_ENABLED:-false}
- USERS_ALLOWED_TO_STREAM=${USERS_ALLOWED_TO_STREAM:-}
Expand Down
100 changes: 68 additions & 32 deletions yew-ui/src/components/attendants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub enum Msg {
ToggleForceDesktopGrid,
HangUp,
ShowCopyToast(bool),
RegisterHostToggleName(Callback<MouseEvent>),
}

impl From<WsAction> for Msg {
Expand Down Expand Up @@ -145,6 +146,7 @@ pub struct AttendantsComponent {
force_desktop_grid_on_mobile: bool,
simulation_info_message: Option<String>,
show_copy_toast: bool,
host_toggle_change_name: Option<Callback<MouseEvent>>,
show_dropdown: bool,
}

Expand Down Expand Up @@ -357,6 +359,7 @@ impl Component for AttendantsComponent {
force_desktop_grid_on_mobile: true,
simulation_info_message: None,
show_copy_toast: false,
host_toggle_change_name: None,
show_dropdown: false,
};
if let Err(e) = crate::constants::app_config() {
Expand Down Expand Up @@ -578,6 +581,10 @@ impl Component for AttendantsComponent {
let _ = window().location().reload(); // Refresh page for clean state
true
}
Msg::RegisterHostToggleName(callback) => {
self.host_toggle_change_name = Some(callback);
true
}
}
}

Expand All @@ -593,21 +600,46 @@ impl Component for AttendantsComponent {
let mut display_peers_vec = real_peers_vec.clone();
display_peers_vec.extend(self.fake_peer_ids.iter().cloned());

// // ✅ Ensure host (the current user) appears in the peers list
let my_email = ctx.props().email.clone();
if !display_peers_vec.contains(&my_email) {
// Insert host at the beginning so they appear first in the grid
display_peers_vec.insert(0, my_email.clone() + " (You)");
}

let num_display_peers = display_peers_vec.len();
// Cap the number of peers used for styling at CANVAS_LIMIT
let num_peers_for_styling = num_display_peers.min(CANVAS_LIMIT);

// Determine if the "Add Fake Peer" button should be disabled
let add_fake_peer_disabled = num_display_peers >= CANVAS_LIMIT;

let on_encoder_settings_update = ctx.link().callback(WsAction::EncoderSettingsUpdated);

let rows: Vec<Html> = display_peers_vec
.iter()
.take(CANVAS_LIMIT)
.enumerate()
.map(|(i, peer_id)| {
let full_bleed = display_peers_vec.len() == 1
&& !self.client.is_screen_share_enabled_for_peer(peer_id);
html!{ <PeerTile key={format!("tile-{}-{}", i, peer_id)} peer_id={peer_id.clone()} client={self.client.clone()} full_bleed={full_bleed} /> }
let is_host = peer_id == &(email.clone() + " (You)");
let full_bleed = (display_peers_vec.len() == 1
&& !self.client.is_screen_share_enabled_for_peer(peer_id))
|| num_display_peers == 1;
let on_toggle_change_name = if is_host {
self.host_toggle_change_name.clone()
} else {
None
};
html! {
<PeerTile
key={format!("tile-{}-{}", i, peer_id)}
peer_id={peer_id.clone()}
client={self.client.clone()}
full_bleed={full_bleed}
is_host={is_host}
on_toggle_change_name={on_toggle_change_name}
/>
}
})
.collect();

Expand All @@ -617,8 +649,6 @@ impl Component for AttendantsComponent {
num_peers_for_styling.max(1)
);

let on_encoder_settings_update = ctx.link().callback(WsAction::EncoderSettingsUpdated);

// Compute meeting link for invitation overlay
let meeting_link = {
let origin_result = window().location().origin();
Expand Down Expand Up @@ -777,6 +807,7 @@ impl Component for AttendantsComponent {
<nav class="host">
<div class="controls">
<nav class="video-controls-container">
// Mic mute/unmute button
<button
class={classes!("video-control-button", self.mic_enabled.then_some("active"))}
onclick={ctx.link().callback(|_| MeetingAction::ToggleMicMute)}>
Expand Down Expand Up @@ -807,6 +838,7 @@ impl Component for AttendantsComponent {
}
}
</button>
// Video on/off button
<button
class={classes!("video-control-button", self.video_enabled.then_some("active"))}
onclick={ctx.link().callback(|_| MeetingAction::ToggleVideoOnOff)}>
Expand Down Expand Up @@ -834,8 +866,7 @@ impl Component for AttendantsComponent {
}
}
</button>

// Hide screen share button on Safari/iOS devices
// Screen share button (hide on Safari/iOS devices)
{
if !is_ios() {
html! {
Expand Down Expand Up @@ -874,6 +905,7 @@ impl Component for AttendantsComponent {
html! {}
}
}
// peer list button
<button
class={classes!("video-control-button", self.peer_list_open.then_some("active"))}
onclick={toggle_peer_list.clone()}>
Expand Down Expand Up @@ -906,6 +938,7 @@ impl Component for AttendantsComponent {
}
}
</button>
// diagnostics button
<button
class={classes!("video-control-button", self.diagnostics_open.then_some("active"))}
onclick={toggle_diagnostics.clone()}>
Expand All @@ -932,6 +965,7 @@ impl Component for AttendantsComponent {
}
}
</button>
// device settings button (mobile only)
<button
class={classes!("video-control-button", "mobile-only-device-settings", self.device_settings_open.then_some("active"))}
onclick={ctx.link().callback(|_| UserScreenToggleAction::DeviceSettings)}>
Expand Down Expand Up @@ -959,6 +993,7 @@ impl Component for AttendantsComponent {
}
}
</button>
// hang up button
<button
class="video-control-button danger"
onclick={ctx.link().callback(|_| Msg::HangUp)}>
Expand All @@ -969,18 +1004,17 @@ impl Component for AttendantsComponent {
</button>
{ self.view_grid_toggle(ctx) }
{ self.view_fake_peer_buttons(ctx, add_fake_peer_disabled) }

</nav>
{ html!{} }
{
if let Some(message) = &self.simulation_info_message {
html!{
<p class="simulation-info-message">{ message }</p>
}
} else {
html!{}
}
}
{
if let Some(message) = &self.simulation_info_message {
html!{
<p class="simulation-info-message">{ message }</p>
}
} else {
html!{}
}
}
</div>
{
if let Some(err) = &self.mic_error {
Expand All @@ -1001,23 +1035,25 @@ impl Component for AttendantsComponent {
} else { html!{} }
}
{
if media_access_granted {
html! {<Host
client={self.client.clone()}
share_screen={self.share_screen}
mic_enabled={self.mic_enabled}
video_enabled={self.video_enabled}
on_encoder_settings_update={on_encoder_settings_update}
device_settings_open={self.device_settings_open}
on_device_settings_toggle={ctx.link().callback(|_| UserScreenToggleAction::DeviceSettings)}
on_microphone_error={ctx.link().callback(Msg::OnMicrophoneError)}
/>}
} else {
html! {<></>}
}
if media_access_granted {
html! {
<Host
client={self.client.clone()}
share_screen={self.share_screen}
mic_enabled={self.mic_enabled}
video_enabled={self.video_enabled}
on_encoder_settings_update={on_encoder_settings_update}
device_settings_open={self.device_settings_open}
on_device_settings_toggle={ctx.link().callback(|_| UserScreenToggleAction::DeviceSettings)}
on_microphone_error={ctx.link().callback(Msg::OnMicrophoneError)}
register_toggle_change_name={ctx.link().callback(Msg::RegisterHostToggleName)}
/>
}
} else {
html! {<></>}
}
}
<div class={classes!("connection-led", if self.client.is_connected() { "connected" } else { "connecting" })} title={if self.client.is_connected() { "Connected" } else { "Connecting" }}></div>

</nav>
}
} else {
Expand Down
Loading