Wire up call controls in the `TitleBar`

Marshall Bowers created

Change summary

crates/ui2/src/components/title_bar.rs | 61 +++++++++++++++++++++++++--
crates/ui2/src/elements/player.rs      | 27 ++++++++++++
2 files changed, 83 insertions(+), 5 deletions(-)

Detailed changes

crates/ui2/src/components/title_bar.rs 🔗

@@ -5,8 +5,8 @@ use gpui3::{view, Context, View};
 
 use crate::prelude::*;
 use crate::{
-    random_players_with_call_status, theme, Avatar, Button, Icon, IconButton, IconColor,
-    PlayerStack, PlayerWithCallStatus, ToolDivider, TrafficLights,
+    random_players_with_call_status, theme, Avatar, Button, Icon, IconButton, IconColor, MicStatus,
+    PlayerStack, PlayerWithCallStatus, ScreenShareStatus, ToolDivider, TrafficLights,
 };
 
 #[derive(Clone)]
@@ -21,6 +21,9 @@ pub struct TitleBar {
     /// If the window is active from the OS's perspective.
     is_active: Arc<AtomicBool>,
     livestream: Option<Livestream>,
+    mic_status: MicStatus,
+    is_deafened: bool,
+    screen_share_status: ScreenShareStatus,
 }
 
 impl TitleBar {
@@ -37,6 +40,9 @@ impl TitleBar {
         Self {
             is_active,
             livestream: None,
+            mic_status: MicStatus::Unmuted,
+            is_deafened: false,
+            screen_share_status: ScreenShareStatus::NotShared,
         }
     }
 
@@ -45,6 +51,34 @@ impl TitleBar {
         self
     }
 
+    pub fn is_mic_muted(&self) -> bool {
+        self.mic_status == MicStatus::Muted
+    }
+
+    pub fn toggle_mic_status(&mut self, cx: &mut ViewContext<Self>) {
+        self.mic_status = self.mic_status.inverse();
+
+        // Undeafen yourself when unmuting the mic while deafened.
+        if self.is_deafened && self.mic_status == MicStatus::Unmuted {
+            self.is_deafened = false;
+        }
+
+        cx.notify();
+    }
+
+    pub fn toggle_deafened(&mut self, cx: &mut ViewContext<Self>) {
+        self.is_deafened = !self.is_deafened;
+        self.mic_status = MicStatus::Muted;
+
+        cx.notify()
+    }
+
+    pub fn toggle_screen_share_status(&mut self, cx: &mut ViewContext<Self>) {
+        self.screen_share_status = self.screen_share_status.inverse();
+
+        cx.notify();
+    }
+
     pub fn view(cx: &mut WindowContext) -> View<Self> {
         view(
             cx.entity(|cx| {
@@ -115,9 +149,26 @@ impl TitleBar {
                             .flex()
                             .items_center()
                             .gap_1()
-                            .child(IconButton::new(Icon::Mic))
-                            .child(IconButton::new(Icon::AudioOn))
-                            .child(IconButton::new(Icon::Screen).color(IconColor::Accent)),
+                            .child(
+                                IconButton::<TitleBar>::new(Icon::Mic)
+                                    .when(self.is_mic_muted(), |this| this.color(IconColor::Error))
+                                    .on_click(|title_bar, cx| title_bar.toggle_mic_status(cx)),
+                            )
+                            .child(
+                                IconButton::<TitleBar>::new(Icon::AudioOn)
+                                    .when(self.is_deafened, |this| this.color(IconColor::Error))
+                                    .on_click(|title_bar, cx| title_bar.toggle_deafened(cx)),
+                            )
+                            .child(
+                                IconButton::<TitleBar>::new(Icon::Screen)
+                                    .when(
+                                        self.screen_share_status == ScreenShareStatus::Shared,
+                                        |this| this.color(IconColor::Accent),
+                                    )
+                                    .on_click(|title_bar, cx| {
+                                        title_bar.toggle_screen_share_status(cx)
+                                    }),
+                            ),
                     )
                     .child(
                         div().px_2().flex().items_center().child(

crates/ui2/src/elements/player.rs 🔗

@@ -20,6 +20,15 @@ pub enum MicStatus {
     Unmuted,
 }
 
+impl MicStatus {
+    pub fn inverse(&self) -> Self {
+        match self {
+            Self::Muted => Self::Unmuted,
+            Self::Unmuted => Self::Muted,
+        }
+    }
+}
+
 #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
 pub enum VideoStatus {
     On,
@@ -27,6 +36,15 @@ pub enum VideoStatus {
     Off,
 }
 
+impl VideoStatus {
+    pub fn inverse(&self) -> Self {
+        match self {
+            Self::On => Self::Off,
+            Self::Off => Self::On,
+        }
+    }
+}
+
 #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
 pub enum ScreenShareStatus {
     Shared,
@@ -34,6 +52,15 @@ pub enum ScreenShareStatus {
     NotShared,
 }
 
+impl ScreenShareStatus {
+    pub fn inverse(&self) -> Self {
+        match self {
+            Self::Shared => Self::NotShared,
+            Self::NotShared => Self::Shared,
+        }
+    }
+}
+
 #[derive(Clone)]
 pub struct PlayerCallStatus {
     pub mic_status: MicStatus,