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

View File

@ -1,25 +1,25 @@
use super::*;
#[derive(Clone)]
pub struct Abort {
pub struct Exit {
}
impl Abort {
impl Exit {
pub fn new() -> Self {
Self{}
}
}
#[async_trait]
impl<'a> Flow<'a> for Abort {
impl<'a> Flow<'a> for Exit {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
Ok((FlowOutcome::Abort, state))
}
}
impl Display for Abort {
impl Display for Exit {
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 super::{abort::Abort, *};
use super::{exit::Exit, *};
#[derive(Clone)]
pub struct ListGamenights {
@ -23,9 +23,9 @@ impl<'a> Flow<'a> for ListGamenights {
let response = get_gamenights(&state.configuration).await?;
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>>>();
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)
.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)]
pub struct Main {
@ -12,7 +12,7 @@ impl Main {
let mut main_menu = MainMenu::new();
main_menu.menu.push(Box::new(ListGamenights::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 {
login: Box::new(Login::new()),
main_menu: main_menu

View File

@ -9,7 +9,7 @@ use dyn_clone::DynClone;
pub mod main;
mod login;
mod main_menu;
mod abort;
mod exit;
mod list_gamenights;
mod add_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>);
#[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>;
}

View File

@ -1,6 +1,5 @@
use chrono::DateTime;
use gamenight_api_client_rs::models::Gamenight;
use crate::domain::gamenight::Gamenight;
use super::*;
@ -15,21 +14,13 @@ impl ViewGamenight {
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]
impl<'a> Flow<'a> for ViewGamenight {
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))
}
@ -37,7 +28,7 @@ impl<'a> Flow<'a> for ViewGamenight {
impl Display for ViewGamenight {
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 domain;
use flows::{main::Main, Flow, GamenightState};