Created a domain module to decouple flows from the core.

This commit is contained in:
Dennis Brentjes 2025-05-03 22:49:01 +02:00
parent fce0ebd76b
commit 4e26d3cdcb
9 changed files with 54 additions and 29 deletions

View File

@ -0,0 +1,27 @@
use std::fmt::Display;
use chrono::{DateTime, Local};
use gamenight_api_client_rs::models;
#[derive(Clone)]
pub struct Gamenight {
pub name: String,
pub start_time: DateTime<Local>
}
impl From<models::Gamenight> for Gamenight {
fn from(value: models::Gamenight) -> Self {
Self {
name: value.name,
start_time: DateTime::parse_from_rfc3339(&value.datetime).unwrap().into()
}
}
}
impl Display for Gamenight {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, r#"
Name: {}
When: {}
"#, self.name, self.start_time.format("%d-%m-%Y %H:%M"))
}
}

View File

@ -0,0 +1 @@
pub mod gamenight;

View File

@ -1,6 +1,6 @@
use gamenight_api_client_rs::{apis::default_api::post_gamenight, models}; use gamenight_api_client_rs::{apis::default_api::post_gamenight, models};
use inquire::{Text, DateSelect}; use inquire::{CustomType, DateSelect, Text};
use chrono::{self, Local, NaiveTime}; use chrono::{self, Local, NaiveTime};
use super::*; use super::*;
@ -21,9 +21,14 @@ impl<'a> Flow<'a> for AddGamenight {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> { async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
let mut add_gamenight = models::AddGamenightRequestBody::new(); let mut add_gamenight = models::AddGamenightRequestBody::new();
add_gamenight.name = Some(Text::new("What should we call your gamenight").prompt()?); add_gamenight.name = Some(Text::new("What should we call your gamenight")
add_gamenight.datetime = Some(DateSelect::new("When is your gamenight").prompt()? .prompt()?);
.and_time(NaiveTime::default()) let naive_date = DateSelect::new("When is your gamenight")
.prompt()?;
let naive_time = CustomType::<NaiveTime>::new("At What time")
.prompt()?;
add_gamenight.datetime = Some(naive_date
.and_time(naive_time)
.and_local_timezone(Local) .and_local_timezone(Local)
.earliest() .earliest()
.unwrap() .unwrap()

View File

@ -1,25 +1,25 @@
use super::*; use super::*;
#[derive(Clone)] #[derive(Clone)]
pub struct Abort { pub struct Exit {
} }
impl Abort { impl Exit {
pub fn new() -> Self { pub fn new() -> Self {
Self{} Self{}
} }
} }
#[async_trait] #[async_trait]
impl<'a> Flow<'a> for Abort { impl<'a> Flow<'a> for Exit {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> { async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
Ok((FlowOutcome::Abort, state)) Ok((FlowOutcome::Abort, state))
} }
} }
impl Display for Abort { impl Display for Exit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Abort") write!(f, "Exit")
} }
} }

View File

@ -4,7 +4,7 @@ use inquire::Select;
use crate::flows::view_gamenight::ViewGamenight; use crate::flows::view_gamenight::ViewGamenight;
use super::{abort::Abort, *}; use super::{exit::Exit, *};
#[derive(Clone)] #[derive(Clone)]
pub struct ListGamenights { pub struct ListGamenights {
@ -23,9 +23,9 @@ impl<'a> Flow<'a> for ListGamenights {
let response = get_gamenights(&state.configuration).await?; let response = get_gamenights(&state.configuration).await?;
let mut view_flows = response.into_iter().map(|gamenight| -> Box<dyn Flow<'a> + Send> { let mut view_flows = response.into_iter().map(|gamenight| -> Box<dyn Flow<'a> + Send> {
Box::new(ViewGamenight::new(gamenight)) Box::new(ViewGamenight::new(gamenight.into()))
}).collect::<Vec<Box<dyn Flow<'a> + Send>>>(); }).collect::<Vec<Box<dyn Flow<'a> + Send>>>();
view_flows.push(Box::new(Abort::new())); view_flows.push(Box::new(Exit::new()));
let choice = Select::new("What gamenight would you like to view?", view_flows) let choice = Select::new("What gamenight would you like to view?", view_flows)
.prompt_skippable()?; .prompt_skippable()?;

View File

@ -1,5 +1,5 @@
use super::{abort::Abort, add_gamenight::AddGamenight, list_gamenights::ListGamenights, login::Login, main_menu::MainMenu, *}; use super::{exit::Exit, add_gamenight::AddGamenight, list_gamenights::ListGamenights, login::Login, main_menu::MainMenu, *};
#[derive(Clone)] #[derive(Clone)]
pub struct Main { pub struct Main {
@ -12,7 +12,7 @@ impl Main {
let mut main_menu = MainMenu::new(); let mut main_menu = MainMenu::new();
main_menu.menu.push(Box::new(ListGamenights::new())); main_menu.menu.push(Box::new(ListGamenights::new()));
main_menu.menu.push(Box::new(AddGamenight::new())); main_menu.menu.push(Box::new(AddGamenight::new()));
main_menu.menu.push(Box::new(Abort::new())); main_menu.menu.push(Box::new(Exit::new()));
Self { Self {
login: Box::new(Login::new()), login: Box::new(Login::new()),
main_menu: main_menu main_menu: main_menu

View File

@ -9,7 +9,7 @@ use dyn_clone::DynClone;
pub mod main; pub mod main;
mod login; mod login;
mod main_menu; mod main_menu;
mod abort; mod exit;
mod list_gamenights; mod list_gamenights;
mod add_gamenight; mod add_gamenight;
mod view_gamenight; mod view_gamenight;
@ -68,7 +68,7 @@ type FlowResult<'a> = Result<(FlowOutcome, &'a mut GamenightState), FlowError>;
dyn_clone::clone_trait_object!(for<'a> Flow<'a>); dyn_clone::clone_trait_object!(for<'a> Flow<'a>);
#[async_trait] #[async_trait]
pub trait Flow<'a>: Sync + Display + DynClone + Send { pub trait Flow<'a>: Sync + DynClone + Send + Display {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a>; async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a>;
} }

View File

@ -1,6 +1,5 @@
use chrono::DateTime; use crate::domain::gamenight::Gamenight;
use gamenight_api_client_rs::models::Gamenight;
use super::*; use super::*;
@ -15,21 +14,13 @@ impl ViewGamenight {
gamenight gamenight
} }
} }
pub fn gamenight_localtime(&self) -> Result<String, FlowError> {
let datetime = DateTime::parse_from_rfc3339(&self.gamenight.datetime)?;
let offset = *chrono::offset::Local::now().offset();
Ok(format!("{}", datetime.naive_local().checked_add_offset(offset).unwrap().format("%d-%m-%Y %H:%M")))
}
} }
#[async_trait] #[async_trait]
impl<'a> Flow<'a> for ViewGamenight { impl<'a> Flow<'a> for ViewGamenight {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> { async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
println!("Name: {}", self.gamenight.name);
println!("When: {}", self.gamenight_localtime()?); print!("{}", self.gamenight);
Ok((FlowOutcome::Successful, state)) Ok((FlowOutcome::Successful, state))
} }
@ -37,7 +28,7 @@ impl<'a> Flow<'a> for ViewGamenight {
impl Display for ViewGamenight { impl Display for ViewGamenight {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.gamenight.name, self.gamenight.datetime) write!(f, "{} {}", self.gamenight.name, self.gamenight.start_time.format("%d-%m-%Y %H:%M"))
} }
} }

View File

@ -1,4 +1,5 @@
pub mod flows; pub mod flows;
pub mod domain;
use flows::{main::Main, Flow, GamenightState}; use flows::{main::Main, Flow, GamenightState};