🔒 Repository is read-only – file editing is disabled.

luna/crates/libluna-widgets/src/avatar.rs main

67 lines Raw ← Back
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
//! `Avatar` — okrągły awatar z inicjałami (zastępstwo obrazka).
//!
//! Widget immediate: [`Avatar::paint`] rysuje wypełniony okrąg z inicjałami. Rozmiar z tokenów
//! ([`AvatarMetrics`](libluna_core::AvatarMetrics)).

use libluna_core::style::weight;
use libluna_core::{Rect, Theme};

use crate::ctx::PaintCtx;

/// Awatar z inicjałami.
#[derive(Debug, Clone, Default)]
pub struct Avatar {
    initials: String,
}

impl Avatar {
    pub fn new(initials: impl Into<String>) -> Self {
        Self {
            initials: initials.into(),
        }
    }

    pub fn initials(&self) -> &str {
        &self.initials
    }

    /// Domyślna średnica awatara (z metryk).
    pub fn size(&self, theme: &Theme) -> f64 {
        theme.metrics.avatar.size
    }

    /// Rysuje awatar w (kwadratowym) prostokącie `rect`.
    pub fn paint(&self, ctx: &mut PaintCtx, rect: Rect) {
        let theme = *ctx.theme;
        let radius = rect.width().min(rect.height()) / 2.0;
        ctx.scene
            .fill_rounded_rect(rect, radius, theme.colors.accent);
        // Maksymalnie dwa znaki inicjałów (np. „Ada Lovelace” → „AL”).
        let initials: String = self
            .initials
            .chars()
            .take(2)
            .collect::<String>()
            .to_uppercase();
        ctx.label_center(
            rect.center().x,
            rect.center().y,
            &initials,
            theme.typography.body.size,
            weight::BOLD,
            theme.colors.accent_fg,
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn size_from_metrics() {
        let theme = Theme::light();
        assert_eq!(Avatar::new("AL").size(&theme), theme.metrics.avatar.size);
        assert_eq!(Avatar::new("AL").initials(), "AL");
    }
}