forked from Roflin/gamenight
Added some more gamenight-cli Flows.
This commit is contained in:
135
gamenight-cli/Cargo.lock
generated
135
gamenight-cli/Cargo.lock
generated
@@ -17,6 +17,21 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.88"
|
||||
@@ -93,9 +108,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.19"
|
||||
version = "1.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
||||
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -106,6 +121,20 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@@ -298,6 +327,8 @@ name = "gamenight-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"dyn-clone",
|
||||
"gamenight-api-client-rs",
|
||||
"inquire",
|
||||
"tokio",
|
||||
@@ -353,9 +384,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
@@ -470,6 +501,30 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
@@ -626,6 +681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"chrono",
|
||||
"crossterm",
|
||||
"dyn-clone",
|
||||
"fuzzy-matcher",
|
||||
@@ -772,6 +828,15 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
@@ -821,9 +886,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.107"
|
||||
version = "0.9.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
|
||||
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -978,9 +1043,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.5"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"errno",
|
||||
@@ -1208,9 +1273,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1228,9 +1293,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1591,6 +1656,41 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
@@ -1604,7 +1704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
@@ -1626,6 +1726,15 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
||||
@@ -6,5 +6,7 @@ edition = "2024"
|
||||
[dependencies]
|
||||
gamenight-api-client-rs = { path = "../gamenight-api-client-rs" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
inquire = "0.7.5"
|
||||
async-trait = "0.1"
|
||||
inquire = { version = "0.7.5", features = ["date"] }
|
||||
async-trait = "0.1"
|
||||
dyn-clone = "1.0"
|
||||
chrono = "0.4"
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Abort {
|
||||
|
||||
}
|
||||
|
||||
44
gamenight-cli/src/flows/add_gamenight.rs
Normal file
44
gamenight-cli/src/flows/add_gamenight.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
use gamenight_api_client_rs::{apis::default_api::post_gamenight, models};
|
||||
use inquire::{Text, DateSelect};
|
||||
use chrono::{self, Local, NaiveTime};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AddGamenight {
|
||||
|
||||
}
|
||||
|
||||
impl AddGamenight {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
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())
|
||||
.and_local_timezone(Local)
|
||||
.earliest()
|
||||
.unwrap()
|
||||
.to_utc()
|
||||
.to_rfc3339());
|
||||
|
||||
post_gamenight(&state.configuration, Some(add_gamenight)).await?;
|
||||
|
||||
Ok((FlowOutcome::Successful, state))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AddGamenight {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Add Gamenight.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
|
||||
use gamenight_api_client_rs::apis::default_api::get_gamenights;
|
||||
use inquire::Select;
|
||||
|
||||
use super::*;
|
||||
use crate::flows::view_gamenight::ViewGamenight;
|
||||
|
||||
use super::{abort::Abort, *};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ListGamenights {
|
||||
|
||||
}
|
||||
@@ -17,8 +21,16 @@ impl ListGamenights {
|
||||
impl<'a> Flow<'a> for ListGamenights {
|
||||
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
|
||||
let response = get_gamenights(&state.configuration).await?;
|
||||
println!("{:?}", response);
|
||||
Ok((FlowOutcome::Successful, state))
|
||||
|
||||
let mut view_flows = response.into_iter().map(|gamenight| -> Box<dyn Flow<'a> + Send> {
|
||||
Box::new(ViewGamenight::new(gamenight))
|
||||
}).collect::<Vec<Box<dyn Flow<'a> + Send>>>();
|
||||
view_flows.push(Box::new(Abort::new()));
|
||||
|
||||
let choice = Select::new("What gamenight would you like to view?", view_flows)
|
||||
.prompt_skippable()?;
|
||||
|
||||
handle_choice_option(&choice, self, state).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use inquire::{Password, Text};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Login {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
use super::{abort::Abort, list_gamenights::ListGamenights, login::Login, main_menu::MainMenu, *};
|
||||
|
||||
use super::{abort::Abort, add_gamenight::AddGamenight, list_gamenights::ListGamenights, login::Login, main_menu::MainMenu, *};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Main {
|
||||
login: Box<dyn for<'a> Flow<'a>>,
|
||||
main_menu: MainMenu
|
||||
@@ -11,6 +11,7 @@ impl Main {
|
||||
pub fn new() -> Self {
|
||||
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()));
|
||||
Self {
|
||||
login: Box::new(Login::new()),
|
||||
|
||||
@@ -3,6 +3,7 @@ use inquire::{ui::RenderConfig, Select};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MainMenu {
|
||||
pub menu: Vec<Box<dyn for<'a> Flow<'a> + Send>>
|
||||
}
|
||||
@@ -22,7 +23,7 @@ unsafe impl Send for MainMenu {
|
||||
#[async_trait]
|
||||
impl<'a> Flow<'a> for MainMenu {
|
||||
async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> {
|
||||
let choice = Select::new("What would you like to do?", self.menu)
|
||||
let choice = Select::new("What would you like to do?", self.menu.clone())
|
||||
.with_help_message("Select the action you want to take or quit the program")
|
||||
.with_render_config(RenderConfig {
|
||||
option_index_prefix: inquire::ui::IndexPrefix::Simple,
|
||||
@@ -30,19 +31,7 @@ impl<'a> Flow<'a> for MainMenu {
|
||||
})
|
||||
.prompt_skippable()?;
|
||||
|
||||
if let Some(choice) = choice {
|
||||
let (outcome, new_state) = choice.run(state).await?;
|
||||
|
||||
if outcome == FlowOutcome::Abort {
|
||||
Ok((outcome, new_state))
|
||||
}
|
||||
else {
|
||||
self.run(new_state).await
|
||||
}
|
||||
}
|
||||
else {
|
||||
return Ok((FlowOutcome::Abort, state))
|
||||
}
|
||||
handle_choice_option(&choice, self, state).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::ParseError;
|
||||
use gamenight_api_client_rs::apis::configuration::Configuration;
|
||||
use inquire::InquireError;
|
||||
use dyn_clone::DynClone;
|
||||
|
||||
pub mod main;
|
||||
pub mod login;
|
||||
mod login;
|
||||
mod main_menu;
|
||||
mod abort;
|
||||
mod list_gamenights;
|
||||
mod add_gamenight;
|
||||
mod view_gamenight;
|
||||
|
||||
pub struct GamenightState {
|
||||
configuration: Configuration,
|
||||
@@ -43,6 +47,14 @@ impl<T> From<gamenight_api_client_rs::apis::Error<T>> for FlowError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseError> for FlowError {
|
||||
fn from(value: ParseError) -> Self {
|
||||
Self {
|
||||
error: value.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FlowOutcome {
|
||||
Successful,
|
||||
@@ -53,7 +65,29 @@ pub enum FlowOutcome {
|
||||
|
||||
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 {
|
||||
pub trait Flow<'a>: Sync + Display + DynClone + Send {
|
||||
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?;
|
||||
|
||||
if outcome == FlowOutcome::Abort {
|
||||
Ok((FlowOutcome::Successful, new_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::Abort, state))
|
||||
}
|
||||
}
|
||||
43
gamenight-cli/src/flows/view_gamenight.rs
Normal file
43
gamenight-cli/src/flows/view_gamenight.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
use chrono::DateTime;
|
||||
use gamenight_api_client_rs::models::Gamenight;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ViewGamenight {
|
||||
gamenight: Gamenight
|
||||
}
|
||||
|
||||
impl ViewGamenight {
|
||||
pub fn new(gamenight: Gamenight) -> Self {
|
||||
Self {
|
||||
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()?);
|
||||
|
||||
|
||||
|
||||
Ok((FlowOutcome::Successful, state))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ViewGamenight {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} {}", self.gamenight.name, self.gamenight.datetime)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user