use ratatui::prelude::*;
use crate::theme::Theme;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub enum ItemState {
#[default]
Ready,
Loading,
Error(String),
}
impl ItemState {
pub fn is_loading(&self) -> bool {
matches!(self, Self::Loading)
}
pub fn is_error(&self) -> bool {
matches!(self, Self::Error(_))
}
pub fn is_ready(&self) -> bool {
matches!(self, Self::Ready)
}
pub fn error_message(&self) -> Option<&str> {
if let Self::Error(msg) = self {
Some(msg)
} else {
None
}
}
pub fn symbol(&self, spinner_frame: usize) -> &'static str {
match self {
Self::Ready => " ",
Self::Loading => {
const LOADING_FRAMES: [&str; 10] =
["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
LOADING_FRAMES[spinner_frame % LOADING_FRAMES.len()]
}
Self::Error(_) => "✗",
}
}
pub fn style(&self, theme: &Theme) -> Style {
match self {
Self::Ready => theme.normal_style(),
Self::Loading => theme.warning_style(),
Self::Error(_) => theme.error_style(),
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct LoadingListItem<T: Clone> {
pub(super) data: T,
pub(super) label: String,
pub(super) state: ItemState,
}
impl<T: Clone + PartialEq> PartialEq for LoadingListItem<T> {
fn eq(&self, other: &Self) -> bool {
self.data == other.data && self.label == other.label && self.state == other.state
}
}
impl<T: Clone> LoadingListItem<T> {
pub fn new(data: T, label: impl Into<String>) -> Self {
Self {
data,
label: label.into(),
state: ItemState::Ready,
}
}
pub fn data(&self) -> &T {
&self.data
}
pub fn data_mut(&mut self) -> &mut T {
&mut self.data
}
pub fn label(&self) -> &str {
&self.label
}
pub fn set_label(&mut self, label: impl Into<String>) {
self.label = label.into();
}
pub fn state(&self) -> &ItemState {
&self.state
}
pub fn set_state(&mut self, state: ItemState) {
self.state = state;
}
pub fn is_loading(&self) -> bool {
self.state.is_loading()
}
pub fn is_error(&self) -> bool {
self.state.is_error()
}
pub fn is_ready(&self) -> bool {
self.state.is_ready()
}
}