avatar.rs

 1use std::sync::Arc;
 2
 3use crate::prelude::*;
 4use gpui::{img, rems, Div, ImageData, ImageSource, IntoElement, Styled};
 5
 6#[derive(Debug, Default, PartialEq, Clone)]
 7pub enum Shape {
 8    #[default]
 9    Circle,
10    RoundedRectangle,
11}
12
13#[derive(IntoElement)]
14pub struct Avatar {
15    src: ImageSource,
16    is_available: Option<bool>,
17    shape: Shape,
18}
19
20impl RenderOnce for Avatar {
21    type Rendered = Div;
22
23    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
24        let mut img = img();
25
26        if self.shape == Shape::Circle {
27            img = img.rounded_full();
28        } else {
29            img = img.rounded_md();
30        }
31
32        let size = rems(1.0);
33
34        div()
35            .size(size)
36            .child(
37                img.source(self.src.clone())
38                    .size(size)
39                    // todo!(Pull the avatar fallback background from the theme.)
40                    .bg(gpui::red()),
41            )
42            .children(self.is_available.map(|is_free| {
43                // HACK: non-integer sizes result in oval indicators.
44                let indicator_size = (size.0 * cx.rem_size() * 0.4).round();
45
46                div()
47                    .absolute()
48                    .z_index(1)
49                    .bg(if is_free { gpui::green() } else { gpui::red() })
50                    .size(indicator_size)
51                    .rounded(indicator_size)
52                    .bottom_0()
53                    .right_0()
54            }))
55    }
56}
57
58impl Avatar {
59    pub fn uri(src: impl Into<SharedString>) -> Self {
60        Self {
61            src: src.into().into(),
62            shape: Shape::Circle,
63            is_available: None,
64        }
65    }
66    pub fn data(src: Arc<ImageData>) -> Self {
67        Self {
68            src: src.into(),
69            shape: Shape::Circle,
70            is_available: None,
71        }
72    }
73
74    pub fn source(src: ImageSource) -> Self {
75        Self {
76            src,
77            shape: Shape::Circle,
78            is_available: None,
79        }
80    }
81    pub fn shape(mut self, shape: Shape) -> Self {
82        self.shape = shape;
83        self
84    }
85    pub fn availability_indicator(mut self, is_available: impl Into<Option<bool>>) -> Self {
86        self.is_available = is_available.into();
87        self
88    }
89}