//! TUI state use ratatui::crossterm::event::KeyEvent; use ratatui::widgets::TableState; use crate::places::db_repository::DbPlacesRepository; use crate::places::models::Place; use crate::places::repository::PlacesRepository; use super::ui::Message; pub struct State { pub height: u16, pub page: u32, pub mode: Mode, places_repository: DbPlacesRepository, pub places: Vec, places_status: DataStatus, pub confirmation: Option, pub selected_place: TableState, pub ui_messages: Vec, pub quit: bool, } #[derive(Copy, Clone)] pub enum Mode { List, Edit, } enum DataStatus { Fresh, Old, } pub enum ConfirmationStatus { Deletion(i64), Save(Place), } impl State { pub fn new(places_repository: DbPlacesRepository, height: u16) -> Self { Self { height, page: 0, mode: Mode::List, places_repository, places_status: DataStatus::Old, places: vec![], selected_place: TableState::default(), confirmation: None, ui_messages: Vec::new(), quit: false, } } pub fn set_list_mode(&mut self) { self.mode = Mode::List; self.push_mode_change(); } pub fn set_edit_mode(&mut self) { self.mode = Mode::Edit; self.push_mode_change(); let Some(selection) = self.selected_place.selected() else { return; }; let Some(place) = self.places.get(selection) else { return; }; self.ui_messages.push(Message::EditPlace(place.clone())) } fn push_mode_change(&mut self) { self.ui_messages.push(Message::UpdateAppMode(self.mode)); } pub fn next_page(&mut self) { self.page += 1; self.places_status = DataStatus::Old; self.push_page_change(); } pub fn prev_page(&mut self) { self.page = self.page.saturating_sub(1); self.places_status = DataStatus::Old; self.push_page_change(); } fn push_page_change(&mut self) { self.ui_messages.push(Message::UpdatePage(self.page)); } pub fn edit_next(&mut self) { self.ui_messages.push(Message::EditNext); } pub fn edit_prev(&mut self) { self.ui_messages.push(Message::EditPrev); } pub fn edit_input(&mut self, key_event: KeyEvent) { self.ui_messages.push(Message::Input(key_event)); } pub async fn fetch_places(&mut self) { if let DataStatus::Fresh = self.places_status { return; } let limit = (self.height as u8).saturating_sub(3); let offset = (limit as u32) * self.page; match self .places_repository .get_places_paginated(offset, limit) .await { Ok(places) => { self.places = places; if !self.places.is_empty() { self.selected_place.select(Some(0)); } } Err(err) => { tracing::error!("{err}"); } } self.places_status = DataStatus::Fresh; self.ui_messages .push(Message::UpdatePlaces(self.places.clone())) } pub fn confirm_deletion(&mut self) { if let Some(Some(id)) = self .selected_place .selected() .map(|index| self.places.get(index).map(|p| p.id)) { self.confirmation = Some(ConfirmationStatus::Deletion(id)) } } pub fn start_save(&mut self) { if let Some(Some(id)) = self .selected_place .selected() .map(|index| self.places.get(index).map(|p| p.id)) { self.ui_messages.push(Message::SavePlace(id)); } } pub fn confirm_save(&mut self, place: Place) { self.confirmation = Some(ConfirmationStatus::Save(place)); } pub fn cancel_confirmation(&mut self) { self.confirmation = None; } pub async fn proceed_confirmation(&mut self) { let Some(confirmation) = &self.confirmation else { return; }; match confirmation { ConfirmationStatus::Deletion(id) => { if let Err(err) = self.places_repository.delete_place(*id).await { tracing::error!("{err}"); } } ConfirmationStatus::Save(place) => { if let Err(err) = self.places_repository.update_place(place.clone()).await { tracing::error!("{err}"); } self.mode = Mode::List; self.push_mode_change(); } } self.confirmation = None; self.places_status = DataStatus::Old; } }