use crate::{
authentication::Authentication,
event::{Event, Outcome},
home::Home,
logging::{LogMessage, LogWidget},
widgets::{StatusBar, TitleBar},
};
use color_eyre::{eyre::WrapErr, Result};
use parking_lot::Mutex;
use parking_lot::RwLock;
use ratatui::prelude::*;
use std::sync::Arc;
use tokio::sync::mpsc::Sender;
use tracing::info;
enum State {
Authentication,
Home,
}
pub struct Root {
_event_sender: Sender<Event>,
state: State,
authentication: Authentication,
home: Home,
logs: Arc<Mutex<Vec<LogMessage>>>,
show_logs: bool,
}
impl Root {
pub fn new(event_sender: Sender<Event>, logs: Arc<Mutex<Vec<LogMessage>>>) -> Self {
let authentication_data = Arc::new(RwLock::new(None));
let authentication =
Authentication::new(event_sender.clone(), Arc::clone(&authentication_data));
let home = Home::new(event_sender.clone(), Arc::clone(&authentication_data));
let show_logs = std::env::var("TOOT_RS_SHOW_LOGS").is_ok();
Self {
_event_sender: event_sender,
state: State::Authentication,
authentication,
home,
logs,
show_logs,
}
}
pub async fn start(&mut self) -> Result<()> {
info!("Starting root component");
self.authentication
.start()
.await
.wrap_err("Authentication component failed to start")
}
pub async fn handle_event(&mut self, event: &Event) -> Outcome {
match self.state {
State::Authentication => {
if event == &Event::AuthenticationSuccess {
self.state = State::Home;
self.home.start().await.ok();
return Outcome::Handled;
}
self.authentication.handle_event(event).await
}
State::Home => self.home.handle_event(event),
}
}
}
impl Widget for &Root {
fn render(self, area: Rect, buf: &mut Buffer) {
use Constraint::*;
let log_height = if self.show_logs { 7 } else { 0 };
let [top, mid, logs, bottom] = Layout::vertical([
Length(TitleBar::HEIGHT),
Fill(1),
Length(log_height),
Length(StatusBar::HEIGHT),
])
.areas(area);
match self.state {
State::Authentication => {
TitleBar::new(&self.authentication.title()).render(top, buf);
StatusBar::new("Loading...").render(bottom, buf);
self.authentication.render(mid, buf);
}
State::Home => {
TitleBar::new(&self.home.title()).render(top, buf);
StatusBar::new(&self.home.status()).render(bottom, buf);
self.home.render(mid, buf);
}
}
if self.show_logs {
LogWidget::new(self.logs.clone()).render(logs, buf);
};
}
}