Adds renaming games functionality

This commit is contained in:
2025-07-12 17:07:33 +02:00
parent 28f7306d57
commit 3f99b68d62
30 changed files with 502 additions and 178 deletions

View File

@@ -1,7 +1,7 @@
use std::fmt::Display;
use async_trait::async_trait;
use gamenight_api_client_rs::{apis::default_api::game_post, models::{AddGameRequestBody, Game}};
use gamenight_api_client_rs::{apis::default_api::game_post, models::AddGameRequestBody};
use inquire::{Confirm, Text};

View File

@@ -1,31 +0,0 @@
use gamenight_api_client_rs::models::Game;
use super::*;
#[derive(Clone)]
pub struct EditGame {
game: Game
}
impl EditGame {
pub fn new(game: Game) -> Self {
Self {
game
}
}
}
#[async_trait]
impl<'a> Flow<'a> for EditGame {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
todo!()
}
}
impl Display for EditGame {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "")
}
}

View File

@@ -38,8 +38,7 @@ impl<'a> Flow<'a> for GamenightMenu {
})
.prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}

View File

@@ -34,9 +34,8 @@ impl<'a> Flow<'a> for Games {
..Default::default()
})
.prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}

View File

@@ -40,8 +40,7 @@ impl<'a> Flow<'a> for ListGamenights {
let choice = Select::new("What gamenight would you like to view?", view_flows).prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}

View File

@@ -4,7 +4,7 @@ use async_trait::async_trait;
use gamenight_api_client_rs::apis::default_api::games_get;
use inquire::{ui::RenderConfig, Select};
use crate::flows::{edit_game::EditGame, exit::Exit};
use crate::flows::{view_game::ViewGame, exit::Exit};
use super::*;
@@ -25,7 +25,7 @@ impl<'a> Flow<'a> for ListGames {
let games = games_get(&state.api_configuration).await?;
let mut flows = games.into_iter().map(|game| -> Box<dyn Flow + Send> {
Box::new(EditGame::new(game))
Box::new(ViewGame::new(game.into()))
}).collect::<Vec::<Box::<dyn Flow + Send>>>();
flows.push(Box::new(Exit::new()));
@@ -38,9 +38,7 @@ impl<'a> Flow<'a> for ListGames {
})
.prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}

View File

@@ -50,8 +50,7 @@ impl<'a> Flow<'a> for Main {
})
.prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}

View File

@@ -23,7 +23,8 @@ mod settings;
mod games;
mod list_games;
mod add_game;
mod edit_game;
mod view_game;
mod rename_game;
pub struct GamenightState {
api_configuration: Configuration,
@@ -111,25 +112,27 @@ dyn_clone::clone_trait_object!(for<'a> Flow<'a>);
#[async_trait]
pub trait Flow<'a>: Sync + DynClone + Send + Display {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a>;
}
async fn handle_choice<'a>(choice: &Box<dyn Flow<'a> + Send>, flow: &dyn Flow<'a>, state: &'a mut GamenightState) -> FlowResult<'a> {
let (outcome, new_state) = choice.run(state).await?;
async fn continue_choice(&self, state: &'a mut GamenightState, choice: &Option<Box<dyn Flow<'a> + Send>>) -> FlowResult<'a> {
clear_screen::clear();
if let Some(choice) = choice {
let (outcome, new_state) = choice.run(state).await?;
if outcome == FlowOutcome::Abort {
Ok((FlowOutcome::Successful, new_state))
if outcome == FlowOutcome::Abort {
Ok((FlowOutcome::Successful, new_state))
}
else {
self.run(new_state).await
}
}
else {
Ok((FlowOutcome::Cancelled, state))
}
}
else {
flow.run(new_state).await
}
}
async fn handle_choice_option<'a>(choice: &Option<Box<dyn Flow<'a> + Send>>, flow: &dyn Flow<'a>, state: &'a mut GamenightState) -> FlowResult<'a> {
if let Some(choice) = choice {
handle_choice(choice, flow, state).await
}
else {
Ok((FlowOutcome::Cancelled, state))
async fn continue_with(&self, state: &'a mut GamenightState, other: &dyn Flow<'a>) -> FlowResult<'a> {
clear_screen::clear();
other.run(state).await
}
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a>;
}

View File

@@ -0,0 +1,47 @@
use std::fmt::Display;
use async_trait::async_trait;
use gamenight_api_client_rs::{apis::default_api::rename_game_post, models::RenameGameRequestBody};
use inquire::Text;
use crate::domain::game::Game;
use super::{Flow, FlowOutcome, FlowResult, GamenightState};
#[derive(Clone)]
pub struct RenameGame {
pub game: Game
}
impl RenameGame {
pub fn new(game: Game) -> Self {
Self{
game
}
}
}
#[async_trait]
impl<'a> Flow<'a> for RenameGame {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
if let Some(name) = Text::new(&format!("Rename {} to:", self.game.name))
.with_initial_value(&format!("{}", self.game.name))
.prompt_skippable()?
{
let req = RenameGameRequestBody {
id: self.game.id.to_string(),
name
};
rename_game_post(&state.api_configuration, Some(req)).await?;
return Ok((FlowOutcome::Successful, state))
}
Ok((FlowOutcome::Cancelled, state))
}
}
impl Display for RenameGame {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Rename")
}
}

View File

@@ -0,0 +1,46 @@
use gamenight_api_client_rs::{apis::default_api::game_get, models::GameId};
use inquire::Select;
use crate::{domain::game::Game, flows::{exit::Exit, rename_game::RenameGame}};
use super::*;
#[derive(Clone)]
pub struct ViewGame {
game: Game
}
impl ViewGame {
pub fn new(game: Game) -> Self {
Self {
game
}
}
}
#[async_trait]
impl<'a> Flow<'a> for ViewGame {
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
let game_id = GameId{ game_id: self.game.id.to_string() };
let game: Game = game_get(&state.api_configuration, Some(game_id)).await?.into();
println!("{}", game);
let options: Vec<Box<dyn Flow<'a> + Send>> = vec![
Box::new(RenameGame::new(game.clone())),
Box::new(Exit::new())
];
let choice = Select::new("What do you want to do:", options)
.prompt_skippable()?;
self.continue_choice(state, &choice).await
}
}
impl Display for ViewGame {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.game.name)
}
}

View File

@@ -77,8 +77,7 @@ impl<'a> Flow<'a> for ViewGamenight {
let choice = Select::new("What do you want to do:", options)
.prompt_skippable()?;
clear_screen::clear();
handle_choice_option(&choice, self, state).await
self.continue_choice(state, &choice).await
}
}