Detailed changes
@@ -14,8 +14,8 @@ use rpc::proto;
use std::sync::Arc;
use theme::ActiveTheme;
use ui::{
- h_flex, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon,
- IconButton, IconName, TintColor, Tooltip,
+ h_flex, popover_menu, prelude::*, Avatar, AvatarAudioStatusIndicator, Button, ButtonLike,
+ ButtonStyle, ContextMenu, Icon, IconButton, IconName, TintColor, Tooltip,
};
use util::ResultExt;
use vcs_menu::{build_branch_list, BranchList, OpenRecent as ToggleVcsMenu};
@@ -486,12 +486,16 @@ impl CollabTitlebarItem {
.child(
Avatar::new(user.avatar_uri.clone())
.grayscale(!is_present)
- .border_color(if is_speaking {
- cx.theme().status().info_border
- } else if is_muted {
- cx.theme().status().error_border
- } else {
- Hsla::default()
+ .when(is_speaking, |avatar| {
+ avatar.border_color(cx.theme().status().info_border)
+ })
+ .when(is_muted, |avatar| {
+ avatar.indicator(
+ AvatarAudioStatusIndicator::new(ui::AudioStatus::Muted).tooltip({
+ let github_login = user.github_login.clone();
+ move |cx| Tooltip::text(format!("{} is muted", github_login), cx)
+ }),
+ )
}),
)
.children(followers.iter().filter_map(|follower_peer_id| {
@@ -1,5 +1,7 @@
mod avatar;
+mod avatar_audio_status_indicator;
mod avatar_availability_indicator;
pub use avatar::*;
+pub use avatar_audio_status_indicator::*;
pub use avatar_availability_indicator::*;
@@ -1,4 +1,5 @@
use crate::prelude::*;
+
use gpui::{img, AnyElement, Hsla, ImageSource, Img, IntoElement, Styled};
/// The shape of an [`Avatar`].
@@ -0,0 +1,65 @@
+use gpui::AnyView;
+
+use crate::prelude::*;
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
+pub enum AudioStatus {
+ Muted,
+ Deafened,
+}
+
+#[derive(IntoElement)]
+pub struct AvatarAudioStatusIndicator {
+ audio_status: AudioStatus,
+ tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView>>,
+}
+
+impl AvatarAudioStatusIndicator {
+ pub fn new(audio_status: AudioStatus) -> Self {
+ Self {
+ audio_status,
+ tooltip: None,
+ }
+ }
+
+ pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
+ self.tooltip = Some(Box::new(tooltip));
+ self
+ }
+}
+
+impl RenderOnce for AvatarAudioStatusIndicator {
+ fn render(self, cx: &mut WindowContext) -> impl IntoElement {
+ let icon_size = IconSize::Indicator;
+
+ let width_in_px = icon_size.rems() * cx.rem_size();
+ let padding_x = px(4.);
+
+ div()
+ .absolute()
+ .bottom(rems(-1. / 16.))
+ .right(rems(-4. / 16.))
+ .w(width_in_px + padding_x)
+ .h(icon_size.rems())
+ .child(
+ h_flex()
+ .id("muted-indicator")
+ .justify_center()
+ .px(padding_x)
+ .py(px(2.))
+ .bg(cx.theme().status().error_background)
+ .rounded_md()
+ .child(
+ Icon::new(match self.audio_status {
+ AudioStatus::Muted => IconName::MicMute,
+ AudioStatus::Deafened => IconName::AudioOff,
+ })
+ .size(icon_size)
+ .color(Color::Error),
+ )
+ .when_some(self.tooltip, |this, tooltip| {
+ this.tooltip(move |cx| tooltip(cx))
+ }),
+ )
+ }
+}
@@ -5,6 +5,7 @@ use crate::prelude::*;
#[derive(Default, PartialEq, Copy, Clone)]
pub enum IconSize {
+ Indicator,
XSmall,
Small,
#[default]
@@ -14,6 +15,7 @@ pub enum IconSize {
impl IconSize {
pub fn rems(self) -> Rems {
match self {
+ IconSize::Indicator => rems(10. / 16.),
IconSize::XSmall => rems(12. / 16.),
IconSize::Small => rems(14. / 16.),
IconSize::Medium => rems(16. / 16.),
@@ -1,8 +1,8 @@
use gpui::Render;
use story::Story;
-use crate::Avatar;
-use crate::{prelude::*, Availability, AvatarAvailabilityIndicator};
+use crate::{prelude::*, AudioStatus, Availability, AvatarAvailabilityIndicator};
+use crate::{Avatar, AvatarAudioStatusIndicator};
pub struct AvatarStory;
@@ -25,5 +25,13 @@ impl Render for AvatarStory {
Avatar::new("https://avatars.githubusercontent.com/u/326587?v=4")
.indicator(AvatarAvailabilityIndicator::new(Availability::Busy)),
)
+ .child(
+ Avatar::new("https://avatars.githubusercontent.com/u/326587?v=4")
+ .indicator(AvatarAudioStatusIndicator::new(AudioStatus::Muted)),
+ )
+ .child(
+ Avatar::new("https://avatars.githubusercontent.com/u/326587?v=4")
+ .indicator(AvatarAudioStatusIndicator::new(AudioStatus::Deafened)),
+ )
}
}