88 lines
2.2 KiB
Rust
88 lines
2.2 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::prelude::*;
|
|
use gpui::{img, rems, Div, ImageData, ImageSource, IntoElement, Styled};
|
|
|
|
#[derive(Debug, Default, PartialEq, Clone)]
|
|
pub enum Shape {
|
|
#[default]
|
|
Circle,
|
|
RoundedRectangle,
|
|
}
|
|
|
|
#[derive(IntoElement)]
|
|
pub struct Avatar {
|
|
src: ImageSource,
|
|
is_available: Option<bool>,
|
|
shape: Shape,
|
|
}
|
|
|
|
impl RenderOnce for Avatar {
|
|
type Rendered = Div;
|
|
|
|
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
|
|
let mut img = img(self.src);
|
|
|
|
if self.shape == Shape::Circle {
|
|
img = img.rounded_full();
|
|
} else {
|
|
img = img.rounded_md();
|
|
}
|
|
|
|
let size = rems(1.0);
|
|
|
|
div()
|
|
.size(size)
|
|
.child(
|
|
img.size(size)
|
|
// todo!(Pull the avatar fallback background from the theme.)
|
|
.bg(gpui::red()),
|
|
)
|
|
.children(self.is_available.map(|is_free| {
|
|
// HACK: non-integer sizes result in oval indicators.
|
|
let indicator_size = (size.0 * cx.rem_size() * 0.4).round();
|
|
|
|
div()
|
|
.absolute()
|
|
.z_index(1)
|
|
.bg(if is_free { gpui::green() } else { gpui::red() })
|
|
.size(indicator_size)
|
|
.rounded(indicator_size)
|
|
.bottom_0()
|
|
.right_0()
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Avatar {
|
|
pub fn uri(src: impl Into<SharedString>) -> Self {
|
|
Self {
|
|
src: src.into().into(),
|
|
shape: Shape::Circle,
|
|
is_available: None,
|
|
}
|
|
}
|
|
pub fn data(src: Arc<ImageData>) -> Self {
|
|
Self {
|
|
src: src.into(),
|
|
shape: Shape::Circle,
|
|
is_available: None,
|
|
}
|
|
}
|
|
|
|
pub fn source(src: ImageSource) -> Self {
|
|
Self {
|
|
src,
|
|
shape: Shape::Circle,
|
|
is_available: None,
|
|
}
|
|
}
|
|
pub fn shape(mut self, shape: Shape) -> Self {
|
|
self.shape = shape;
|
|
self
|
|
}
|
|
pub fn availability_indicator(mut self, is_available: impl Into<Option<bool>>) -> Self {
|
|
self.is_available = is_available.into();
|
|
self
|
|
}
|
|
}
|