use crate::icons::{Icon, icons};
use crate::styles::icons as icon_sizes;
use crate::tokens::DESIGN_TOKENS;
use crate::ui::model::ConnectionState;
use egui::{Color32, Response, RichText, Ui, Vec2, Widget};
pub struct ConnectionStatusIndicator<'a> {
state: &'a ConnectionState,
show_label: bool,
}
impl<'a> ConnectionStatusIndicator<'a> {
pub fn new(state: &'a ConnectionState) -> Self {
Self {
state,
show_label: false,
}
}
#[must_use]
pub fn with_label(mut self) -> Self {
self.show_label = true;
self
}
fn state_color(&self) -> Color32 {
match self.state {
ConnectionState::Connected => DESIGN_TOKENS.semantic.extended.bullish,
ConnectionState::Connecting => DESIGN_TOKENS.semantic.status.caution,
ConnectionState::Reconnecting { .. } => DESIGN_TOKENS.semantic.status.caution,
ConnectionState::Disconnected => DESIGN_TOKENS.semantic.ui.text_muted_dark,
ConnectionState::Failed(_) => DESIGN_TOKENS.semantic.extended.bearish,
}
}
fn state_icon(&self) -> &'static Icon {
match self.state {
ConnectionState::Connected => &icons::STATUS_CONNECTED,
ConnectionState::Connecting | ConnectionState::Reconnecting { .. } => {
&icons::STATUS_CONNECTING
}
ConnectionState::Disconnected => &icons::STATUS_DISCONNECTED,
ConnectionState::Failed(_) => &icons::STATUS_ERROR,
}
}
fn state_label(&self) -> &'static str {
match self.state {
ConnectionState::Connected => "Live",
ConnectionState::Connecting => "Connecting...",
ConnectionState::Reconnecting { attempt: _ } => {
"Reconnecting..."
}
ConnectionState::Disconnected => "Offline",
ConnectionState::Failed(_) => "Error",
}
}
}
impl<'a> Widget for ConnectionStatusIndicator<'a> {
fn ui(self, ui: &mut Ui) -> Response {
let color = self.state_color();
let icon = self.state_icon();
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = DESIGN_TOKENS.spacing.xs;
ui.add(icon.as_image_tinted(Vec2::splat(icon_sizes::XS), color));
if self.show_label {
ui.label(RichText::new(self.state_label()).color(color).size(11.0));
}
})
.response
}
}
pub fn show_connection_status(ui: &mut Ui, state: &ConnectionState) -> Response {
ConnectionStatusIndicator::new(state).ui(ui)
}
pub fn show_connection_status_with_label(ui: &mut Ui, state: &ConnectionState) -> Response {
ConnectionStatusIndicator::new(state).with_label().ui(ui)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_icons() {
let connected = ConnectionStatusIndicator::new(&ConnectionState::Connected);
assert_eq!(connected.state_icon(), &icons::STATUS_CONNECTED);
let disconnected = ConnectionStatusIndicator::new(&ConnectionState::Disconnected);
assert_eq!(disconnected.state_icon(), &icons::STATUS_DISCONNECTED);
let failed_state = ConnectionState::Failed("error".to_string());
let failed = ConnectionStatusIndicator::new(&failed_state);
assert_eq!(failed.state_icon(), &icons::STATUS_ERROR);
}
}