use crate::event::{AppEvent, EventHandler}; use crate::widgets::views::{AppView, MainView}; use color_eyre::Result; use crossterm::event::{Event}; use ratatui::{DefaultTerminal, Frame}; use std::time::Duration; use color_eyre::eyre::eyre; use db::RocksDBFactory; use models::config::ApplicationConfig; use models::dlsite::{DLSiteCategory, DLSiteGenre, DLSiteManiax}; pub(crate) struct App { events: EventHandler, state: AppState, db_factory: RocksDBFactory } #[derive(Clone)] pub struct AppState { view: Option, } impl App { pub async fn create() -> Result { let config = ApplicationConfig::get_config()?; let mut db_factory = RocksDBFactory::default(); db_factory.register::(); db_factory.register::(); db_factory.register::(); let state = AppState { view: Some(AppView::Main(MainView::new(db_factory.clone())?)), }; let app = Self { events: EventHandler::new(Duration::from_millis(config.basic_config.tick_rate)), state, db_factory }; Ok(app) } pub async fn run(mut self, terminal: &mut DefaultTerminal) -> Result<()> { loop { let event = self.events.next().await?; self.update(event)?; let Some(current_view) = self.state.view.as_mut() else { continue; }; let view = current_view.get_view(); if !view.is_running() { break Ok(()) } terminal.draw(|frame| self.draw(frame))?; } } fn update(&mut self, event: AppEvent) -> Result<()> { if let AppEvent::Raw(cross_event) = event { self.handle_event(&cross_event)?; } Ok(()) } fn handle_event(&mut self, key: &Event) -> Result<()> { let Some(current_view) = self.state.view.as_mut() else { return Err(eyre!("there is no view")); }; let view = current_view.get_view(); view.handle_input(key)?; Ok(()) } fn draw(&mut self, frame: &mut Frame) { let Some(current_view) = self.state.view.as_mut() else { return; }; let view = current_view.get_view(); if let Some(pos) = view.screen_cursor() { frame.set_cursor_position(pos); } match current_view { AppView::Main(main_view) => { frame.render_stateful_widget( main_view.clone(), frame.area(), &mut main_view.state, ); } } } }