huellas/src/tui/state.rs

184 lines
4.7 KiB
Rust

//! 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<Place>,
places_status: DataStatus,
pub confirmation: Option<ConfirmationStatus>,
pub selected_place: TableState,
pub ui_messages: Vec<Message>,
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;
}
}