From bffb171c1458c12fa8b61541fd14080455e62c2d Mon Sep 17 00:00:00 2001 From: Yash Sharma Date: Mon, 20 Nov 2023 01:35:55 -0800 Subject: [PATCH] Fixed compile issues on newer versions of rust + bumped dependencies + clippy fixes + added extra info if no cards are present in a board + code refactoring for readability + shifted from saving access tokens to saving refresh tokens + fixed horizontal scrollbar not rendering --- Cargo.lock | 186 +++++-- Cargo.toml | 26 +- src/app/actions.rs | 176 +++--- src/app/app_helper.rs | 1055 ++++++++++++++++++++++++------------ src/app/kanban.rs | 38 +- src/app/mod.rs | 486 ++++++++++------- src/app/state.rs | 784 +++++++++++++++------------ src/constants.rs | 230 ++------ src/inputs/key.rs | 190 ++++--- src/inputs/mouse.rs | 16 +- src/io/data_handler.rs | 8 +- src/io/io_handler.rs | 416 +++++++++----- src/io/mod.rs | 24 +- src/main.rs | 8 +- src/ui/mod.rs | 1160 ++++++++-------------------------------- src/ui/themes.rs | 480 +++++++++++++++++ src/ui/ui_helper.rs | 804 ++++++++++++++++------------ src/ui/ui_main.rs | 7 +- src/ui/widgets.rs | 191 +++---- src/util.rs | 2 +- 20 files changed, 3417 insertions(+), 2870 deletions(-) create mode 100644 src/ui/themes.rs diff --git a/Cargo.lock b/Cargo.lock index 0f63123..27058a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", @@ -52,6 +52,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.0.2" @@ -61,6 +73,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -78,9 +96,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", @@ -116,9 +134,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys", @@ -147,9 +165,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -229,9 +247,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", @@ -253,9 +271,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.2" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", @@ -263,9 +281,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstream", "anstyle", @@ -275,9 +293,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -287,9 +305,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -405,9 +423,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" dependencies = [ "indenter", "once_cell", @@ -559,6 +577,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "heck" version = "0.4.1" @@ -697,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -753,9 +781,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linked-hash-map" @@ -794,6 +822,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lru" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +dependencies = [ + "hashbrown 0.14.2", +] + [[package]] name = "memchr" version = "2.6.3" @@ -817,9 +854,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", @@ -1029,15 +1066,16 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e2e4cd95294a85c3b4446e63ef054eea43e0205b1fd60120c16b74ff7ff96ad" +checksum = "0ebc917cfb527a566c37ecb94c7e3fd098353516fb4eb6bea17015ade0182425" dependencies = [ "bitflags 2.3.3", "cassowary", "crossterm", "indoc", "itertools", + "lru", "paste", "serde", "strum", @@ -1056,9 +1094,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.5" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -1068,9 +1106,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1079,15 +1117,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64", "bytes", @@ -1110,6 +1148,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -1122,7 +1161,7 @@ dependencies = [ [[package]] name = "rust-kanban" -version = "0.8.1" +version = "0.8.2" dependencies = [ "aes-gcm", "base64", @@ -1219,18 +1258,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", @@ -1239,9 +1278,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1323,9 +1362,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys", @@ -1367,15 +1406,36 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.28" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.7.0" @@ -1426,9 +1486,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -1438,16 +1498,16 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.5", "tokio-macros", "windows-sys", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -1590,9 +1650,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "getrandom", ] @@ -1815,3 +1875,23 @@ dependencies = [ "cfg-if", "windows-sys", ] + +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 4d1ff90..bdb7938 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-kanban" -version = "0.8.1" +version = "0.8.2" authors = ["Yash Sharma "] edition = "2021" license = "MIT" @@ -11,24 +11,24 @@ categories = ["command-line-utilities", "text-editors"] [dependencies] log = "0.4.20" -ratatui = { version = "0.23.0", features = ["serde"] } +ratatui = { version = "0.24.0", features = ["serde"] } crossterm = "0.27.0" -tokio = { version = "1.32.0", features = ["full"] } -chrono = "0.4.30" +tokio = { version = "1.34.0", features = ["full"] } +chrono = "0.4.31" textwrap = "0.16" -eyre = "0.6.8" +eyre = "0.6.9" home = "0.5.5" -serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.106" -clap = { version = "4.4.2", features = ["derive"] } -uuid = { version = "1.4.1", features = ["v4"] } -regex = "1.9.5" +serde = { version = "1.0.192", features = ["derive"] } +serde_json = "1.0.108" +clap = { version = "4.4.8", features = ["derive"] } +uuid = { version = "1.5.0", features = ["v4"] } +regex = "1.10.2" linked-hash-map = "0.5.6" ngrammatic = "0.4.0" lazy_static = "1.4.0" fxhash = "0.2.1" parking_lot = "0.12.1" -reqwest = { version = "0.11.20", features = ["json"] } -aes-gcm = "0.10.2" -base64 = "0.21.4" +reqwest = { version = "0.11.22", features = ["json"] } +aes-gcm = "0.10.3" +base64 = "0.21.5" bunt = "0.2.8" diff --git a/src/app/actions.rs b/src/app/actions.rs index a0e7c3a..8362052 100644 --- a/src/app/actions.rs +++ b/src/app/actions.rs @@ -8,110 +8,110 @@ use std::{ #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Action { - Quit, - NextFocus, - PrvFocus, - OpenConfigMenu, - Up, + ChangeCardStatusToActive, + ChangeCardStatusToCompleted, + ChangeCardStatusToStale, + ClearAllToasts, + Delete, + DeleteBoard, Down, - Right, + Enter, + GoToMainMenu, + GoToPreviousUIMode, + HideUiElement, Left, - MoveCardUp, MoveCardDown, - MoveCardRight, MoveCardLeft, - TakeUserInput, - StopUserInput, - GoToPreviousUIMode, - Enter, - HideUiElement, - SaveState, + MoveCardRight, + MoveCardUp, NewBoard, NewCard, - Delete, - DeleteBoard, - ChangeCardStatusToCompleted, - ChangeCardStatusToActive, - ChangeCardStatusToStale, + NextFocus, + OpenConfigMenu, + PrvFocus, + Quit, + Redo, ResetUI, - GoToMainMenu, + Right, + SaveState, + StopUserInput, + TakeUserInput, ToggleCommandPalette, Undo, - Redo, - ClearAllToasts, + Up, } impl Action { pub fn iterator() -> Iter<'static, Action> { static ACTIONS: [Action; 31] = [ - Action::Quit, - Action::NextFocus, - Action::PrvFocus, - Action::OpenConfigMenu, - Action::Up, + Action::ChangeCardStatusToActive, + Action::ChangeCardStatusToCompleted, + Action::ChangeCardStatusToStale, + Action::ClearAllToasts, + Action::Delete, + Action::DeleteBoard, Action::Down, - Action::Right, + Action::Enter, + Action::GoToMainMenu, + Action::GoToPreviousUIMode, + Action::HideUiElement, Action::Left, - Action::MoveCardUp, Action::MoveCardDown, - Action::MoveCardRight, Action::MoveCardLeft, - Action::TakeUserInput, - Action::StopUserInput, - Action::GoToPreviousUIMode, - Action::Enter, - Action::HideUiElement, - Action::SaveState, + Action::MoveCardRight, + Action::MoveCardUp, Action::NewBoard, Action::NewCard, - Action::Delete, - Action::DeleteBoard, - Action::ChangeCardStatusToCompleted, - Action::ChangeCardStatusToActive, - Action::ChangeCardStatusToStale, + Action::NextFocus, + Action::OpenConfigMenu, + Action::PrvFocus, + Action::Quit, + Action::Redo, Action::ResetUI, - Action::GoToMainMenu, + Action::Right, + Action::SaveState, + Action::StopUserInput, + Action::TakeUserInput, Action::ToggleCommandPalette, Action::Undo, - Action::Redo, - Action::ClearAllToasts, + Action::Up, ]; ACTIONS.iter() } pub fn keys(&self) -> &[Key] { match self { - Action::Quit => &[Key::Ctrl('c'), Key::Char('q')], - Action::NextFocus => &[Key::Tab], - Action::PrvFocus => &[Key::BackTab], - Action::OpenConfigMenu => &[Key::Char('c')], - Action::Up => &[Key::Up], + Action::ChangeCardStatusToActive => &[Key::Char('2')], + Action::ChangeCardStatusToCompleted => &[Key::Char('1')], + Action::ChangeCardStatusToStale => &[Key::Char('3')], + Action::ClearAllToasts => &[Key::Char('t')], + Action::Delete => &[Key::Char('d')], + Action::DeleteBoard => &[Key::Char('D')], Action::Down => &[Key::Down], - Action::Right => &[Key::Right], + Action::Enter => &[Key::Enter], + Action::GoToMainMenu => &[Key::Char('m')], + Action::GoToPreviousUIMode => &[Key::Esc], + Action::HideUiElement => &[Key::Char('h')], Action::Left => &[Key::Left], - Action::MoveCardUp => &[Key::ShiftUp], Action::MoveCardDown => &[Key::ShiftDown], - Action::MoveCardRight => &[Key::ShiftRight], Action::MoveCardLeft => &[Key::ShiftLeft], - Action::TakeUserInput => &[Key::Char('i')], - Action::StopUserInput => &[Key::Ins], - Action::GoToPreviousUIMode => &[Key::Esc], - Action::Enter => &[Key::Enter], - Action::HideUiElement => &[Key::Char('h')], - Action::SaveState => &[Key::Ctrl('s')], + Action::MoveCardRight => &[Key::ShiftRight], + Action::MoveCardUp => &[Key::ShiftUp], Action::NewBoard => &[Key::Char('b')], Action::NewCard => &[Key::Char('n')], - Action::Delete => &[Key::Char('d')], - Action::DeleteBoard => &[Key::Char('D')], - Action::ChangeCardStatusToCompleted => &[Key::Char('1')], - Action::ChangeCardStatusToActive => &[Key::Char('2')], - Action::ChangeCardStatusToStale => &[Key::Char('3')], + Action::NextFocus => &[Key::Tab], + Action::OpenConfigMenu => &[Key::Char('c')], + Action::PrvFocus => &[Key::BackTab], + Action::Quit => &[Key::Ctrl('c'), Key::Char('q')], + Action::Redo => &[Key::Ctrl('y')], Action::ResetUI => &[Key::Char('r')], - Action::GoToMainMenu => &[Key::Char('m')], + Action::Right => &[Key::Right], + Action::SaveState => &[Key::Ctrl('s')], + Action::StopUserInput => &[Key::Ins], + Action::TakeUserInput => &[Key::Char('i')], Action::ToggleCommandPalette => &[Key::Ctrl('p')], Action::Undo => &[Key::Ctrl('z')], - Action::Redo => &[Key::Ctrl('y')], - Action::ClearAllToasts => &[Key::Char('t')], + Action::Up => &[Key::Up], } } @@ -123,37 +123,37 @@ impl Action { impl Display for Action { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str = match self { - Action::Quit => "Quit", - Action::NextFocus => "Focus next", - Action::PrvFocus => "Focus previous", - Action::OpenConfigMenu => "configure", - Action::Up => "Go up", + Action::ChangeCardStatusToActive => "Change card status to active", + Action::ChangeCardStatusToCompleted => "Change card status to completed", + Action::ChangeCardStatusToStale => "Change card status to stale", + Action::ClearAllToasts => "Clear all toasts", + Action::Delete => "Delete focused element", + Action::DeleteBoard => "Delete Board", Action::Down => "Go down", - Action::Right => "Go right", + Action::Enter => "Accept", + Action::GoToMainMenu => "Go to main menu", + Action::GoToPreviousUIMode => "Go to previous mode", + Action::HideUiElement => "Hide Focused element", Action::Left => "Go left", - Action::MoveCardUp => "Move card up", Action::MoveCardDown => "Move card down", - Action::MoveCardRight => "Move card right", Action::MoveCardLeft => "Move card left", - Action::TakeUserInput => "Enter input mode", - Action::StopUserInput => "Stop input mode", - Action::GoToPreviousUIMode => "Go to previous mode", - Action::Enter => "Accept", - Action::HideUiElement => "Hide Focused element", - Action::SaveState => "Save Kanban state", + Action::MoveCardRight => "Move card right", + Action::MoveCardUp => "Move card up", Action::NewBoard => "Create new board", Action::NewCard => "Create new card in current board", - Action::Delete => "Delete focused element", - Action::DeleteBoard => "Delete Board", - Action::ChangeCardStatusToCompleted => "Change card status to completed", - Action::ChangeCardStatusToActive => "Change card status to active", - Action::ChangeCardStatusToStale => "Change card status to stale", + Action::NextFocus => "Focus next", + Action::OpenConfigMenu => "configure", + Action::PrvFocus => "Focus previous", + Action::Quit => "Quit", + Action::Redo => "Redo", Action::ResetUI => "Reset UI", - Action::GoToMainMenu => "Go to main menu", + Action::Right => "Go right", + Action::SaveState => "Save Kanban state", + Action::StopUserInput => "Stop input mode", + Action::TakeUserInput => "Enter input mode", Action::ToggleCommandPalette => "Open command palette", Action::Undo => "Undo", - Action::Redo => "Redo", - Action::ClearAllToasts => "Clear all toasts", + Action::Up => "Go up", }; write!(f, "{}", str) } diff --git a/src/app/app_helper.rs b/src/app/app_helper.rs index 7bdaaa7..556613a 100644 --- a/src/app/app_helper.rs +++ b/src/app/app_helper.rs @@ -526,37 +526,39 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { reset_mouse(app); if key == Key::Esc { match app.state.focus { - Focus::NewBoardName => app.state.new_board_form[0] = "".to_string(), - Focus::NewBoardDescription => app.state.new_board_form[1] = "".to_string(), - Focus::CardName => app.state.new_card_form[0] = "".to_string(), - Focus::CardDescription => app.state.new_card_form[1] = "".to_string(), - Focus::CardDueDate => app.state.new_card_form[2] = "".to_string(), + Focus::NewBoardName => app.state.app_form_states.new_board[0] = "".to_string(), + Focus::NewBoardDescription => app.state.app_form_states.new_board[1] = "".to_string(), + Focus::CardName => app.state.app_form_states.new_card[0] = "".to_string(), + Focus::CardDescription => app.state.app_form_states.new_card[1] = "".to_string(), + Focus::CardDueDate => app.state.app_form_states.new_card[2] = "".to_string(), Focus::EmailIDField => { if app.state.ui_mode == UiMode::Login { - app.state.login_form.0[0] = "".to_string() + app.state.app_form_states.login.0[0] = "".to_string() } else if app.state.ui_mode == UiMode::SignUp { - app.state.signup_form.0[0] = "".to_string() + app.state.app_form_states.signup.0[0] = "".to_string() } else if app.state.ui_mode == UiMode::ResetPassword { - app.state.reset_password_form.0[0] = "".to_string() + app.state.app_form_states.reset_password.0[0] = "".to_string() } } Focus::PasswordField => { if app.state.ui_mode == UiMode::Login { - app.state.login_form.0[1] = "".to_string() + app.state.app_form_states.login.0[1] = "".to_string() } else if app.state.ui_mode == UiMode::SignUp { - app.state.signup_form.0[1] = "".to_string() + app.state.app_form_states.signup.0[1] = "".to_string() } else if app.state.ui_mode == UiMode::ResetPassword { - app.state.reset_password_form.0[1] = "".to_string() + app.state.app_form_states.reset_password.0[1] = "".to_string() } } Focus::ConfirmPasswordField => { if app.state.ui_mode == UiMode::SignUp { - app.state.signup_form.0[2] = "".to_string() + app.state.app_form_states.signup.0[2] = "".to_string() } else if app.state.ui_mode == UiMode::ResetPassword { - app.state.reset_password_form.0[2] = "".to_string() + app.state.app_form_states.reset_password.0[2] = "".to_string() } } - Focus::ResetPasswordLinkField => app.state.reset_password_form.0[3] = "".to_string(), + Focus::ResetPasswordLinkField => { + app.state.app_form_states.reset_password.0[3] = "".to_string() + } _ => app.state.current_user_input = "".to_string(), } if app.state.popup_mode.is_some() { @@ -762,7 +764,8 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { card_being_edited.1.tags.push(String::new()); app.state.current_cursor_position = Some(0); app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(card_being_edited.1.tags.len() - 1)); return AppReturn::Continue; } @@ -770,7 +773,8 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { card_being_edited.1.comments.push(String::new()); app.state.current_cursor_position = Some(0); app.state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .select(Some(card_being_edited.1.comments.len() - 1)); return AppReturn::Continue; } @@ -792,15 +796,21 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { }, Key::Tab => { handle_next_focus(app); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; return AppReturn::Continue; } Key::BackTab => { handle_prv_focus(app); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; return AppReturn::Continue; } @@ -833,9 +843,15 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { ); } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { let selected_tag_index = - app.state.card_view_tag_list_state.selected(); + app.state.app_list_states.card_view_tag_list.selected(); if selected_tag_index.is_some() && card_being_edited .1 @@ -844,7 +860,8 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { .is_none() { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(card_being_edited.1.tags.len() - 1)); return AppReturn::Continue; } @@ -864,12 +881,18 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { .is_none() { if card_being_edited.1.tags.is_empty() { - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_tag_list + .select(None); app.send_warning_toast("No tag selected press or to select a tag", None); } else { - app.state.card_view_tag_list_state.select( - Some(card_being_edited.1.tags.len() - 1), - ); + app.state + .app_list_states + .card_view_tag_list + .select(Some( + card_being_edited.1.tags.len() - 1, + )); } return AppReturn::Continue; } @@ -887,9 +910,18 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { - let selected_comment_index = - app.state.card_view_comment_list_state.selected(); + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { + let selected_comment_index = app + .state + .app_list_states + .card_view_comment_list + .selected(); if selected_comment_index.is_some() && card_being_edited .1 @@ -898,12 +930,18 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { .is_none() { if card_being_edited.1.comments.is_empty() { - app.state.card_view_comment_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); app.send_warning_toast("No comment selected press or to select a comment", None); } else { - app.state.card_view_comment_list_state.select( - Some(card_being_edited.1.comments.len() - 1), - ); + app.state + .app_list_states + .card_view_comment_list + .select(Some( + card_being_edited.1.comments.len() - 1, + )); } return AppReturn::Continue; } @@ -961,9 +999,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { ); } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let tag = card_being_edited.1.tags.get_mut(selected_tag); if tag.is_some() { let tag = tag.unwrap(); @@ -989,10 +1037,17 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let selected_comment = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); let comment = @@ -1052,9 +1107,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { ); } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let tag = card_being_edited.1.tags.get_mut(selected_tag); if tag.is_some() { let tag = tag.unwrap(); @@ -1075,10 +1140,17 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let selected_comment = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); let comment = @@ -1142,9 +1214,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { app.state.current_cursor_position = Some(0); } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let tag = card_being_edited.1.tags.get(selected_tag); if tag.is_some() { app.state.current_cursor_position = Some(0); @@ -1154,10 +1236,17 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let selected_comment = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); let comment = @@ -1208,9 +1297,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Some(card_being_edited.1.due_date.len()); } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let tag = card_being_edited.1.tags.get(selected_tag); if tag.is_some() { app.state.current_cursor_position = @@ -1221,10 +1320,17 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let selected_comment = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); let comment = @@ -1244,31 +1350,51 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Key::ShiftRight => { match app.state.focus { Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); if card_being_edited.1.tags.is_empty() { return AppReturn::Continue; } - let selected_tag_index = - app.state.card_view_tag_list_state.selected().unwrap(); + let selected_tag_index = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); if selected_tag_index < card_being_edited.1.tags.len() - 1 { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(selected_tag_index + 1)); } } else { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); if !card_being_edited.1.tags.is_empty() { - app.state.card_view_tag_list_state.select(Some(0)); + app.state + .app_list_states + .card_view_tag_list + .select(Some(0)); } } app.state.current_cursor_position = None; return AppReturn::Continue; } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); if card_being_edited.1.comments.is_empty() { @@ -1276,21 +1402,26 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { } let selected_comment_index = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); if selected_comment_index < card_being_edited.1.comments.len() - 1 { app.state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .select(Some(selected_comment_index + 1)); } } else { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); if !card_being_edited.1.comments.is_empty() { - app.state.card_view_comment_list_state.select(Some(0)); + app.state + .app_list_states + .card_view_comment_list + .select(Some(0)); } } app.state.current_cursor_position = None; @@ -1303,12 +1434,23 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Key::ShiftLeft => { match app.state.focus { Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag_index = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag_index = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); if selected_tag_index > 0 { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(selected_tag_index - 1)); } } else { @@ -1316,7 +1458,8 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { app.state.card_being_edited.as_mut().unwrap(); if !card_being_edited.1.tags.is_empty() { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(card_being_edited.1.tags.len() - 1)); } } @@ -1324,24 +1467,35 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { return AppReturn::Continue; } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let selected_comment_index = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); if selected_comment_index > 0 { app.state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .select(Some(selected_comment_index - 1)); } } else { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); if !card_being_edited.1.comments.is_empty() { - app.state.card_view_comment_list_state.select(Some( - card_being_edited.1.comments.len() - 1, - )); + app.state + .app_list_states + .card_view_comment_list + .select(Some( + card_being_edited.1.comments.len() - 1, + )); } } app.state.current_cursor_position = None; @@ -1354,22 +1508,37 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Key::Delete => { match app.state.focus { Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); - let selected_tag_index = - app.state.card_view_tag_list_state.selected().unwrap(); + let selected_tag_index = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); card_being_edited.1.tags.remove(selected_tag_index); if selected_tag_index < card_being_edited.1.tags.len() { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(selected_tag_index)); } else if selected_tag_index > 0 { app.state - .card_view_tag_list_state + .app_list_states + .card_view_tag_list .select(Some(selected_tag_index - 1)); } else { - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_tag_list + .select(None); } } else { app.send_warning_toast("No tag selected, press or to select a tag", None); @@ -1378,12 +1547,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { return AppReturn::Continue; } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { let card_being_edited = app.state.card_being_edited.as_mut().unwrap(); let selected_comment_index = app .state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .selected() .unwrap(); card_being_edited.1.comments.remove(selected_comment_index); @@ -1391,14 +1567,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { < card_being_edited.1.comments.len() { app.state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .select(Some(selected_comment_index)); } else if selected_comment_index > 0 { app.state - .card_view_comment_list_state + .app_list_states + .card_view_comment_list .select(Some(selected_comment_index - 1)); } else { - app.state.card_view_comment_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); } } else { app.send_warning_toast("No comment selected, press or to select a comment", None); @@ -1544,13 +1725,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::NewBoardName => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.new_board_form[0], + &mut app.state.app_form_states.new_board[0], ); } Focus::NewBoardDescription => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.new_board_form[1], + &mut app.state.app_form_states.new_board[1], ); } _ => { @@ -1564,19 +1745,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardName => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.new_card_form[0], + &mut app.state.app_form_states.new_card[0], ); } Focus::CardDescription => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.new_card_form[1], + &mut app.state.app_form_states.new_card[1], ); } Focus::CardDueDate => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.new_card_form[2], + &mut app.state.app_form_states.new_card[2], ); } _ => { @@ -1590,13 +1771,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.login_form.0[0], + &mut app.state.app_form_states.login.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.login_form.0[1], + &mut app.state.app_form_states.login.0[1], ); } _ => { @@ -1610,19 +1791,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.signup_form.0[0], + &mut app.state.app_form_states.signup.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.signup_form.0[1], + &mut app.state.app_form_states.signup.0[1], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.signup_form.0[2], + &mut app.state.app_form_states.signup.0[2], ); } _ => { @@ -1636,25 +1817,25 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[0], + &mut app.state.app_form_states.reset_password.0[0], ); } Focus::ResetPasswordLinkField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[1], + &mut app.state.app_form_states.reset_password.0[1], ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[2], + &mut app.state.app_form_states.reset_password.0[2], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_backspace( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[3], + &mut app.state.app_form_states.reset_password.0[3], ); } _ => { @@ -1679,13 +1860,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::NewBoardName => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.new_board_form[0], + &app.state.app_form_states.new_board[0], ); } Focus::NewBoardDescription => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.new_board_form[1], + &app.state.app_form_states.new_board[1], ); } _ => { @@ -1699,19 +1880,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardName => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.new_card_form[0], + &app.state.app_form_states.new_card[0], ); } Focus::CardDescription => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.new_card_form[1], + &app.state.app_form_states.new_card[1], ); } Focus::CardDueDate => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.new_card_form[2], + &app.state.app_form_states.new_card[2], ); } _ => { @@ -1725,13 +1906,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.login_form.0[0], + &app.state.app_form_states.login.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.login_form.0[1], + &app.state.app_form_states.login.0[1], ); } _ => { @@ -1745,19 +1926,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.signup_form.0[0], + &app.state.app_form_states.signup.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.signup_form.0[1], + &app.state.app_form_states.signup.0[1], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.signup_form.0[2], + &app.state.app_form_states.signup.0[2], ); } _ => { @@ -1771,25 +1952,25 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.reset_password_form.0[0], + &app.state.app_form_states.reset_password.0[0], ); } Focus::ResetPasswordLinkField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.reset_password_form.0[1], + &app.state.app_form_states.reset_password.0[1], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.reset_password_form.0[2], + &app.state.app_form_states.reset_password.0[2], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = move_cursor_left( app.state.current_cursor_position, - &app.state.reset_password_form.0[3], + &app.state.app_form_states.reset_password.0[3], ); } _ => { @@ -1814,13 +1995,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::NewBoardName => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.new_board_form[0], + &app.state.app_form_states.new_board[0], ); } Focus::NewBoardDescription => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.new_board_form[1], + &app.state.app_form_states.new_board[1], ); } _ => { @@ -1834,19 +2015,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardName => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.new_card_form[0], + &app.state.app_form_states.new_card[0], ); } Focus::CardDescription => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.new_card_form[1], + &app.state.app_form_states.new_card[1], ); } Focus::CardDueDate => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.new_card_form[2], + &app.state.app_form_states.new_card[2], ); } _ => { @@ -1860,13 +2041,13 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.login_form.0[0], + &app.state.app_form_states.login.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.login_form.0[1], + &app.state.app_form_states.login.0[1], ); } _ => { @@ -1880,19 +2061,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.signup_form.0[0], + &app.state.app_form_states.signup.0[0], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.signup_form.0[1], + &app.state.app_form_states.signup.0[1], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.signup_form.0[2], + &app.state.app_form_states.signup.0[2], ); } _ => { @@ -1906,25 +2087,25 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.reset_password_form.0[0], + &app.state.app_form_states.reset_password.0[0], ); } Focus::ResetPasswordLinkField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.reset_password_form.0[1], + &app.state.app_form_states.reset_password.0[1], ); } Focus::PasswordField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.reset_password_form.0[2], + &app.state.app_form_states.reset_password.0[2], ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = move_cursor_right( app.state.current_cursor_position, - &app.state.reset_password_form.0[3], + &app.state.app_form_states.reset_password.0[3], ); } _ => { @@ -1999,11 +2180,11 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { UiMode::NewBoard => match app.state.focus { Focus::NewBoardName => { app.state.current_cursor_position = - Some(app.state.new_board_form[0].len()); + Some(app.state.app_form_states.new_board[0].len()); } Focus::NewBoardDescription => { app.state.current_cursor_position = - Some(app.state.new_board_form[1].len()); + Some(app.state.app_form_states.new_board[1].len()); } _ => { app.state.current_cursor_position = @@ -2013,15 +2194,15 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { UiMode::NewCard => match app.state.focus { Focus::CardName => { app.state.current_cursor_position = - Some(app.state.new_card_form[0].len()); + Some(app.state.app_form_states.new_card[0].len()); } Focus::CardDescription => { app.state.current_cursor_position = - Some(app.state.new_card_form[1].len()); + Some(app.state.app_form_states.new_card[1].len()); } Focus::CardDueDate => { app.state.current_cursor_position = - Some(app.state.new_card_form[2].len()); + Some(app.state.app_form_states.new_card[2].len()); } _ => { app.state.current_cursor_position = @@ -2031,11 +2212,11 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { UiMode::Login => match app.state.focus { Focus::EmailIDField => { app.state.current_cursor_position = - Some(app.state.login_form.0[0].len()); + Some(app.state.app_form_states.login.0[0].len()); } Focus::PasswordField => { app.state.current_cursor_position = - Some(app.state.login_form.0[1].len()); + Some(app.state.app_form_states.login.0[1].len()); } _ => { app.state.current_cursor_position = @@ -2045,15 +2226,15 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { UiMode::SignUp => match app.state.focus { Focus::EmailIDField => { app.state.current_cursor_position = - Some(app.state.signup_form.0[0].len()); + Some(app.state.app_form_states.signup.0[0].len()); } Focus::PasswordField => { app.state.current_cursor_position = - Some(app.state.signup_form.0[1].len()); + Some(app.state.app_form_states.signup.0[1].len()); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = - Some(app.state.signup_form.0[2].len()); + Some(app.state.app_form_states.signup.0[2].len()); } _ => { app.state.current_cursor_position = @@ -2063,19 +2244,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { UiMode::ResetPassword => match app.state.focus { Focus::EmailIDField => { app.state.current_cursor_position = - Some(app.state.reset_password_form.0[0].len()); + Some(app.state.app_form_states.reset_password.0[0].len()); } Focus::ResetPasswordLinkField => { app.state.current_cursor_position = - Some(app.state.reset_password_form.0[1].len()); + Some(app.state.app_form_states.reset_password.0[1].len()); } Focus::PasswordField => { app.state.current_cursor_position = - Some(app.state.reset_password_form.0[2].len()); + Some(app.state.app_form_states.reset_password.0[2].len()); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = - Some(app.state.reset_password_form.0[3].len()); + Some(app.state.app_form_states.reset_password.0[3].len()); } _ => { app.state.current_cursor_position = @@ -2140,9 +2321,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardTags => { let mut current_cursor_position = app.state.current_cursor_position.unwrap_or(0); - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_tag = - app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let mut tag = card_being_edited.1.tags.get_mut(selected_tag); if tag.is_some() { let tag = tag.as_mut().unwrap(); @@ -2162,9 +2353,19 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardComments => { let mut current_cursor_position = app.state.current_cursor_position.unwrap_or(0); - if app.state.card_view_comment_list_state.selected().is_some() { - let selected_comment = - app.state.card_view_comment_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { + let selected_comment = app + .state + .app_list_states + .card_view_comment_list + .selected() + .unwrap(); let mut comment = card_being_edited.1.comments.get_mut(selected_comment); if comment.is_some() { @@ -2209,14 +2410,14 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::NewBoardName => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.new_board_form[0], + &mut app.state.app_form_states.new_board[0], current_key, ); } Focus::NewBoardDescription => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.new_board_form[1], + &mut app.state.app_form_states.new_board[1], current_key, ); } @@ -2232,21 +2433,21 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::CardName => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.new_card_form[0], + &mut app.state.app_form_states.new_card[0], current_key, ); } Focus::CardDescription => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.new_card_form[1], + &mut app.state.app_form_states.new_card[1], current_key, ); } Focus::CardDueDate => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.new_card_form[2], + &mut app.state.app_form_states.new_card[2], current_key, ); } @@ -2262,14 +2463,14 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.login_form.0[0], + &mut app.state.app_form_states.login.0[0], current_key, ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.login_form.0[1], + &mut app.state.app_form_states.login.0[1], current_key, ); } @@ -2285,21 +2486,21 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.signup_form.0[0], + &mut app.state.app_form_states.signup.0[0], current_key, ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.signup_form.0[1], + &mut app.state.app_form_states.signup.0[1], current_key, ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.signup_form.0[2], + &mut app.state.app_form_states.signup.0[2], current_key, ); } @@ -2315,28 +2516,28 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { Focus::EmailIDField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[0], + &mut app.state.app_form_states.reset_password.0[0], current_key, ); } Focus::ResetPasswordLinkField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[1], + &mut app.state.app_form_states.reset_password.0[1], current_key, ); } Focus::PasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[2], + &mut app.state.app_form_states.reset_password.0[2], current_key, ); } Focus::ConfirmPasswordField => { app.state.current_cursor_position = handle_cursor_pos_for_insert_string( app.state.current_cursor_position, - &mut app.state.reset_password_form.0[3], + &mut app.state.app_form_states.reset_password.0[3], current_key, ); } @@ -2361,7 +2562,7 @@ pub async fn handle_user_input_mode(app: &mut App<'_>, key: Key) -> AppReturn { AppReturn::Continue } -pub async fn handle_keybinding_mode(app: &mut App<'_>, key: Key) -> AppReturn { +pub async fn handle_edit_keybinding_mode(app: &mut App<'_>, key: Key) -> AppReturn { match key { Key::Esc => { app.state.app_status = AppStatus::Initialized; @@ -2388,10 +2589,7 @@ pub async fn handle_keybinding_mode(app: &mut App<'_>, key: Key) -> AppReturn { pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { if let Some(action) = app.actions.find(key, &app.config) { match action { - Action::Quit => { - handle_exit(app).await; - AppReturn::Exit - } + Action::Quit => handle_exit(app).await, Action::NextFocus => { handle_next_focus(app); AppReturn::Continue @@ -2441,7 +2639,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { _ => { app.state.prev_ui_mode = Some(app.state.ui_mode); app.state.ui_mode = UiMode::ConfigMenu; - if app.state.config_state.selected().is_none() { + if app.state.app_table_states.config.selected().is_none() { app.config_next() } let available_focus_targets = app.state.ui_mode.get_available_targets(); @@ -3044,7 +3242,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { let current_ui_mode = app.state.ui_mode; if current_ui_mode == UiMode::Zen { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else if current_ui_mode == UiMode::TitleBody { @@ -3053,7 +3251,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Body; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3063,7 +3261,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Body; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3073,7 +3271,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Body; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3086,7 +3284,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Title; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3099,7 +3297,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Title; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3115,7 +3313,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Title; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3128,7 +3326,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.focus = Focus::Body; } else { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -3145,7 +3343,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { if UiMode::view_modes().contains(&app.state.ui_mode) { reset_new_board_form(app); app.set_ui_mode(UiMode::NewBoard); - app.state.previous_focus = Some(app.state.focus); + app.state.prev_focus = Some(app.state.focus); } AppReturn::Continue } @@ -3158,7 +3356,7 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { } reset_new_card_form(app); app.set_ui_mode(UiMode::NewCard); - app.state.previous_focus = Some(app.state.focus); + app.state.prev_focus = Some(app.state.focus); } AppReturn::Continue } @@ -3345,8 +3543,8 @@ pub async fn handle_general_actions(app: &mut App<'_>, key: Key) -> AppReturn { app.state.current_card_id = None; app.state.focus = Focus::MainMenu; app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { - app.state.main_menu_state.select(Some(0)); + if app.state.app_list_states.main_menu.selected().is_none() { + app.state.app_list_states.main_menu.select(Some(0)); } AppReturn::Continue } @@ -4315,7 +4513,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR } else if app.state.mouse_focus == Some(Focus::CloseButton) { app.state.filter_tags = None; app.state.all_available_tags = None; - app.state.filter_by_tag_list_state.select(None); + app.state.app_list_states.filter_by_tag_list.select(None); app.state.popup_mode = None; } else if app.state.mouse_focus == Some(Focus::SubmitButton) { handle_filter_by_tag(app); @@ -4339,8 +4537,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.popup_mode = Some(PopupMode::ViewCard); app.state.focus = Focus::CardName; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up && app.state.mouse_focus == Some(Focus::Body) { scroll_up(app); @@ -4356,7 +4553,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::TitleBody); @@ -4364,8 +4561,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.popup_mode = Some(PopupMode::ViewCard); app.state.focus = Focus::CardName; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up && app.state.mouse_focus == Some(Focus::Body) { scroll_up(app); @@ -4386,8 +4582,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.ui_mode = UiMode::HelpMenu; app.state.prev_ui_mode = Some(UiMode::BodyHelp); } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up { if app.state.mouse_focus == Some(Focus::Body) { @@ -4416,8 +4611,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.ui_mode = UiMode::LogsOnly; app.state.prev_ui_mode = Some(UiMode::BodyLog); } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up && app.state.mouse_focus == Some(Focus::Body) { scroll_up(app); @@ -4433,7 +4627,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::TitleBodyHelp); @@ -4444,8 +4638,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.popup_mode = Some(PopupMode::ViewCard); app.state.focus = Focus::CardName; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up { if app.state.mouse_focus == Some(Focus::Body) { @@ -4469,7 +4662,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::TitleBodyLog); @@ -4480,8 +4673,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.popup_mode = Some(PopupMode::ViewCard); app.state.focus = Focus::CardName; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up && app.state.mouse_focus == Some(Focus::Body) { scroll_up(app); @@ -4497,7 +4689,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::TitleBodyHelpLog); @@ -4511,8 +4703,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.popup_mode = Some(PopupMode::ViewCard); app.state.focus = Focus::CardName; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up { if app.state.mouse_focus == Some(Focus::Body) { @@ -4544,8 +4735,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR app.state.ui_mode = UiMode::LogsOnly; app.state.prev_ui_mode = Some(UiMode::BodyHelpLog); } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } else if mouse_scroll_up { if app.state.mouse_focus == Some(Focus::Body) { @@ -4569,7 +4759,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::ConfigMenu); @@ -4602,7 +4792,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if left_button_pressed { if app.state.mouse_focus == Some(Focus::Title) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next() } app.state.prev_ui_mode = Some(UiMode::EditKeybindings); @@ -4635,8 +4825,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR } else if app.state.mouse_focus == Some(Focus::MainMenu) { return handle_main_menu_action(app).await; } else if app.state.mouse_focus == Some(Focus::CloseButton) { - handle_exit(app).await; - return AppReturn::Exit; + return handle_exit(app).await; } } } @@ -4691,7 +4880,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if app.state.mouse_focus == Some(Focus::CloseButton) { handle_go_to_prv_ui_mode(app); } else if app.state.mouse_focus == Some(Focus::LoadSave) - && app.state.load_save_state.selected().is_some() + && app.state.app_list_states.load_save.selected().is_some() { app.dispatch(IoEvent::LoadLocalPreview).await; } @@ -4732,7 +4921,7 @@ pub async fn handle_mouse_action(app: &mut App<'_>, mouse_action: Mouse) -> AppR if app.state.mouse_focus == Some(Focus::CloseButton) { handle_go_to_prv_ui_mode(app); } else if app.state.mouse_focus == Some(Focus::LoadSave) - && app.state.load_save_state.selected().is_some() + && app.state.app_list_states.load_save.selected().is_some() && app.state.cloud_data.is_some() { app.dispatch(IoEvent::LoadCloudPreview).await; @@ -4748,7 +4937,7 @@ fn handle_config_menu_action(app: &mut App) -> AppReturn { if app.state.focus == Focus::SubmitButton { app.config = AppConfig::default(); app.state.focus = Focus::ConfigTable; - app.state.config_state.select(Some(0)); + app.state.app_table_states.config.select(Some(0)); let write_config_status = write_config(&app.config); if write_config_status.is_err() { error!( @@ -4773,7 +4962,7 @@ fn handle_config_menu_action(app: &mut App) -> AppReturn { app.config = AppConfig::default(); app.config.keybindings = keybindings; app.state.focus = Focus::ConfigTable; - app.state.config_state.select(Some(0)); + app.state.app_table_states.config.select(Some(0)); let write_config_status = write_config(&app.config); if write_config_status.is_err() { error!( @@ -4793,7 +4982,8 @@ fn handle_config_menu_action(app: &mut App) -> AppReturn { } return AppReturn::Continue; } - app.state.config_item_being_edited = Some(app.state.config_state.selected().unwrap_or(0)); + app.state.config_item_being_edited = + Some(app.state.app_table_states.config.selected().unwrap_or(0)); let app_config_list = &app.config.to_view_list(); if app.state.config_item_being_edited.unwrap_or(0) < app_config_list.len() { let default_config_item = String::from(""); @@ -4802,11 +4992,17 @@ fn handle_config_menu_action(app: &mut App) -> AppReturn { .unwrap_or(&default_config_item); if *config_item == "Edit Keybindings" { app.state.ui_mode = UiMode::EditKeybindings; - if app.state.edit_keybindings_state.selected().is_none() { + if app + .state + .app_table_states + .edit_keybindings + .selected() + .is_none() + { app.edit_keybindings_next(); } } else if *config_item == "Select Default View" { - if app.state.default_view_state.selected().is_none() { + if app.state.app_list_states.default_view.selected().is_none() { app.select_default_view_next(); } app.state.popup_mode = Some(PopupMode::SelectDefaultView); @@ -4971,18 +5167,15 @@ fn handle_config_menu_action(app: &mut App) -> AppReturn { } async fn handle_main_menu_action(app: &mut App<'_>) -> AppReturn { - if app.state.main_menu_state.selected().is_some() { - let selected_index = app.state.main_menu_state.selected().unwrap(); + if app.state.app_list_states.main_menu.selected().is_some() { + let selected_index = app.state.app_list_states.main_menu.selected().unwrap(); let selected_item = app.main_menu.from_index(selected_index); match selected_item { - MainMenuItem::Quit => { - handle_exit(app).await; - return AppReturn::Exit; - } + MainMenuItem::Quit => return handle_exit(app).await, MainMenuItem::Config => { app.state.prev_ui_mode = Some(UiMode::MainMenu); app.state.ui_mode = UiMode::ConfigMenu; - if app.state.config_state.selected().is_none() { + if app.state.app_table_states.config.selected().is_none() { app.config_next(); } } @@ -5013,7 +5206,12 @@ async fn handle_main_menu_action(app: &mut App<'_>) -> AppReturn { fn handle_default_view_selection(app: &mut App) { let all_ui_modes = UiMode::view_modes_as_string(); - let current_selected_mode = app.state.default_view_state.selected().unwrap_or(0); + let current_selected_mode = app + .state + .app_list_states + .default_view + .selected() + .unwrap_or(0); if current_selected_mode < all_ui_modes.len() { let selected_mode = &all_ui_modes[current_selected_mode]; app.config.default_view = UiMode::from_string(selected_mode).unwrap_or(UiMode::MainMenu); @@ -5038,8 +5236,8 @@ fn handle_default_view_selection(app: &mut App) { app.send_info_toast("Config updated Successfully", None); } - app.state.default_view_state.select(Some(0)); - if app.state.config_state.selected().is_none() { + app.state.app_list_states.default_view.select(Some(0)); + if app.state.app_table_states.config.selected().is_none() { app.config_next(); } if app.state.popup_mode.is_some() { @@ -5055,7 +5253,12 @@ fn handle_default_view_selection(app: &mut App) { fn handle_change_date_format(app: &mut App) { let all_date_formats = DateFormat::get_all_date_formats(); - let current_selected_format = app.state.date_format_selector_state.selected().unwrap_or(0); + let current_selected_format = app + .state + .app_list_states + .date_format_selector + .selected() + .unwrap_or(0); if current_selected_format < all_date_formats.len() { let selected_format = &all_date_formats[current_selected_format]; app.config.date_format = *selected_format; @@ -5083,8 +5286,11 @@ fn handle_change_date_format(app: &mut App) { app.send_info_toast("Config updated Successfully", None); } - app.state.date_format_selector_state.select(Some(0)); - if app.state.config_state.selected().is_none() { + app.state + .app_list_states + .date_format_selector + .select(Some(0)); + if app.state.app_table_states.config.selected().is_none() { app.config_next(); } if app.state.popup_mode.is_some() { @@ -5099,7 +5305,12 @@ fn handle_change_date_format(app: &mut App) { } fn handle_change_ui_mode(app: &mut App) { - let current_index = app.state.default_view_state.selected().unwrap_or(0); + let current_index = app + .state + .app_list_states + .default_view + .selected() + .unwrap_or(0); let all_ui_modes = UiMode::view_modes_as_string() .iter() .filter_map(|s| UiMode::from_string(s)) @@ -5115,7 +5326,12 @@ fn handle_change_ui_mode(app: &mut App) { } fn handle_edit_keybindings_action(app: &mut App) { - if app.state.edit_keybindings_state.selected().is_some() + if app + .state + .app_table_states + .edit_keybindings + .selected() + .is_some() && app.state.focus != Focus::SubmitButton { app.state.popup_mode = Some(PopupMode::EditSpecificKeyBinding); @@ -5124,7 +5340,7 @@ fn handle_edit_keybindings_action(app: &mut App) { warn!("Reset keybindings to default"); app.send_warning_toast("Reset keybindings to default", None); app.state.focus = Focus::NoFocus; - app.state.edit_keybindings_state.select(None); + app.state.app_table_states.edit_keybindings.select(None); let write_config_status = write_config(&app.config); if let Err(error_message) = write_config_status { error!("Error writing config: {}", error_message); @@ -5142,7 +5358,7 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { app.state.popup_mode = None; } else { app.state.ui_mode = UiMode::ConfigMenu; - if app.state.config_state.selected().is_none() { + if app.state.app_table_states.config.selected().is_none() { app.config_next() } } @@ -5151,7 +5367,13 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { } PopupMode::EditSpecificKeyBinding => { app.state.ui_mode = UiMode::EditKeybindings; - if app.state.edit_keybindings_state.selected().is_none() { + if app + .state + .app_table_states + .edit_keybindings + .selected() + .is_none() + { app.edit_keybindings_next(); } } @@ -5194,7 +5416,7 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { PopupMode::FilterByTag => { app.state.filter_tags = None; app.state.all_available_tags = None; - app.state.filter_by_tag_list_state.select(None); + app.state.app_list_states.filter_by_tag_list.select(None); } PopupMode::ChangeTheme => { let config_theme = { @@ -5229,27 +5451,24 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { } AppReturn::Continue } - UiMode::MainMenu => { - handle_exit(app).await; - AppReturn::Exit - } + UiMode::MainMenu => handle_exit(app).await, UiMode::EditKeybindings => { app.state.ui_mode = UiMode::ConfigMenu; - if app.state.config_state.selected().is_none() { + if app.state.app_table_states.config.selected().is_none() { app.config_next() } AppReturn::Continue } UiMode::LoadLocalSave => { - app.state.load_save_state = ListState::default(); + app.state.app_list_states.load_save = ListState::default(); if app.state.prev_ui_mode == Some(app.state.ui_mode) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else { app.state.ui_mode = *app.state.prev_ui_mode.as_ref().unwrap_or(&UiMode::MainMenu); - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -5259,12 +5478,12 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { reset_login_form(app); if app.state.prev_ui_mode == Some(app.state.ui_mode) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else { app.state.ui_mode = *app.state.prev_ui_mode.as_ref().unwrap_or(&UiMode::MainMenu); - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -5274,12 +5493,12 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { reset_signup_form(app); if app.state.prev_ui_mode == Some(app.state.ui_mode) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else { app.state.ui_mode = *app.state.prev_ui_mode.as_ref().unwrap_or(&UiMode::MainMenu); - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -5289,12 +5508,12 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { reset_reset_password_form(app); if app.state.prev_ui_mode == Some(app.state.ui_mode) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else { app.state.ui_mode = *app.state.prev_ui_mode.as_ref().unwrap_or(&UiMode::MainMenu); - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -5303,12 +5522,12 @@ pub async fn handle_go_to_previous_ui_mode(app: &mut App<'_>) -> AppReturn { _ => { if app.state.prev_ui_mode == Some(app.state.ui_mode) { app.state.ui_mode = UiMode::MainMenu; - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } else { app.state.ui_mode = *app.state.prev_ui_mode.as_ref().unwrap_or(&UiMode::MainMenu); - if app.state.main_menu_state.selected().is_none() { + if app.state.app_list_states.main_menu.selected().is_none() { app.main_menu_next(); } } @@ -5321,7 +5540,12 @@ fn handle_change_card_status(app: &mut App, status: Option) -> AppRe let selected_status = if let Some(status) = status { status } else { - let current_index = app.state.card_status_selector_state.selected().unwrap_or(0); + let current_index = app + .state + .app_list_states + .card_status_selector + .selected() + .unwrap_or(0); let all_statuses = CardStatus::all(); let current_index = if current_index >= all_statuses.len() { @@ -5401,7 +5625,8 @@ fn handle_change_card_status(app: &mut App, status: Option) -> AppRe fn handle_change_card_priority(app: &mut App) -> AppReturn { let current_index = app .state - .card_priority_selector_state + .app_list_states + .card_priority_selector .selected() .unwrap_or(0); let all_priorities = CardPriority::all(); @@ -5443,7 +5668,7 @@ fn handle_change_card_priority(app: &mut App) -> AppReturn { } fn handle_edit_general_config(app: &mut App) { - let config_item_index = app.state.config_state.selected().unwrap_or(0); + let config_item_index = app.state.app_table_states.config.selected().unwrap_or(0); let config_item_list = AppConfig::to_view_list(&app.config); let config_item = config_item_list[config_item_index].clone(); let default_key = String::from(""); @@ -5470,26 +5695,31 @@ fn handle_edit_general_config(app: &mut App) { app.send_info_toast("Config updated Successfully", None); } - app.state.config_state.select(Some(0)); + app.state.app_table_states.config.select(Some(0)); app.state.config_item_being_edited = None; app.state.current_user_input = String::new(); app.state.current_cursor_position = None; app.state.ui_mode = UiMode::ConfigMenu; - if app.state.config_state.selected().is_none() { + if app.state.app_table_states.config.selected().is_none() { app.config_next(); } refresh_visible_boards_and_cards(app); } - app.state.config_state.select(Some(0)); + app.state.app_table_states.config.select(Some(0)); } fn handle_edit_specific_keybinding(app: &mut App) { if app.state.edited_keybinding.is_some() { - let selected = app.state.edit_keybindings_state.selected().unwrap(); + let selected = app + .state + .app_table_states + .edit_keybindings + .selected() + .unwrap(); if selected < app.config.keybindings.iter().count() { let result = app.config.edit_keybinding( selected, - app.state.edited_keybinding.clone().unwrap_or(vec![]), + app.state.edited_keybinding.clone().unwrap_or_default(), ); if let Err(e) = result { app.send_error_toast(&format!("Error editing Keybinding: {}", e), None); @@ -5500,7 +5730,7 @@ fn handle_edit_specific_keybinding(app: &mut App) { } let (key, _) = key_list[selected]; let key_string = key.to_string(); - let value = app.state.edited_keybinding.clone().unwrap_or(vec![]); + let value = app.state.edited_keybinding.clone().unwrap_or_default(); let value = value .iter() .map(|s| s.to_string()) @@ -5515,10 +5745,16 @@ fn handle_edit_specific_keybinding(app: &mut App) { error!("Selected Keybinding with id {} not found", selected); app.send_error_toast("Selected Keybinding not found", None); app.state.edited_keybinding = None; - app.state.edit_keybindings_state.select(None); + app.state.app_table_states.edit_keybindings.select(None); } app.state.ui_mode = UiMode::EditKeybindings; - if app.state.edit_keybindings_state.selected().is_none() { + if app + .state + .app_table_states + .edit_keybindings + .selected() + .is_none() + { app.edit_keybindings_next() } app.state.edited_keybinding = None; @@ -5529,7 +5765,13 @@ fn handle_edit_specific_keybinding(app: &mut App) { } } else { app.state.ui_mode = UiMode::EditKeybindings; - if app.state.edit_keybindings_state.selected().is_none() { + if app + .state + .app_table_states + .edit_keybindings + .selected() + .is_none() + { app.edit_keybindings_next() } } @@ -5538,9 +5780,9 @@ fn handle_edit_specific_keybinding(app: &mut App) { fn handle_new_board_action(app: &mut App) { if app.state.focus == Focus::SubmitButton { - let new_board_name = app.state.new_board_form[0].clone(); + let new_board_name = app.state.app_form_states.new_board[0].clone(); let new_board_name = new_board_name.trim(); - let new_board_description = app.state.new_board_form[1].clone(); + let new_board_description = app.state.app_form_states.new_board[1].clone(); let new_board_description = new_board_description.trim(); let mut same_name_exists = false; for board in app.boards.iter() { @@ -5569,7 +5811,7 @@ fn handle_new_board_action(app: &mut App) { .prev_ui_mode .as_ref() .unwrap_or(&app.config.default_view); - if let Some(previous_focus) = &app.state.previous_focus { + if let Some(previous_focus) = &app.state.prev_focus { app.state.focus = *previous_focus; } refresh_visible_boards_and_cards(app); @@ -5585,11 +5827,11 @@ fn handle_new_board_action(app: &mut App) { fn handle_new_card_action(app: &mut App) -> AppReturn { if app.state.focus == Focus::SubmitButton { - let new_card_name = app.state.new_card_form[0].clone(); + let new_card_name = app.state.app_form_states.new_card[0].clone(); let new_card_name = new_card_name.trim(); - let new_card_description = app.state.new_card_form[1].clone(); + let new_card_description = app.state.app_form_states.new_card[1].clone(); let new_card_description = new_card_description.trim(); - let new_card_due_date = app.state.new_card_form[2].clone(); + let new_card_due_date = app.state.app_form_states.new_card[2].clone(); let new_card_due_date = new_card_due_date.trim(); let mut same_name_exists = false; let current_board_id = app.state.current_board_id.unwrap_or((0, 0)); @@ -5672,7 +5914,7 @@ fn handle_new_card_action(app: &mut App) -> AppReturn { app.send_warning_toast("New card name is empty or already exists", None); } - if let Some(previous_focus) = &app.state.previous_focus { + if let Some(previous_focus) = &app.state.prev_focus { app.state.focus = *previous_focus; } refresh_visible_boards_and_cards(app); @@ -5683,7 +5925,7 @@ fn handle_new_card_action(app: &mut App) -> AppReturn { if !app.filtered_boards.is_empty() { app.state.filter_tags = None; app.state.all_available_tags = None; - app.state.filter_by_tag_list_state.select(None); + app.state.app_list_states.filter_by_tag_list.select(None); app.send_warning_toast("Filter Reset", None); } AppReturn::Continue @@ -5935,7 +6177,7 @@ fn reset_mouse(app: &mut App) { fn handle_change_theme(app: &mut App, default_theme_mode: bool) -> AppReturn { if default_theme_mode { app.state.default_theme_mode = false; - let config_index = app.state.config_state.selected(); + let config_index = app.state.app_table_states.config.selected(); if config_index.is_some() { let config_item_index = &app.state.config_item_being_edited; let list_items = app.config.to_view_list(); @@ -5946,7 +6188,12 @@ fn handle_change_theme(app: &mut App, default_theme_mode: bool) -> AppReturn { "Theme Name" }; if config_item_name == "Default Theme" { - let theme_index = app.state.theme_selector_state.selected().unwrap_or(0); + let theme_index = app + .state + .app_list_states + .theme_selector + .selected() + .unwrap_or(0); if theme_index < app.all_themes.len() { let theme = app.all_themes[theme_index].clone(); app.config.default_theme = theme.name.clone(); @@ -5983,7 +6230,7 @@ fn handle_change_theme(app: &mut App, default_theme_mode: bool) -> AppReturn { AppReturn::Continue } } else { - let selected_item_index = app.state.theme_selector_state.selected(); + let selected_item_index = app.state.app_list_states.theme_selector.selected(); if selected_item_index.is_none() { debug!("No selected item index found"); app.send_error_toast("Something went wrong", None); @@ -6039,22 +6286,57 @@ fn handle_create_theme_action(app: &mut App) -> AppReturn { TextColorOptions::to_iter().collect::>(); let all_modifier_options = TextModifierOptions::to_iter().collect::>(); - if app.state.edit_specific_style_state.0.selected().is_none() { - app.state.edit_specific_style_state.0.select(Some(0)); - } - if app.state.edit_specific_style_state.1.selected().is_none() { - app.state.edit_specific_style_state.1.select(Some(0)); - } - if app.state.edit_specific_style_state.2.selected().is_none() { - app.state.edit_specific_style_state.2.select(Some(0)); - } - let selected_fg_index = app.state.edit_specific_style_state.0.selected(); - let selected_bg_index = app.state.edit_specific_style_state.1.selected(); + if app + .state + .app_list_states + .edit_specific_style + .0 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .0 + .select(Some(0)); + } + if app + .state + .app_list_states + .edit_specific_style + .1 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .1 + .select(Some(0)); + } + if app + .state + .app_list_states + .edit_specific_style + .2 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .2 + .select(Some(0)); + } + let selected_fg_index = + app.state.app_list_states.edit_specific_style.0.selected(); + let selected_bg_index = + app.state.app_list_states.edit_specific_style.1.selected(); let selected_modifier_index = - app.state.edit_specific_style_state.2.selected(); + app.state.app_list_states.edit_specific_style.2.selected(); let theme_style_bring_edited_index = - app.state.theme_editor_state.selected(); + app.state.app_table_states.theme_editor.selected(); if theme_style_bring_edited_index.is_none() { debug!("No theme style being edited index found"); app.send_error_toast("Something went wrong", None); @@ -6160,7 +6442,8 @@ fn handle_create_theme_action(app: &mut App) -> AppReturn { app.state.focus = Focus::ThemeEditor; } Focus::StyleEditorFG => { - let selected_index = app.state.edit_specific_style_state.0.selected(); + let selected_index = + app.state.app_list_states.edit_specific_style.0.selected(); if selected_index.is_none() { return AppReturn::Continue; } @@ -6177,7 +6460,8 @@ fn handle_create_theme_action(app: &mut App) -> AppReturn { } } Focus::StyleEditorBG => { - let selected_index = app.state.edit_specific_style_state.1.selected(); + let selected_index = + app.state.app_list_states.edit_specific_style.1.selected(); if selected_index.is_none() { return AppReturn::Continue; } @@ -6210,9 +6494,9 @@ fn handle_create_theme_action(app: &mut App) -> AppReturn { } app.state.popup_mode = Some(PopupMode::SaveThemePrompt); } else if app.state.focus == Focus::ThemeEditor - && app.state.theme_editor_state.selected().is_some() + && app.state.app_table_states.theme_editor.selected().is_some() { - let selected_item_index = app.state.theme_editor_state.selected().unwrap(); + let selected_item_index = app.state.app_table_states.theme_editor.selected().unwrap(); if selected_item_index == 0 { app.state.popup_mode = Some(PopupMode::EditGeneralConfig); app.state.current_user_input = String::new(); @@ -6267,13 +6551,16 @@ fn handle_next_focus(app: &mut App) { } if app.state.popup_mode == Some(PopupMode::CommandPalette) { app.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(None); app.state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .select(None); app.state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .select(None); } } @@ -6308,13 +6595,16 @@ fn handle_prv_focus(app: &mut App) { } if app.state.popup_mode == Some(PopupMode::CommandPalette) { app.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(None); app.state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .select(None); app.state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .select(None); } } @@ -6364,7 +6654,7 @@ fn handle_custom_rgb_prompt(app: &mut App, fg: bool) -> AppReturn { } let rgb_values = rgb_values.unwrap(); let all_color_options = TextColorOptions::to_iter().collect::>(); - let selected_index = app.state.edit_specific_style_state.0.selected(); + let selected_index = app.state.app_list_states.edit_specific_style.0.selected(); if selected_index.is_none() { debug!("No selected index found"); app.send_error_toast("Something went wrong", None); @@ -6374,7 +6664,7 @@ fn handle_custom_rgb_prompt(app: &mut App, fg: bool) -> AppReturn { debug!("Selected index is out of bounds"); app.send_error_toast("Something went wrong", None); } - let theme_style_bring_edited_index = app.state.theme_editor_state.selected(); + let theme_style_bring_edited_index = app.state.app_table_states.theme_editor.selected(); if theme_style_bring_edited_index.is_none() { debug!("No theme style being edited index found"); app.send_error_toast("Something went wrong", None); @@ -6408,23 +6698,34 @@ fn handle_custom_rgb_prompt(app: &mut App, fg: bool) -> AppReturn { fn handle_theme_maker_scroll_up(app: &mut App) { if app.state.focus == Focus::StyleEditorFG { - let current_index = app.state.edit_specific_style_state.0.selected(); + let current_index = app.state.app_list_states.edit_specific_style.0.selected(); let total_length = TextColorOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.0.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .0 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.0.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .0 + .selected() + .unwrap(); let selector_index = if current_index > 0 { current_index - 1 } else { total_length - 1 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .0 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextColorOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6437,23 +6738,34 @@ fn handle_theme_maker_scroll_up(app: &mut App) { ); } } else if app.state.focus == Focus::StyleEditorBG { - let current_index = app.state.edit_specific_style_state.1.selected(); + let current_index = app.state.app_list_states.edit_specific_style.1.selected(); let total_length = TextColorOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.1.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .1 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.1.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .1 + .selected() + .unwrap(); let selector_index = if current_index > 0 { current_index - 1 } else { total_length - 1 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .1 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextColorOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6466,23 +6778,34 @@ fn handle_theme_maker_scroll_up(app: &mut App) { ); } } else if app.state.focus == Focus::StyleEditorModifier { - let current_index = app.state.edit_specific_style_state.2.selected(); + let current_index = app.state.app_list_states.edit_specific_style.2.selected(); let total_length = TextModifierOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.2.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .2 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.2.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .2 + .selected() + .unwrap(); let selector_index = if current_index > 0 { current_index - 1 } else { total_length - 1 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .2 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextModifierOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6501,23 +6824,34 @@ fn handle_theme_maker_scroll_up(app: &mut App) { fn handle_theme_maker_scroll_down(app: &mut App) { if app.state.focus == Focus::StyleEditorFG { - let current_index = app.state.edit_specific_style_state.0.selected(); + let current_index = app.state.app_list_states.edit_specific_style.0.selected(); let total_length = TextColorOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.0.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .0 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.0.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .0 + .selected() + .unwrap(); let selector_index = if current_index < total_length - 1 { current_index + 1 } else { 0 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .0 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextColorOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6530,23 +6864,34 @@ fn handle_theme_maker_scroll_down(app: &mut App) { ); } } else if app.state.focus == Focus::StyleEditorBG { - let current_index = app.state.edit_specific_style_state.1.selected(); + let current_index = app.state.app_list_states.edit_specific_style.1.selected(); let total_length = TextColorOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.1.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .1 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.1.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .1 + .selected() + .unwrap(); let selector_index = if current_index < total_length - 1 { current_index + 1 } else { 0 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .1 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextColorOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6559,23 +6904,34 @@ fn handle_theme_maker_scroll_down(app: &mut App) { ); } } else if app.state.focus == Focus::StyleEditorModifier { - let current_index = app.state.edit_specific_style_state.2.selected(); + let current_index = app.state.app_list_states.edit_specific_style.2.selected(); let total_length = TextModifierOptions::to_iter().count(); if current_index.is_none() { - app.state.edit_specific_style_state.2.select(Some(0)); + app.state + .app_list_states + .edit_specific_style + .2 + .select(Some(0)); } - let current_index = app.state.edit_specific_style_state.2.selected().unwrap(); + let current_index = app + .state + .app_list_states + .edit_specific_style + .2 + .selected() + .unwrap(); let selector_index = if current_index < total_length - 1 { current_index + 1 } else { 0 }; app.state - .edit_specific_style_state + .app_list_states + .edit_specific_style .2 .select(Some(selector_index)); let theme_style_being_edited = app.state.theme_being_edited.to_vec_str() - [app.state.theme_editor_state.selected().unwrap()]; + [app.state.app_table_states.theme_editor.selected().unwrap()]; if TextModifierOptions::to_iter().nth(selector_index).is_some() { app.state.theme_being_edited = app.state.theme_being_edited.edit_style( theme_style_being_edited, @@ -6755,7 +7111,7 @@ fn open_command_palette(app: &mut App) { fn handle_filter_by_tag(app: &mut App) { match app.state.focus { Focus::FilterByTagPopup => { - let selected_index = app.state.filter_by_tag_list_state.selected(); + let selected_index = app.state.app_list_states.filter_by_tag_list.selected(); if selected_index.is_none() { return; } @@ -6834,13 +7190,17 @@ fn filter_boards(app: &mut App) { None, ); app.state.popup_mode = None; - app.state.filter_by_tag_list_state.select(None); + app.state.app_list_states.filter_by_tag_list.select(None); } fn handle_command_palette_card_selection(app: &mut App) { reset_mouse(app); refresh_visible_boards_and_cards(app); - let card_details_index = app.state.command_palette_card_search_list_state.selected(); + let card_details_index = app + .state + .app_list_states + .command_palette_card_search + .selected(); if card_details_index.is_none() { return; } @@ -6879,7 +7239,11 @@ fn handle_command_palette_card_selection(app: &mut App) { fn handle_command_palette_board_selection(app: &mut App) { reset_mouse(app); refresh_visible_boards_and_cards(app); - let board_details_index = app.state.command_palette_board_search_list_state.selected(); + let board_details_index = app + .state + .app_list_states + .command_palette_board_search + .selected(); if board_details_index.is_none() { return; } @@ -6910,46 +7274,46 @@ fn handle_command_palette_board_selection(app: &mut App) { pub async fn handle_login_submit_action(app: &mut App<'_>) { app.dispatch(IoEvent::Login( - app.state.login_form.0[0].to_string(), - app.state.login_form.0[1].to_string(), + app.state.app_form_states.login.0[0].to_string(), + app.state.app_form_states.login.0[1].to_string(), )) .await; } pub async fn handle_signup_submit_action(app: &mut App<'_>) { app.dispatch(IoEvent::SignUp( - app.state.signup_form.0[0].to_string(), - app.state.signup_form.0[1].to_string(), - app.state.signup_form.0[2].to_string(), + app.state.app_form_states.signup.0[0].to_string(), + app.state.app_form_states.signup.0[1].to_string(), + app.state.app_form_states.signup.0[2].to_string(), )) .await; } pub async fn handle_reset_password_submit_action(app: &mut App<'_>) { app.dispatch(IoEvent::ResetPassword( - app.state.reset_password_form.0[1].to_string(), - app.state.reset_password_form.0[2].to_string(), - app.state.reset_password_form.0[3].to_string(), + app.state.app_form_states.reset_password.0[1].to_string(), + app.state.app_form_states.reset_password.0[2].to_string(), + app.state.app_form_states.reset_password.0[3].to_string(), )) .await; } pub async fn handle_send_reset_password_link_action(app: &mut App<'_>) { app.dispatch(IoEvent::SendResetPasswordEmail( - app.state.reset_password_form.0[0].to_string(), + app.state.app_form_states.reset_password.0[0].to_string(), )) .await; } fn reset_new_board_form(app: &mut App) { - app.state.new_board_form = NEW_BOARD_FORM_DEFAULT_STATE + app.state.app_form_states.new_board = NEW_BOARD_FORM_DEFAULT_STATE .iter() .map(|s| s.to_string()) .collect(); } fn reset_new_card_form(app: &mut App) { - app.state.new_card_form = NEW_CARD_FORM_DEFAULT_STATE + app.state.app_form_states.new_card = NEW_CARD_FORM_DEFAULT_STATE .iter() .map(|s| s.to_string()) .collect(); @@ -6957,7 +7321,7 @@ fn reset_new_card_form(app: &mut App) { } fn reset_login_form(app: &mut App) { - app.state.login_form = ( + app.state.app_form_states.login = ( LOGIN_FORM_DEFAULT_STATE .0 .iter() @@ -6968,7 +7332,7 @@ fn reset_login_form(app: &mut App) { } fn reset_signup_form(app: &mut App) { - app.state.signup_form = ( + app.state.app_form_states.signup = ( SIGNUP_FORM_DEFAULT_STATE .0 .iter() @@ -6979,7 +7343,7 @@ fn reset_signup_form(app: &mut App) { } fn reset_reset_password_form(app: &mut App) { - app.state.reset_password_form = ( + app.state.app_form_states.reset_password = ( RESET_PASSWORD_FORM_DEFAULT_STATE .0 .iter() @@ -7008,7 +7372,7 @@ async fn handle_login_action(app: &mut App<'_>) { } } Focus::ExtraFocus => { - app.state.login_form.1 = !app.state.login_form.1; + app.state.app_form_states.login.1 = !app.state.app_form_states.login.1; } Focus::Title => { app.state.prev_ui_mode = Some(app.state.ui_mode); @@ -7047,7 +7411,7 @@ async fn handle_signup_action(app: &mut App<'_>) { } } Focus::ExtraFocus => { - app.state.signup_form.1 = !app.state.signup_form.1; + app.state.app_form_states.signup.1 = !app.state.app_form_states.signup.1; } Focus::Title => { app.state.prev_ui_mode = Some(app.state.ui_mode); @@ -7097,7 +7461,8 @@ async fn handle_reset_password_action(app: &mut App<'_>) { } } Focus::ExtraFocus => { - app.state.reset_password_form.1 = !app.state.reset_password_form.1; + app.state.app_form_states.reset_password.1 = + !app.state.app_form_states.reset_password.1; } Focus::SubmitButton => { handle_reset_password_submit_action(app).await; diff --git a/src/app/kanban.rs b/src/app/kanban.rs index f98ae89..b47b7be 100644 --- a/src/app/kanban.rs +++ b/src/app/kanban.rs @@ -7,10 +7,10 @@ use uuid::Uuid; #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct Board { + pub cards: Vec, + pub description: String, pub id: (u64, u64), pub name: String, - pub description: String, - pub cards: Vec, } impl Board { @@ -82,10 +82,10 @@ impl Board { impl Default for Board { fn default() -> Self { Self { + cards: vec![Card::default()], + description: String::from("Default Board Description"), id: get_id(), name: String::from("Default Board"), - description: String::from("Default Board Description"), - cards: vec![Card::default()], } } } @@ -115,40 +115,40 @@ impl CardStatus { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum CardPriority { + High, Low, Medium, - High, } impl fmt::Display for CardPriority { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + CardPriority::High => write!(f, "High"), CardPriority::Low => write!(f, "Low"), CardPriority::Medium => write!(f, "Medium"), - CardPriority::High => write!(f, "High"), } } } impl CardPriority { pub fn all() -> Vec { - vec![CardPriority::Low, CardPriority::Medium, CardPriority::High] + vec![CardPriority::High, CardPriority::Low, CardPriority::Medium] } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct Card { - pub id: (u64, u64), - pub name: String, - pub description: String, + pub card_status: CardStatus, + pub comments: Vec, + pub date_completed: String, pub date_created: String, pub date_modified: String, + pub description: String, pub due_date: String, - pub date_completed: String, + pub id: (u64, u64), + pub name: String, pub priority: CardPriority, - pub card_status: CardStatus, pub tags: Vec, - pub comments: Vec, } impl Card { @@ -301,17 +301,17 @@ impl Card { impl Default for Card { fn default() -> Self { Self { - id: get_id(), - name: String::from("Default Card"), - description: String::from("Default Card Description"), + card_status: CardStatus::Active, + comments: Vec::new(), + date_completed: FIELD_NOT_SET.to_string(), date_created: Utc::now().to_string(), date_modified: Utc::now().to_string(), + description: String::from("Default Card Description"), due_date: FIELD_NOT_SET.to_string(), - date_completed: FIELD_NOT_SET.to_string(), + id: get_id(), + name: String::from("Default Card"), priority: CardPriority::Low, - card_status: CardStatus::Active, tags: Vec::new(), - comments: Vec::new(), } } } diff --git a/src/app/mod.rs b/src/app/mod.rs index c663bc2..5f27bac 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,7 +1,7 @@ use self::{ actions::Actions, app_helper::{ - handle_general_actions, handle_keybinding_mode, handle_mouse_action, + handle_edit_keybinding_mode, handle_general_actions, handle_mouse_action, handle_user_input_mode, prepare_config_for_new_app, }, kanban::{Board, Card, CardPriority}, @@ -33,7 +33,6 @@ use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime}; use linked_hash_map::LinkedHashMap; use log::{debug, error, info}; use ratatui::{ - backend::Backend, widgets::{ListState, TableState}, Frame, }; @@ -148,7 +147,7 @@ impl App<'_> { if self.state.app_status == AppStatus::UserInput { handle_user_input_mode(self, key).await } else if self.state.app_status == AppStatus::KeyBindMode { - handle_keybinding_mode(self, key).await + handle_edit_keybinding_mode(self, key).await } else { handle_general_actions(self, key).await } @@ -210,10 +209,10 @@ impl App<'_> { self.state.current_user_input = String::new(); } pub fn set_config_state(&mut self, config_state: TableState) { - self.state.config_state = config_state; + self.state.app_table_states.config = config_state; } pub fn config_next(&mut self) { - let i = match self.state.config_state.selected() { + let i = match self.state.app_table_states.config.selected() { Some(i) => { if i >= self.config.to_view_list().len() - 1 { 0 @@ -223,10 +222,10 @@ impl App<'_> { } None => 0, }; - self.state.config_state.select(Some(i)); + self.state.app_table_states.config.select(Some(i)); } pub fn config_prv(&mut self) { - let i = match self.state.config_state.selected() { + let i = match self.state.app_table_states.config.selected() { Some(i) => { if i == 0 { self.config.to_view_list().len() - 1 @@ -236,10 +235,10 @@ impl App<'_> { } None => 0, }; - self.state.config_state.select(Some(i)); + self.state.app_table_states.config.select(Some(i)); } pub fn main_menu_next(&mut self) { - let i = match self.state.main_menu_state.selected() { + let i = match self.state.app_list_states.main_menu.selected() { Some(i) => { if i >= self.main_menu.all().len() - 1 { 0 @@ -249,10 +248,10 @@ impl App<'_> { } None => 0, }; - self.state.main_menu_state.select(Some(i)); + self.state.app_list_states.main_menu.select(Some(i)); } pub fn main_menu_prv(&mut self) { - let i = match self.state.main_menu_state.selected() { + let i = match self.state.app_list_states.main_menu.selected() { Some(i) => { if i == 0 { self.main_menu.items.len() - 1 @@ -262,10 +261,10 @@ impl App<'_> { } None => 0, }; - self.state.main_menu_state.select(Some(i)); + self.state.app_list_states.main_menu.select(Some(i)); } pub fn load_save_next(&mut self, cloud_mode: bool) { - let i = match self.state.load_save_state.selected() { + let i = match self.state.app_list_states.load_save.selected() { Some(i) => { if cloud_mode { let cloud_save_files = self.state.cloud_data.clone(); @@ -297,10 +296,10 @@ impl App<'_> { } None => 0, }; - self.state.load_save_state.select(Some(i)); + self.state.app_list_states.load_save.select(Some(i)); } pub fn load_save_prv(&mut self, cloud_mode: bool) { - let i = match self.state.load_save_state.selected() { + let i = match self.state.app_list_states.load_save.selected() { Some(i) => { if cloud_mode { let cloud_save_files = self.state.cloud_data.clone(); @@ -336,10 +335,10 @@ impl App<'_> { } None => 0, }; - self.state.load_save_state.select(Some(i)); + self.state.app_list_states.load_save.select(Some(i)); } pub fn config_state(&self) -> &TableState { - &self.state.config_state + &self.state.app_table_states.config } pub fn set_ui_mode(&mut self, ui_mode: UiMode) { self.state.prev_ui_mode = Some(self.state.ui_mode); @@ -355,7 +354,7 @@ impl App<'_> { } pub fn edit_keybindings_next(&mut self) { let keybinding_iterator = self.config.keybindings.iter(); - let i = match self.state.edit_keybindings_state.selected() { + let i = match self.state.app_table_states.edit_keybindings.selected() { Some(i) => { if i >= keybinding_iterator.count() - 1 { 0 @@ -365,11 +364,11 @@ impl App<'_> { } None => 0, }; - self.state.edit_keybindings_state.select(Some(i)); + self.state.app_table_states.edit_keybindings.select(Some(i)); } pub fn edit_keybindings_prv(&mut self) { let keybinding_iterator = self.config.keybindings.iter(); - let i = match self.state.edit_keybindings_state.selected() { + let i = match self.state.app_table_states.edit_keybindings.selected() { Some(i) => { if i == 0 { keybinding_iterator.count() - 1 @@ -379,10 +378,10 @@ impl App<'_> { } None => 0, }; - self.state.edit_keybindings_state.select(Some(i)); + self.state.app_table_states.edit_keybindings.select(Some(i)); } pub fn help_next(&mut self) { - let i = match self.state.help_state.selected() { + let i = match self.state.app_table_states.help.selected() { Some(i) => { if !self.state.keybinding_store.is_empty() { if i >= (self.state.keybinding_store.len() / 2) - 1 { @@ -396,10 +395,10 @@ impl App<'_> { } None => 0, }; - self.state.help_state.select(Some(i)); + self.state.app_table_states.help.select(Some(i)); } pub fn help_prv(&mut self) { - let i = match self.state.help_state.selected() { + let i = match self.state.app_table_states.help.selected() { Some(i) => { if !self.state.keybinding_store.is_empty() { if i == 0 { @@ -413,10 +412,10 @@ impl App<'_> { } None => 0, }; - self.state.help_state.select(Some(i)); + self.state.app_table_states.help.select(Some(i)); } pub fn select_default_view_next(&mut self) { - let i = match self.state.default_view_state.selected() { + let i = match self.state.app_list_states.default_view.selected() { Some(i) => { if i >= UiMode::view_modes_as_string().len() - 1 { 0 @@ -426,10 +425,10 @@ impl App<'_> { } None => 0, }; - self.state.default_view_state.select(Some(i)); + self.state.app_list_states.default_view.select(Some(i)); } pub fn select_default_view_prv(&mut self) { - let i = match self.state.default_view_state.selected() { + let i = match self.state.app_list_states.default_view.selected() { Some(i) => { if i == 0 { UiMode::view_modes_as_string().len() - 1 @@ -439,12 +438,13 @@ impl App<'_> { } None => 0, }; - self.state.default_view_state.select(Some(i)); + self.state.app_list_states.default_view.select(Some(i)); } pub fn command_palette_command_search_prv(&mut self) { let i = match self .state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .selected() { Some(i) => { @@ -466,13 +466,15 @@ impl App<'_> { None => 0, }; self.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(Some(i)); } pub fn command_palette_command_search_next(&mut self) { let i = match self .state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .selected() { Some(i) => { @@ -496,11 +498,17 @@ impl App<'_> { None => 0, }; self.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(Some(i)); } pub fn command_palette_card_search_next(&mut self) { - let i = match self.state.command_palette_card_search_list_state.selected() { + let i = match self + .state + .app_list_states + .command_palette_card_search + .selected() + { Some(i) => { if self.command_palette.card_search_results.is_some() { if i >= self @@ -522,11 +530,17 @@ impl App<'_> { None => 0, }; self.state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .select(Some(i)); } pub fn command_palette_card_search_prv(&mut self) { - let i = match self.state.command_palette_card_search_list_state.selected() { + let i = match self + .state + .app_list_states + .command_palette_card_search + .selected() + { Some(i) => { if self.command_palette.card_search_results.is_some() { if i == 0 { @@ -546,13 +560,15 @@ impl App<'_> { None => 0, }; self.state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .select(Some(i)); } pub fn command_palette_board_search_next(&mut self) { let i = match self .state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .selected() { Some(i) => { @@ -576,13 +592,15 @@ impl App<'_> { None => 0, }; self.state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .select(Some(i)); } pub fn command_palette_board_search_prv(&mut self) { let i = match self .state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .selected() { Some(i) => { @@ -604,7 +622,8 @@ impl App<'_> { None => 0, }; self.state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .select(Some(i)); } pub fn keybinding_list_maker(&mut self) { @@ -715,7 +734,7 @@ impl App<'_> { } } pub fn select_card_status_prv(&mut self) { - let i = match self.state.card_status_selector_state.selected() { + let i = match self.state.app_list_states.card_status_selector.selected() { Some(i) => { if i == 0 { CardStatus::all().len() - 1 @@ -725,10 +744,13 @@ impl App<'_> { } None => 0, }; - self.state.card_status_selector_state.select(Some(i)); + self.state + .app_list_states + .card_status_selector + .select(Some(i)); } pub fn select_card_status_next(&mut self) { - let i = match self.state.card_status_selector_state.selected() { + let i = match self.state.app_list_states.card_status_selector.selected() { Some(i) => { if i >= CardStatus::all().len() - 1 { 0 @@ -738,7 +760,10 @@ impl App<'_> { } None => 0, }; - self.state.card_status_selector_state.select(Some(i)); + self.state + .app_list_states + .card_status_selector + .select(Some(i)); } pub fn increase_loading_toast_time(&mut self, msg: &str, increase_by: Duration) { let toast = self.state.toasts.iter_mut().find(|x| x.message == msg); @@ -750,7 +775,7 @@ impl App<'_> { toast.duration += increase_by; } pub fn select_change_theme_next(&mut self) { - let i = match self.state.theme_selector_state.selected() { + let i = match self.state.app_list_states.theme_selector.selected() { Some(i) => { if i >= self.all_themes.len() - 1 { 0 @@ -760,11 +785,11 @@ impl App<'_> { } None => 0, }; - self.state.theme_selector_state.select(Some(i)); + self.state.app_list_states.theme_selector.select(Some(i)); self.current_theme = self.all_themes[i].clone(); } pub fn select_change_theme_prv(&mut self) { - let i = match self.state.theme_selector_state.selected() { + let i = match self.state.app_list_states.theme_selector.selected() { Some(i) => { if i == 0 { self.all_themes.len() - 1 @@ -774,12 +799,12 @@ impl App<'_> { } None => 0, }; - self.state.theme_selector_state.select(Some(i)); + self.state.app_list_states.theme_selector.select(Some(i)); self.current_theme = self.all_themes[i].clone(); } pub fn select_create_theme_next(&mut self) { let theme_rows_len = Theme::default().to_rows(self).1.len(); - let i = match self.state.theme_editor_state.selected() { + let i = match self.state.app_table_states.theme_editor.selected() { Some(i) => { if i >= theme_rows_len - 1 { 0 @@ -789,11 +814,11 @@ impl App<'_> { } None => 0, }; - self.state.theme_editor_state.select(Some(i)); + self.state.app_table_states.theme_editor.select(Some(i)); } pub fn select_create_theme_prv(&mut self) { let theme_rows_len = Theme::default().to_rows(self).1.len(); - let i = match self.state.theme_editor_state.selected() { + let i = match self.state.app_table_states.theme_editor.selected() { Some(i) => { if i == 0 { theme_rows_len - 1 @@ -803,10 +828,10 @@ impl App<'_> { } None => 0, }; - self.state.theme_editor_state.select(Some(i)); + self.state.app_table_states.theme_editor.select(Some(i)); } pub fn select_edit_style_fg_next(&mut self) { - let i = match self.state.edit_specific_style_state.0.selected() { + let i = match self.state.app_list_states.edit_specific_style.0.selected() { Some(i) => { if i >= TextColorOptions::to_iter().count() - 1 { 0 @@ -816,10 +841,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.0.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .0 + .select(Some(i)); } pub fn select_edit_style_fg_prv(&mut self) { - let i = match self.state.edit_specific_style_state.0.selected() { + let i = match self.state.app_list_states.edit_specific_style.0.selected() { Some(i) => { if i == 0 { TextColorOptions::to_iter().count() - 1 @@ -829,10 +858,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.0.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .0 + .select(Some(i)); } pub fn select_edit_style_bg_next(&mut self) { - let i = match self.state.edit_specific_style_state.1.selected() { + let i = match self.state.app_list_states.edit_specific_style.1.selected() { Some(i) => { if i >= TextColorOptions::to_iter().count() - 1 { 0 @@ -842,10 +875,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.1.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .1 + .select(Some(i)); } pub fn select_edit_style_bg_prv(&mut self) { - let i = match self.state.edit_specific_style_state.1.selected() { + let i = match self.state.app_list_states.edit_specific_style.1.selected() { Some(i) => { if i == 0 { TextColorOptions::to_iter().count() - 1 @@ -855,10 +892,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.1.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .1 + .select(Some(i)); } pub fn select_edit_style_modifier_next(&mut self) { - let i = match self.state.edit_specific_style_state.2.selected() { + let i = match self.state.app_list_states.edit_specific_style.2.selected() { Some(i) => { if i >= TextModifierOptions::to_iter().count() - 1 { 0 @@ -868,10 +909,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.2.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .2 + .select(Some(i)); } pub fn select_edit_style_modifier_prv(&mut self) { - let i = match self.state.edit_specific_style_state.2.selected() { + let i = match self.state.app_list_states.edit_specific_style.2.selected() { Some(i) => { if i == 0 { TextModifierOptions::to_iter().count() - 1 @@ -881,10 +926,14 @@ impl App<'_> { } None => 0, }; - self.state.edit_specific_style_state.2.select(Some(i)); + self.state + .app_list_states + .edit_specific_style + .2 + .select(Some(i)); } pub fn select_card_priority_next(&mut self) { - let i = match self.state.card_priority_selector_state.selected() { + let i = match self.state.app_list_states.card_priority_selector.selected() { Some(i) => { if i >= CardPriority::all().len() - 1 { 0 @@ -894,10 +943,13 @@ impl App<'_> { } None => 0, }; - self.state.card_priority_selector_state.select(Some(i)); + self.state + .app_list_states + .card_priority_selector + .select(Some(i)); } pub fn select_card_priority_prv(&mut self) { - let i = match self.state.card_priority_selector_state.selected() { + let i = match self.state.app_list_states.card_priority_selector.selected() { Some(i) => { if i == 0 { CardPriority::all().len() - 1 @@ -907,7 +959,10 @@ impl App<'_> { } None => 0, }; - self.state.card_priority_selector_state.select(Some(i)); + self.state + .app_list_states + .card_priority_selector + .select(Some(i)); } pub fn filter_by_tag_popup_next(&mut self) { let all_tags_len = if self.state.all_available_tags.is_some() { @@ -916,7 +971,7 @@ impl App<'_> { 0 }; if all_tags_len > 0 { - let i = match self.state.filter_by_tag_list_state.selected() { + let i = match self.state.app_list_states.filter_by_tag_list.selected() { Some(i) => { if i >= all_tags_len - 1 { 0 @@ -926,7 +981,10 @@ impl App<'_> { } None => 0, }; - self.state.filter_by_tag_list_state.select(Some(i)); + self.state + .app_list_states + .filter_by_tag_list + .select(Some(i)); } } pub fn filter_by_tag_popup_prv(&mut self) { @@ -936,7 +994,7 @@ impl App<'_> { 0 }; if all_tags_len > 0 { - let i = match self.state.filter_by_tag_list_state.selected() { + let i = match self.state.app_list_states.filter_by_tag_list.selected() { Some(i) => { if i == 0 { all_tags_len - 1 @@ -946,11 +1004,14 @@ impl App<'_> { } None => 0, }; - self.state.filter_by_tag_list_state.select(Some(i)); + self.state + .app_list_states + .filter_by_tag_list + .select(Some(i)); } } pub fn change_date_format_popup_next(&mut self) { - let i = match self.state.date_format_selector_state.selected() { + let i = match self.state.app_list_states.date_format_selector.selected() { Some(i) => { if i >= DateFormat::get_all_date_formats().len() - 1 { 0 @@ -960,10 +1021,13 @@ impl App<'_> { } None => 0, }; - self.state.date_format_selector_state.select(Some(i)); + self.state + .app_list_states + .date_format_selector + .select(Some(i)); } pub fn change_date_format_popup_prv(&mut self) { - let i = match self.state.date_format_selector_state.selected() { + let i = match self.state.app_list_states.date_format_selector.selected() { Some(i) => { if i == 0 { DateFormat::get_all_date_formats().len() - 1 @@ -973,7 +1037,10 @@ impl App<'_> { } None => 0, }; - self.state.date_format_selector_state.select(Some(i)); + self.state + .app_list_states + .date_format_selector + .select(Some(i)); } pub fn undo(&mut self) { if self.action_history_manager.history_index == 0 { @@ -1411,10 +1478,7 @@ impl PopupMode { } } - pub fn render(self, rect: &mut Frame, app: &mut App) - where - B: Backend, - { + pub fn render(self, rect: &mut Frame, app: &mut App) { match self { PopupMode::ViewCard => { ui_helper::render_view_card(rect, app); @@ -1465,154 +1529,195 @@ impl PopupMode { } } +#[derive(Debug, Clone)] +pub struct AppListStates { + pub card_priority_selector: ListState, + pub card_status_selector: ListState, + pub card_view_comment_list: ListState, + pub card_view_list: ListState, + pub card_view_tag_list: ListState, + pub command_palette_board_search: ListState, + pub command_palette_card_search: ListState, + pub command_palette_command_search: ListState, + pub date_format_selector: ListState, + pub default_view: ListState, + pub edit_specific_style: (ListState, ListState, ListState), + pub filter_by_tag_list: ListState, + pub load_save: ListState, + pub logs: ListState, + pub main_menu: ListState, + pub theme_selector: ListState, +} + +impl Default for AppListStates { + fn default() -> Self { + AppListStates { + card_priority_selector: ListState::default(), + card_status_selector: ListState::default(), + card_view_comment_list: ListState::default(), + card_view_list: ListState::default(), + card_view_tag_list: ListState::default(), + command_palette_board_search: ListState::default(), + command_palette_card_search: ListState::default(), + command_palette_command_search: ListState::default(), + date_format_selector: ListState::default(), + default_view: ListState::default(), + edit_specific_style: ( + ListState::default(), + ListState::default(), + ListState::default(), + ), + filter_by_tag_list: ListState::default(), + load_save: ListState::default(), + logs: ListState::default(), + main_menu: ListState::default(), + theme_selector: ListState::default(), + } + } +} + +#[derive(Debug, Clone)] +pub struct AppTableStates { + pub config: TableState, + pub edit_keybindings: TableState, + pub help: TableState, + pub theme_editor: TableState, +} + +impl Default for AppTableStates { + fn default() -> Self { + AppTableStates { + config: TableState::default(), + edit_keybindings: TableState::default(), + help: TableState::default(), + theme_editor: TableState::default(), + } + } +} + +#[derive(Debug, Clone)] +pub struct AppFormStates { + pub login: (Vec, bool), + pub new_board: Vec, + pub new_card: Vec, + pub reset_password: (Vec, bool), + pub signup: (Vec, bool), +} + +impl Default for AppFormStates { + fn default() -> Self { + AppFormStates { + login: (vec![String::new(), String::new()], false), + new_board: vec![String::new(), String::new()], + new_card: vec![String::new(), String::new(), String::new()], + reset_password: ( + vec![String::new(), String::new(), String::new(), String::new()], + false, + ), + signup: (vec![String::new(), String::new(), String::new()], false), + } + } +} + #[derive(Debug, Clone)] pub struct AppState<'a> { + pub all_available_tags: Option>, + pub app_form_states: AppFormStates, + pub app_list_states: AppListStates, pub app_status: AppStatus, + pub app_table_states: AppTableStates, + pub card_being_edited: Option<((u64, u64), Card)>, // (board_id, card) + pub card_description_text_buffer: Option>, + pub cloud_data: Option>, + pub config_item_being_edited: Option, pub current_board_id: Option<(u64, u64)>, pub current_card_id: Option<(u64, u64)>, - pub focus: Focus, - pub previous_focus: Option, + pub current_cursor_position: Option, + pub current_mouse_coordinates: (u16, u16), pub current_user_input: String, - pub main_menu_state: ListState, - pub config_state: TableState, - pub new_board_form: Vec, - pub new_card_form: Vec, - pub login_form: (Vec, bool), - pub signup_form: (Vec, bool), - pub reset_password_form: (Vec, bool), - pub load_save_state: ListState, - pub edit_keybindings_state: TableState, + pub debug_menu_toggled: bool, + pub default_theme_mode: bool, pub edited_keybinding: Option>, - pub help_state: TableState, + pub encryption_key_from_arguments: Option, + pub filter_tags: Option>, + pub focus: Focus, pub keybinding_store: Vec>, - pub default_view_state: ListState, - pub current_cursor_position: Option, - pub toasts: Vec, - pub term_background_color: (u8, u8, u8), + pub last_mouse_action: Option, + pub last_mouse_action_time: Option, + pub last_reset_password_link_sent_time: Option, + pub mouse_focus: Option, + pub mouse_list_index: Option, + pub no_of_cards_to_show: u16, + pub popup_mode: Option, + pub prev_focus: Option, + pub prev_ui_mode: Option, pub preview_boards_and_cards: Option>, - pub preview_visible_boards_and_cards: LinkedHashMap<(u64, u64), Vec<(u64, u64)>>, pub preview_file_name: Option, - pub popup_mode: Option, + pub preview_visible_boards_and_cards: LinkedHashMap<(u64, u64), Vec<(u64, u64)>>, + pub term_background_color: (u8, u8, u8), + pub theme_being_edited: Theme, + pub toasts: Vec, pub ui_mode: UiMode, - pub no_of_cards_to_show: u16, - pub command_palette_command_search_list_state: ListState, - pub command_palette_card_search_list_state: ListState, - pub command_palette_board_search_list_state: ListState, - pub card_status_selector_state: ListState, - pub prev_ui_mode: Option, - pub debug_menu_toggled: bool, pub ui_render_time: Option, - pub current_mouse_coordinates: (u16, u16), - pub mouse_focus: Option, - pub mouse_list_index: Option, - pub last_mouse_action: Option, - pub last_mouse_action_time: Option, - pub theme_selector_state: ListState, - pub theme_being_edited: Theme, - pub theme_editor_state: TableState, - pub edit_specific_style_state: (ListState, ListState, ListState), - pub default_theme_mode: bool, - pub card_view_list_state: ListState, - pub card_view_tag_list_state: ListState, - pub card_view_comment_list_state: ListState, - pub card_priority_selector_state: ListState, - pub all_available_tags: Option>, - pub filter_tags: Option>, - pub filter_by_tag_list_state: ListState, - pub date_format_selector_state: ListState, - pub log_state: ListState, pub user_login_data: UserLoginData, - pub cloud_data: Option>, - pub last_reset_password_link_sent_time: Option, - pub encryption_key_from_arguments: Option, - pub card_being_edited: Option<((u64, u64), Card)>, // (board_id, card) - pub card_description_text_buffer: Option>, - pub config_item_being_edited: Option, } impl Default for AppState<'_> { fn default() -> AppState<'static> { AppState { + all_available_tags: None, + app_form_states: AppFormStates::default(), + app_list_states: AppListStates::default(), app_status: AppStatus::default(), - focus: Focus::NoFocus, + app_table_states: AppTableStates::default(), + card_being_edited: None, + card_description_text_buffer: None, + cloud_data: None, + config_item_being_edited: None, current_board_id: None, current_card_id: None, - previous_focus: None, + current_cursor_position: None, + current_mouse_coordinates: MOUSE_OUT_OF_BOUNDS_COORDINATES, // make sure it's out of bounds when mouse mode is disabled current_user_input: String::new(), - main_menu_state: ListState::default(), - config_state: TableState::default(), - new_board_form: vec![String::new(), String::new()], - new_card_form: vec![String::new(), String::new(), String::new()], - login_form: (vec![String::new(), String::new()], false), - signup_form: (vec![String::new(), String::new(), String::new()], false), - reset_password_form: ( - vec![String::new(), String::new(), String::new(), String::new()], - false, - ), - load_save_state: ListState::default(), - edit_keybindings_state: TableState::default(), + debug_menu_toggled: false, + default_theme_mode: false, edited_keybinding: None, - help_state: TableState::default(), + encryption_key_from_arguments: None, + filter_tags: None, + focus: Focus::NoFocus, keybinding_store: Vec::new(), - default_view_state: ListState::default(), - current_cursor_position: None, - toasts: Vec::new(), - term_background_color: get_term_bg_color(), + last_mouse_action: None, + last_mouse_action_time: None, + last_reset_password_link_sent_time: None, + mouse_focus: None, + mouse_list_index: None, + no_of_cards_to_show: NO_OF_CARDS_PER_BOARD, + popup_mode: None, + prev_focus: None, + prev_ui_mode: None, preview_boards_and_cards: None, - preview_visible_boards_and_cards: LinkedHashMap::new(), preview_file_name: None, - popup_mode: None, + preview_visible_boards_and_cards: LinkedHashMap::new(), + term_background_color: get_term_bg_color(), + theme_being_edited: Theme::default(), + toasts: Vec::new(), ui_mode: DEFAULT_UI_MODE, - no_of_cards_to_show: NO_OF_CARDS_PER_BOARD, - command_palette_command_search_list_state: ListState::default(), - command_palette_card_search_list_state: ListState::default(), - command_palette_board_search_list_state: ListState::default(), - card_status_selector_state: ListState::default(), - prev_ui_mode: None, - debug_menu_toggled: false, ui_render_time: None, - current_mouse_coordinates: MOUSE_OUT_OF_BOUNDS_COORDINATES, // make sure it's out of bounds when mouse mode is disabled - mouse_focus: None, - mouse_list_index: None, - last_mouse_action: None, - last_mouse_action_time: None, - theme_selector_state: ListState::default(), - theme_being_edited: Theme::default(), - theme_editor_state: TableState::default(), - edit_specific_style_state: ( - ListState::default(), - ListState::default(), - ListState::default(), - ), - default_theme_mode: false, - card_view_list_state: ListState::default(), - card_view_tag_list_state: ListState::default(), - card_view_comment_list_state: ListState::default(), - card_priority_selector_state: ListState::default(), - all_available_tags: None, - filter_tags: None, - filter_by_tag_list_state: ListState::default(), - date_format_selector_state: ListState::default(), - log_state: ListState::default(), user_login_data: UserLoginData { email_id: None, auth_token: None, + refresh_token: None, user_id: None, }, - cloud_data: None, - last_reset_password_link_sent_time: None, - encryption_key_from_arguments: None, - card_being_edited: None, - card_description_text_buffer: None, - config_item_being_edited: None, } } } #[derive(Debug, Clone, Default)] pub struct UserLoginData { - pub email_id: Option, pub auth_token: Option, + pub email_id: Option, + pub refresh_token: Option, pub user_id: Option, } @@ -2427,8 +2532,9 @@ pub fn date_format_converter(date_string: &str, date_format: DateFormat) -> Resu } } -pub async fn handle_exit(app: &mut App<'_>) { +pub async fn handle_exit(app: &mut App<'_>) -> AppReturn { if app.config.save_on_exit { app.dispatch(IoEvent::AutoSave).await; } + AppReturn::Exit } diff --git a/src/app/state.rs b/src/app/state.rs index 2532739..3442ed4 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -1,34 +1,34 @@ use super::{actions::Action, App}; use crate::{inputs::key::Key, ui::ui_helper}; use log::{debug, error}; -use ratatui::{backend::Backend, Frame}; +use ratatui::Frame; use serde::{Deserialize, Serialize}; use std::{fmt, str::FromStr, vec}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Copy, Default)] pub enum UiMode { - #[default] - Zen, - TitleBody, BodyHelp, - BodyLog, - TitleBodyHelp, - TitleBodyLog, - TitleBodyHelpLog, BodyHelpLog, + BodyLog, ConfigMenu, + CreateTheme, EditKeybindings, - MainMenu, HelpMenu, + LoadCloudSave, + LoadLocalSave, + Login, LogsOnly, + MainMenu, NewBoard, NewCard, - LoadLocalSave, - CreateTheme, - Login, - SignUp, ResetPassword, - LoadCloudSave, + SignUp, + TitleBody, + TitleBodyHelp, + TitleBodyHelpLog, + TitleBodyLog, + #[default] + Zen, } #[derive(Clone, PartialEq, Debug, Default)] @@ -36,132 +36,231 @@ pub enum AppStatus { #[default] Init, Initialized, - UserInput, KeyBindMode, + UserInput, } #[derive(Clone, PartialEq, Debug, Copy, Default)] pub enum Focus { - Title, Body, - Help, - Log, - ConfigTable, - ConfigHelp, - MainMenu, - MainMenuHelp, - NewBoardName, - NewBoardDescription, - CardName, + CardComments, CardDescription, CardDueDate, - SubmitButton, - EditKeybindingsTable, - CloseButton, - CommandPaletteCommand, - CommandPaletteCard, - CommandPaletteBoard, - LoadSave, - SelectDefaultView, - ChangeUiModePopup, - ChangeCardStatusPopup, - EditGeneralConfigPopup, - EditSpecificKeyBindingPopup, - ThemeSelector, - ThemeEditor, - StyleEditorFG, - StyleEditorBG, - StyleEditorModifier, - TextInput, + CardName, CardPriority, CardStatus, CardTags, - CardComments, ChangeCardPriorityPopup, + ChangeCardStatusPopup, ChangeDateFormatPopup, + ChangeUiModePopup, + CloseButton, + CommandPaletteBoard, + CommandPaletteCard, + CommandPaletteCommand, + ConfigHelp, + ConfigTable, + ConfirmPasswordField, + EditGeneralConfigPopup, + EditKeybindingsTable, + EditSpecificKeyBindingPopup, + EmailIDField, + ExtraFocus, // Used in cases where defining a new focus is not necessary FilterByTagPopup, + Help, + LoadSave, + Log, + MainMenu, + MainMenuHelp, + NewBoardDescription, + NewBoardName, #[default] NoFocus, - ExtraFocus, // Used in cases where defining a new focus is not necessary - EmailIDField, PasswordField, - ConfirmPasswordField, - SendResetPasswordLinkButton, ResetPasswordLinkField, + SelectDefaultView, + SendResetPasswordLinkButton, + StyleEditorBG, + StyleEditorFG, + StyleEditorModifier, + SubmitButton, + TextInput, + ThemeEditor, + ThemeSelector, + Title, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct KeyBindings { - pub quit: Vec, - pub open_config_menu: Vec, - pub up: Vec, + pub change_card_status_to_active: Vec, + pub change_card_status_to_completed: Vec, + pub change_card_status_to_stale: Vec, + pub clear_all_toasts: Vec, + pub delete_board: Vec, + pub delete_card: Vec, pub down: Vec, - pub right: Vec, - pub left: Vec, - pub next_focus: Vec, - pub prev_focus: Vec, - pub take_user_input: Vec, - pub stop_user_input: Vec, + pub go_to_main_menu: Vec, pub hide_ui_element: Vec, - pub save_state: Vec, + pub left: Vec, pub new_board: Vec, pub new_card: Vec, - pub delete_board: Vec, - pub delete_card: Vec, - pub change_card_status_to_completed: Vec, - pub change_card_status_to_active: Vec, - pub change_card_status_to_stale: Vec, + pub next_focus: Vec, + pub open_config_menu: Vec, + pub prev_focus: Vec, + pub quit: Vec, + pub redo: Vec, pub reset_ui: Vec, - pub go_to_main_menu: Vec, + pub right: Vec, + pub save_state: Vec, + pub stop_user_input: Vec, + pub take_user_input: Vec, pub toggle_command_palette: Vec, - pub clear_all_toasts: Vec, pub undo: Vec, - pub redo: Vec, + pub up: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum KeyBindingEnum { + ChangeCardStatusToActive, + ChangeCardStatusToCompleted, + ChangeCardStatusToStale, + ClearAllToasts, + DeleteBoard, + DeleteCard, + Down, + GoToMainMenu, + HideUiElement, + Left, + NewBoard, + NewCard, + NextFocus, + OpenConfigMenu, + PrvFocus, + Quit, + Redo, + ResetUI, + Right, + SaveState, + StopUserInput, + TakeUserInput, + ToggleCommandPalette, + Undo, + Up, +} + +impl KeyBindingEnum { + pub fn to_str(&self) -> &str { + match self { + Self::ChangeCardStatusToActive => "change_card_status_to_active", + Self::ChangeCardStatusToCompleted => "change_card_status_to_completed", + Self::ChangeCardStatusToStale => "change_card_status_to_stale", + Self::ClearAllToasts => "clear_all_toasts", + Self::DeleteBoard => "delete_board", + Self::DeleteCard => "delete_card", + Self::Down => "down", + Self::GoToMainMenu => "go_to_main_menu", + Self::HideUiElement => "hide_ui_element", + Self::Left => "left", + Self::NewBoard => "new_board", + Self::NewCard => "new_card", + Self::NextFocus => "next_focus", + Self::OpenConfigMenu => "open_config_menu", + Self::PrvFocus => "prev_focus", + Self::Quit => "quit", + Self::Redo => "redo", + Self::ResetUI => "reset_ui", + Self::Right => "right", + Self::SaveState => "save_state", + Self::StopUserInput => "stop_user_input", + Self::TakeUserInput => "take_user_input", + Self::ToggleCommandPalette => "toggle_command_palette", + Self::Undo => "undo", + Self::Up => "up", + } + } + pub fn from_str(s: &str) -> Option { + match s { + "change_card_status_to_active" => Some(Self::ChangeCardStatusToActive), + "change_card_status_to_completed" => Some(Self::ChangeCardStatusToCompleted), + "change_card_status_to_stale" => Some(Self::ChangeCardStatusToStale), + "clear_all_toasts" => Some(Self::ClearAllToasts), + "delete_board" => Some(Self::DeleteBoard), + "delete_card" => Some(Self::DeleteCard), + "down" => Some(Self::Down), + "go_to_main_menu" => Some(Self::GoToMainMenu), + "hide_ui_element" => Some(Self::HideUiElement), + "left" => Some(Self::Left), + "new_board" => Some(Self::NewBoard), + "new_card" => Some(Self::NewCard), + "next_focus" => Some(Self::NextFocus), + "open_config_menu" => Some(Self::OpenConfigMenu), + "prev_focus" => Some(Self::PrvFocus), + "quit" => Some(Self::Quit), + "redo" => Some(Self::Redo), + "reset_ui" => Some(Self::ResetUI), + "right" => Some(Self::Right), + "save_state" => Some(Self::SaveState), + "stop_user_input" => Some(Self::StopUserInput), + "take_user_input" => Some(Self::TakeUserInput), + "toggle_command_palette" => Some(Self::ToggleCommandPalette), + "undo" => Some(Self::Undo), + "up" => Some(Self::Up), + _ => None, + } + } } impl UiMode { pub fn from_string(s: &str) -> Option { match s { - "Zen" => Some(UiMode::Zen), - "Title and Body" => Some(UiMode::TitleBody), "Body and Help" => Some(UiMode::BodyHelp), - "Body and Log" => Some(UiMode::BodyLog), - "Title, Body and Help" => Some(UiMode::TitleBodyHelp), - "Title, Body and Log" => Some(UiMode::TitleBodyLog), "Body, Help and Log" => Some(UiMode::BodyHelpLog), - "Title, Body, Help and Log" => Some(UiMode::TitleBodyHelpLog), + "Body and Log" => Some(UiMode::BodyLog), "Config" => Some(UiMode::ConfigMenu), + "Create Theme" => Some(UiMode::CreateTheme), "Edit Keybindings" => Some(UiMode::EditKeybindings), - "Main Menu" => Some(UiMode::MainMenu), "Help Menu" => Some(UiMode::HelpMenu), + "Load a Save (Cloud)" => Some(UiMode::LoadCloudSave), + "Load a Save (Local)" => Some(UiMode::LoadLocalSave), + "Login" => Some(UiMode::Login), "Logs Only" => Some(UiMode::LogsOnly), + "Main Menu" => Some(UiMode::MainMenu), "New Board" => Some(UiMode::NewBoard), "New Card" => Some(UiMode::NewCard), - "Load a Save" => Some(UiMode::LoadLocalSave), - "Create Theme" => Some(UiMode::CreateTheme), + "Reset Password" => Some(UiMode::ResetPassword), + "Sign Up" => Some(UiMode::SignUp), + "Title and Body" => Some(UiMode::TitleBody), + "Title, Body and Help" => Some(UiMode::TitleBodyHelp), + "Title, Body, Help and Log" => Some(UiMode::TitleBodyHelpLog), + "Title, Body and Log" => Some(UiMode::TitleBodyLog), + "Zen" => Some(UiMode::Zen), _ => None, } } pub fn from_json_string(s: &str) -> Option { match s { - "Zen" => Some(UiMode::Zen), - "TitleBody" => Some(UiMode::TitleBody), "BodyHelp" => Some(UiMode::BodyHelp), - "BodyLog" => Some(UiMode::BodyLog), - "TitleBodyHelp" => Some(UiMode::TitleBodyHelp), - "TitleBodyLog" => Some(UiMode::TitleBodyLog), "BodyHelpLog" => Some(UiMode::BodyHelpLog), - "TitleBodyHelpLog" => Some(UiMode::TitleBodyHelpLog), + "BodyLog" => Some(UiMode::BodyLog), "ConfigMenu" => Some(UiMode::ConfigMenu), + "CreateTheme" => Some(UiMode::CreateTheme), "EditKeybindings" => Some(UiMode::EditKeybindings), - "MainMenu" => Some(UiMode::MainMenu), "HelpMenu" => Some(UiMode::HelpMenu), + "LoadCloudSave" => Some(UiMode::LoadCloudSave), + "LoadLocalSave" => Some(UiMode::LoadLocalSave), + "Login" => Some(UiMode::Login), "LogsOnly" => Some(UiMode::LogsOnly), + "MainMenu" => Some(UiMode::MainMenu), "NewBoard" => Some(UiMode::NewBoard), "NewCard" => Some(UiMode::NewCard), - "LoadSave" => Some(UiMode::LoadLocalSave), - "CreateTheme" => Some(UiMode::CreateTheme), + "ResetPassword" => Some(UiMode::ResetPassword), + "SignUp" => Some(UiMode::SignUp), + "TitleBody" => Some(UiMode::TitleBody), + "TitleBodyHelp" => Some(UiMode::TitleBodyHelp), + "TitleBodyHelpLog" => Some(UiMode::TitleBodyHelpLog), + "TitleBodyLog" => Some(UiMode::TitleBodyLog), + "Zen" => Some(UiMode::Zen), _ => None, } } @@ -186,19 +285,24 @@ impl UiMode { pub fn get_available_targets(&self) -> Vec { match self { - UiMode::Zen => vec![Focus::Body], - UiMode::TitleBody => vec![Focus::Title, Focus::Body], UiMode::BodyHelp => vec![Focus::Body, Focus::Help], - UiMode::BodyLog => vec![Focus::Body, Focus::Log], - UiMode::TitleBodyHelp => vec![Focus::Title, Focus::Body, Focus::Help], - UiMode::TitleBodyLog => vec![Focus::Title, Focus::Body, Focus::Log], UiMode::BodyHelpLog => vec![Focus::Body, Focus::Help, Focus::Log], - UiMode::TitleBodyHelpLog => vec![Focus::Title, Focus::Body, Focus::Help, Focus::Log], + UiMode::BodyLog => vec![Focus::Body, Focus::Log], UiMode::ConfigMenu => vec![Focus::ConfigTable, Focus::SubmitButton, Focus::ExtraFocus], + UiMode::CreateTheme => vec![Focus::ThemeEditor, Focus::SubmitButton, Focus::ExtraFocus], UiMode::EditKeybindings => vec![Focus::EditKeybindingsTable, Focus::SubmitButton], - UiMode::MainMenu => vec![Focus::MainMenu, Focus::MainMenuHelp, Focus::Log], UiMode::HelpMenu => vec![Focus::Help, Focus::Log], + UiMode::LoadCloudSave => vec![Focus::Body], + UiMode::LoadLocalSave => vec![Focus::Body], + UiMode::Login => vec![ + Focus::Title, + Focus::EmailIDField, + Focus::PasswordField, + Focus::ExtraFocus, + Focus::SubmitButton, + ], UiMode::LogsOnly => vec![Focus::Log], + UiMode::MainMenu => vec![Focus::MainMenu, Focus::MainMenuHelp, Focus::Log], UiMode::NewBoard => vec![ Focus::NewBoardName, Focus::NewBoardDescription, @@ -210,34 +314,29 @@ impl UiMode { Focus::CardDueDate, Focus::SubmitButton, ], - UiMode::LoadLocalSave => vec![Focus::Body], - UiMode::CreateTheme => vec![Focus::ThemeEditor, Focus::SubmitButton, Focus::ExtraFocus], - UiMode::Login => vec![ - Focus::Title, - Focus::EmailIDField, - Focus::PasswordField, - Focus::ExtraFocus, - Focus::SubmitButton, - ], - UiMode::SignUp => vec![ + UiMode::ResetPassword => vec![ Focus::Title, Focus::EmailIDField, + Focus::SendResetPasswordLinkButton, + Focus::ResetPasswordLinkField, Focus::PasswordField, Focus::ConfirmPasswordField, Focus::ExtraFocus, Focus::SubmitButton, ], - UiMode::ResetPassword => vec![ + UiMode::SignUp => vec![ Focus::Title, Focus::EmailIDField, - Focus::SendResetPasswordLinkButton, - Focus::ResetPasswordLinkField, Focus::PasswordField, Focus::ConfirmPasswordField, Focus::ExtraFocus, Focus::SubmitButton, ], - UiMode::LoadCloudSave => vec![Focus::Body], + UiMode::TitleBody => vec![Focus::Title, Focus::Body], + UiMode::TitleBodyHelp => vec![Focus::Title, Focus::Body, Focus::Help], + UiMode::TitleBodyHelpLog => vec![Focus::Title, Focus::Body, Focus::Help, Focus::Log], + UiMode::TitleBodyLog => vec![Focus::Title, Focus::Body, Focus::Log], + UiMode::Zen => vec![Focus::Body], } } @@ -258,10 +357,7 @@ impl UiMode { ] } - pub fn render(self, rect: &mut Frame, app: &mut App) - where - B: Backend, - { + pub fn render(self, rect: &mut Frame, app: &mut App) { match self { UiMode::Zen => { ui_helper::render_zen_mode(rect, app); @@ -321,27 +417,27 @@ impl UiMode { impl fmt::Display for UiMode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - UiMode::Zen => write!(f, "Zen"), - UiMode::TitleBody => write!(f, "Title and Body"), UiMode::BodyHelp => write!(f, "Body and Help"), - UiMode::BodyLog => write!(f, "Body and Log"), - UiMode::TitleBodyHelp => write!(f, "Title, Body and Help"), - UiMode::TitleBodyLog => write!(f, "Title, Body and Log"), UiMode::BodyHelpLog => write!(f, "Body, Help and Log"), - UiMode::TitleBodyHelpLog => write!(f, "Title, Body, Help and Log"), + UiMode::BodyLog => write!(f, "Body and Log"), UiMode::ConfigMenu => write!(f, "Config"), + UiMode::CreateTheme => write!(f, "Create Theme"), UiMode::EditKeybindings => write!(f, "Edit Keybindings"), - UiMode::MainMenu => write!(f, "Main Menu"), UiMode::HelpMenu => write!(f, "Help Menu"), + UiMode::LoadCloudSave => write!(f, "Load a Save (Cloud)"), + UiMode::LoadLocalSave => write!(f, "Load a Save (Local)"), + UiMode::Login => write!(f, "Login"), UiMode::LogsOnly => write!(f, "Logs Only"), + UiMode::MainMenu => write!(f, "Main Menu"), UiMode::NewBoard => write!(f, "New Board"), UiMode::NewCard => write!(f, "New Card"), - UiMode::LoadLocalSave => write!(f, "Load a Save (Local)"), - UiMode::CreateTheme => write!(f, "Create Theme"), - UiMode::Login => write!(f, "Login"), - UiMode::SignUp => write!(f, "Sign Up"), UiMode::ResetPassword => write!(f, "Reset Password"), - UiMode::LoadCloudSave => write!(f, "Load a Save (Cloud)"), + UiMode::SignUp => write!(f, "Sign Up"), + UiMode::TitleBody => write!(f, "Title and Body"), + UiMode::TitleBodyHelp => write!(f, "Title, Body and Help"), + UiMode::TitleBodyHelpLog => write!(f, "Title, Body, Help and Log"), + UiMode::TitleBodyLog => write!(f, "Title, Body and Log"), + UiMode::Zen => write!(f, "Zen"), } } } @@ -359,51 +455,51 @@ impl AppStatus { impl Focus { pub fn to_str(&self) -> &str { match self { - Self::Title => "Title", Self::Body => "Body", - Self::Help => "Help", - Self::Log => "Log", - Self::ConfigTable => "Config", - Self::ConfigHelp => "Config Help", - Self::MainMenu => "Main Menu", - Self::MainMenuHelp => "Main Menu Help", - Self::NewBoardName => "New Board Name", - Self::NewBoardDescription => "New Board Description", - Self::CardName => "New Card Name", + Self::CardComments => "Card Comments", Self::CardDescription => "Card Description", Self::CardDueDate => "Card Due Date", - Self::SubmitButton => "Submit Button", - Self::EditKeybindingsTable => "Edit Keybindings Table", - Self::CloseButton => "Close Button", - Self::CommandPaletteCommand => "Command Palette Command", - Self::CommandPaletteCard => "Command Palette Card", - Self::CommandPaletteBoard => "Command Palette Board", - Self::LoadSave => "Load Save", - Self::SelectDefaultView => "Select Default View", - Self::ChangeUiModePopup => "Change Ui Mode Popup", - Self::ChangeCardStatusPopup => "Change Card Status Popup", - Self::EditGeneralConfigPopup => "Edit General Config Popup", - Self::EditSpecificKeyBindingPopup => "Edit Specific Key Binding Popup", - Self::ThemeSelector => "Theme Selector", - Self::ThemeEditor => "Theme Editor", - Self::StyleEditorFG => "Theme Editor FG", - Self::StyleEditorBG => "Theme Editor BG", - Self::StyleEditorModifier => "Theme Editor Modifier", - Self::TextInput => "Text Input", + Self::CardName => "New Card Name", Self::CardPriority => "Card Priority", Self::CardStatus => "Card Status", Self::CardTags => "Card Tags", - Self::CardComments => "Card Comments", Self::ChangeCardPriorityPopup => "Change Card Priority Popup", + Self::ChangeCardStatusPopup => "Change Card Status Popup", Self::ChangeDateFormatPopup => "Change Date Format Popup", + Self::ChangeUiModePopup => "Change Ui Mode Popup", + Self::CloseButton => "Close Button", + Self::CommandPaletteBoard => "Command Palette Board", + Self::CommandPaletteCard => "Command Palette Card", + Self::CommandPaletteCommand => "Command Palette Command", + Self::ConfigHelp => "Config Help", + Self::ConfigTable => "Config", + Self::ConfirmPasswordField => "Confirm Password Field", + Self::EditGeneralConfigPopup => "Edit General Config Popup", + Self::EditKeybindingsTable => "Edit Keybindings Table", + Self::EditSpecificKeyBindingPopup => "Edit Specific Key Binding Popup", + Self::EmailIDField => "Email ID Field", + Self::ExtraFocus => "Extra Focus", Self::FilterByTagPopup => "Filter By Tag Popup", + Self::Help => "Help", + Self::LoadSave => "Load Save", + Self::Log => "Log", + Self::MainMenu => "Main Menu", + Self::MainMenuHelp => "Main Menu Help", + Self::NewBoardDescription => "New Board Description", + Self::NewBoardName => "New Board Name", Self::NoFocus => "No Focus", - Self::ExtraFocus => "Extra Focus", - Self::EmailIDField => "Email ID Field", Self::PasswordField => "Password Field", - Self::ConfirmPasswordField => "Confirm Password Field", + Self::ResetPasswordLinkField => "Reset Password Link Field", + Self::SelectDefaultView => "Select Default View", Self::SendResetPasswordLinkButton => "Send Reset Password Link Button", - Self::ResetPasswordLinkField => "OTP Field", + Self::StyleEditorBG => "Theme Editor BG", + Self::StyleEditorFG => "Theme Editor FG", + Self::StyleEditorModifier => "Theme Editor Modifier", + Self::SubmitButton => "Submit Button", + Self::TextInput => "Text Input", + Self::ThemeEditor => "Theme Editor", + Self::ThemeSelector => "Theme Selector", + Self::Title => "Title", } } pub fn next(&self, available_tabs: &Vec) -> Self { @@ -436,45 +532,51 @@ impl FromStr for Focus { type Err = String; fn from_str(s: &str) -> Result { match s { - "Title" => Ok(Self::Title), "Body" => Ok(Self::Body), - "Help" => Ok(Self::Help), - "Log" => Ok(Self::Log), - "Config" => Ok(Self::ConfigTable), - "Config Help" => Ok(Self::ConfigHelp), - "Main Menu" => Ok(Self::MainMenu), - "Main Menu Help" => Ok(Self::MainMenuHelp), - "No Focus" => Ok(Self::NoFocus), - "New Board Name" => Ok(Self::NewBoardName), - "New Board Description" => Ok(Self::NewBoardDescription), - "New Card Name" => Ok(Self::CardName), + "Card Comments" => Ok(Self::CardComments), "Card Description" => Ok(Self::CardDescription), "Card Due Date" => Ok(Self::CardDueDate), - "Edit Keybindings Table" => Ok(Self::EditKeybindingsTable), - "Close Button" => Ok(Self::CloseButton), - "Command Palette Command" => Ok(Self::CommandPaletteCommand), - "Command Palette Card" => Ok(Self::CommandPaletteCard), - "Command Palette Board" => Ok(Self::CommandPaletteBoard), - "Load Save" => Ok(Self::LoadSave), - "Select Default View" => Ok(Self::SelectDefaultView), - "Change Ui Mode Popup" => Ok(Self::ChangeUiModePopup), - "Change Card Status Popup" => Ok(Self::ChangeCardStatusPopup), - "Edit General Config Popup" => Ok(Self::EditGeneralConfigPopup), - "Edit Specific Key Binding Popup" => Ok(Self::EditSpecificKeyBindingPopup), - "Theme Selector" => Ok(Self::ThemeSelector), - "Theme Editor" => Ok(Self::ThemeEditor), - "Theme Editor FG" => Ok(Self::StyleEditorFG), - "Theme Editor BG" => Ok(Self::StyleEditorBG), - "Theme Editor Modifier" => Ok(Self::StyleEditorModifier), - "Text Input" => Ok(Self::TextInput), "Card Priority" => Ok(Self::CardPriority), "Card Status" => Ok(Self::CardStatus), "Card Tags" => Ok(Self::CardTags), - "Card Comments" => Ok(Self::CardComments), "Change Card Priority Popup" => Ok(Self::ChangeCardPriorityPopup), + "Change Card Status Popup" => Ok(Self::ChangeCardStatusPopup), + "Change Date Format Popup" => Ok(Self::ChangeDateFormatPopup), + "Change Ui Mode Popup" => Ok(Self::ChangeUiModePopup), + "Close Button" => Ok(Self::CloseButton), + "Command Palette Board" => Ok(Self::CommandPaletteBoard), + "Command Palette Card" => Ok(Self::CommandPaletteCard), + "Command Palette Command" => Ok(Self::CommandPaletteCommand), + "Config Help" => Ok(Self::ConfigHelp), + "Config" => Ok(Self::ConfigTable), + "Confirm Password Field" => Ok(Self::ConfirmPasswordField), + "Edit General Config Popup" => Ok(Self::EditGeneralConfigPopup), + "Edit Keybindings Table" => Ok(Self::EditKeybindingsTable), + "Edit Specific Key Binding Popup" => Ok(Self::EditSpecificKeyBindingPopup), + "Email ID Field" => Ok(Self::EmailIDField), + "Extra Focus" => Ok(Self::ExtraFocus), "Filter By Tag Popup" => Ok(Self::FilterByTagPopup), + "Help" => Ok(Self::Help), + "Load Save" => Ok(Self::LoadSave), + "Log" => Ok(Self::Log), + "Main Menu Help" => Ok(Self::MainMenuHelp), + "Main Menu" => Ok(Self::MainMenu), + "New Board Description" => Ok(Self::NewBoardDescription), + "New Board Name" => Ok(Self::NewBoardName), + "New Card Name" => Ok(Self::CardName), + "No Focus" => Ok(Self::NoFocus), + "Password Field" => Ok(Self::PasswordField), + "Reset Password Link Field" => Ok(Self::ResetPasswordLinkField), + "Select Default View" => Ok(Self::SelectDefaultView), + "Send Reset Password Link Button" => Ok(Self::SendResetPasswordLinkButton), "Submit Button" => Ok(Self::SubmitButton), - "Extra Focus" => Ok(Self::ExtraFocus), + "Text Input" => Ok(Self::TextInput), + "Theme Editor BG" => Ok(Self::StyleEditorBG), + "Theme Editor FG" => Ok(Self::StyleEditorFG), + "Theme Editor Modifier" => Ok(Self::StyleEditorModifier), + "Theme Editor" => Ok(Self::ThemeEditor), + "Theme Selector" => Ok(Self::ThemeSelector), + "Title" => Ok(Self::Title), _ => Ok(Self::NoFocus), } } @@ -483,40 +585,43 @@ impl FromStr for Focus { impl KeyBindings { pub fn iter(&self) -> impl Iterator)> { vec![ - ("quit", &self.quit), - ("next_focus", &self.next_focus), - ("prev_focus", &self.prev_focus), - ("open_config_menu", &self.open_config_menu), - ("up", &self.up), - ("down", &self.down), - ("right", &self.right), - ("left", &self.left), - ("take_user_input", &self.take_user_input), - ("stop_user_input", &self.stop_user_input), - ("hide_ui_element", &self.hide_ui_element), - ("save_state", &self.save_state), - ("new_board", &self.new_board), - ("new_card", &self.new_card), - ("delete_card", &self.delete_card), - ("delete_board", &self.delete_board), ( - "change_card_status_to_completed", - &self.change_card_status_to_completed, + KeyBindingEnum::ChangeCardStatusToActive.to_str(), + &self.change_card_status_to_active, ), ( - "change_card_status_to_active", - &self.change_card_status_to_active, + KeyBindingEnum::ChangeCardStatusToCompleted.to_str(), + &self.change_card_status_to_completed, ), ( - "change_card_status_to_stale", + KeyBindingEnum::ChangeCardStatusToStale.to_str(), &self.change_card_status_to_stale, ), - ("reset_ui", &self.reset_ui), - ("go_to_main_menu", &self.go_to_main_menu), - ("toggle_command_palette", &self.toggle_command_palette), - ("clear_all_toasts", &self.clear_all_toasts), - ("undo", &self.undo), - ("redo", &self.redo), + ( + KeyBindingEnum::ClearAllToasts.to_str(), + &self.clear_all_toasts, + ), + (KeyBindingEnum::DeleteBoard.to_str(), &self.delete_board), + (KeyBindingEnum::DeleteCard.to_str(), &self.delete_card), + (KeyBindingEnum::Down.to_str(), &self.down), + (KeyBindingEnum::GoToMainMenu.to_str(), &self.go_to_main_menu), + ( + KeyBindingEnum::HideUiElement.to_str(), + &self.hide_ui_element, + ), + (KeyBindingEnum::Left.to_str(), &self.left), + (KeyBindingEnum::NewBoard.to_str(), &self.new_board), + (KeyBindingEnum::NewCard.to_str(), &self.new_card), + (KeyBindingEnum::NextFocus.to_str(), &self.next_focus), + ( + KeyBindingEnum::OpenConfigMenu.to_str(), + &self.open_config_menu, + ), + (KeyBindingEnum::PrvFocus.to_str(), &self.prev_focus), + (KeyBindingEnum::Quit.to_str(), &self.quit), + (KeyBindingEnum::Redo.to_str(), &self.redo), + (KeyBindingEnum::ResetUI.to_str(), &self.reset_ui), + (KeyBindingEnum::Right.to_str(), &self.right), ] .into_iter() } @@ -524,137 +629,130 @@ impl KeyBindings { pub fn key_to_action(self, key: Key) -> Option<&'static Action> { for (action, keys) in self.iter() { if keys.contains(&key) { - match action { - "quit" => return Some(&Action::Quit), - "next_focus" => return Some(&Action::NextFocus), - "prev_focus" => return Some(&Action::PrvFocus), - "open_config_menu" => return Some(&Action::OpenConfigMenu), - "up" => return Some(&Action::Up), - "down" => return Some(&Action::Down), - "right" => return Some(&Action::Right), - "left" => return Some(&Action::Left), - "take_user_input" => return Some(&Action::TakeUserInput), - "stop_user_input" => return Some(&Action::StopUserInput), - "hide_ui_element" => return Some(&Action::HideUiElement), - "save_state" => return Some(&Action::SaveState), - "new_board" => return Some(&Action::NewBoard), - "new_card" => return Some(&Action::NewCard), - "delete_card" => return Some(&Action::Delete), - "delete_board" => return Some(&Action::DeleteBoard), - "change_card_status_to_completed" => { - return Some(&Action::ChangeCardStatusToCompleted) - } - "change_card_status_to_active" => { - return Some(&Action::ChangeCardStatusToActive) - } - "change_card_status_to_stale" => return Some(&Action::ChangeCardStatusToStale), - "reset_ui" => return Some(&Action::ResetUI), - "go_to_main_menu" => return Some(&Action::GoToMainMenu), - "toggle_command_palette" => return Some(&Action::ToggleCommandPalette), - "clear_all_toasts" => return Some(&Action::ClearAllToasts), - "undo" => return Some(&Action::Undo), - "redo" => return Some(&Action::Redo), - _ => return None, - } + return self.clone().str_to_action(action); } } None } pub fn str_to_action(self, action: &str) -> Option<&'static Action> { - match action { - "quit" => Some(&Action::Quit), - "next_focus" => Some(&Action::NextFocus), - "prev_focus" => Some(&Action::PrvFocus), - "open_config_menu" => Some(&Action::OpenConfigMenu), - "up" => Some(&Action::Up), - "down" => Some(&Action::Down), - "right" => Some(&Action::Right), - "left" => Some(&Action::Left), - "take_user_input" => Some(&Action::TakeUserInput), - "stop_user_input" => Some(&Action::StopUserInput), - "hide_ui_element" => Some(&Action::HideUiElement), - "save_state" => Some(&Action::SaveState), - "new_board" => Some(&Action::NewBoard), - "new_card" => Some(&Action::NewCard), - "delete_card" => Some(&Action::Delete), - "delete_board" => Some(&Action::DeleteBoard), - "change_card_status_to_completed" => Some(&Action::ChangeCardStatusToCompleted), - "change_card_status_to_active" => Some(&Action::ChangeCardStatusToActive), - "change_card_status_to_stale" => Some(&Action::ChangeCardStatusToStale), - "reset_ui" => Some(&Action::ResetUI), - "go_to_main_menu" => Some(&Action::GoToMainMenu), - "toggle_command_palette" => Some(&Action::ToggleCommandPalette), - "clear_all_toasts" => Some(&Action::ClearAllToasts), - "undo" => Some(&Action::Undo), - "redo" => Some(&Action::Redo), - _ => None, + let keybinding_enum = KeyBindingEnum::from_str(action); + if let Some(keybinding_enum) = keybinding_enum { + return match keybinding_enum { + KeyBindingEnum::ChangeCardStatusToActive => Some(&Action::ChangeCardStatusToActive), + KeyBindingEnum::ChangeCardStatusToCompleted => { + Some(&Action::ChangeCardStatusToCompleted) + } + KeyBindingEnum::ChangeCardStatusToStale => Some(&Action::ChangeCardStatusToStale), + KeyBindingEnum::ClearAllToasts => Some(&Action::ClearAllToasts), + KeyBindingEnum::DeleteBoard => Some(&Action::DeleteBoard), + KeyBindingEnum::DeleteCard => Some(&Action::Delete), + KeyBindingEnum::Down => Some(&Action::Down), + KeyBindingEnum::GoToMainMenu => Some(&Action::GoToMainMenu), + KeyBindingEnum::HideUiElement => Some(&Action::HideUiElement), + KeyBindingEnum::Left => Some(&Action::Left), + KeyBindingEnum::NewBoard => Some(&Action::NewBoard), + KeyBindingEnum::NewCard => Some(&Action::NewCard), + KeyBindingEnum::NextFocus => Some(&Action::NextFocus), + KeyBindingEnum::OpenConfigMenu => Some(&Action::OpenConfigMenu), + KeyBindingEnum::PrvFocus => Some(&Action::PrvFocus), + KeyBindingEnum::Quit => Some(&Action::Quit), + KeyBindingEnum::Redo => Some(&Action::Redo), + KeyBindingEnum::ResetUI => Some(&Action::ResetUI), + KeyBindingEnum::Right => Some(&Action::Right), + KeyBindingEnum::SaveState => Some(&Action::SaveState), + KeyBindingEnum::StopUserInput => Some(&Action::StopUserInput), + KeyBindingEnum::TakeUserInput => Some(&Action::TakeUserInput), + KeyBindingEnum::ToggleCommandPalette => Some(&Action::ToggleCommandPalette), + KeyBindingEnum::Undo => Some(&Action::Undo), + KeyBindingEnum::Up => Some(&Action::Up), + }; + } else { + None } } pub fn edit_keybinding(&mut self, key: &str, keybinding: Vec) -> &mut Self { let mut keybinding = keybinding; keybinding.dedup(); - - match key { - "quit" => self.quit = keybinding, - "next_focus" => self.next_focus = keybinding, - "prev_focus" => self.prev_focus = keybinding, - "open_config_menu" => self.open_config_menu = keybinding, - "up" => self.up = keybinding, - "down" => self.down = keybinding, - "right" => self.right = keybinding, - "left" => self.left = keybinding, - "take_user_input" => self.take_user_input = keybinding, - "stop_user_input" => self.stop_user_input = keybinding, - "hide_ui_element" => self.hide_ui_element = keybinding, - "save_state" => self.save_state = keybinding, - "new_board" => self.new_board = keybinding, - "new_card" => self.new_card = keybinding, - "delete_card" => self.delete_card = keybinding, - "delete_board" => self.delete_board = keybinding, - "change_card_status_to_completed" => self.change_card_status_to_completed = keybinding, - "change_card_status_to_active" => self.change_card_status_to_active = keybinding, - "change_card_status_to_stale" => self.change_card_status_to_stale = keybinding, - "reset_ui" => self.reset_ui = keybinding, - "go_to_main_menu" => self.go_to_main_menu = keybinding, - "toggle_command_palette" => self.toggle_command_palette = keybinding, - "clear_all_toasts" => self.clear_all_toasts = keybinding, - "undo" => self.undo = keybinding, - "redo" => self.redo = keybinding, - _ => debug!("Invalid keybinding: {}", key), + let keybinding_enum = KeyBindingEnum::from_str(key); + if let Some(keybinding_enum) = keybinding_enum { + match keybinding_enum { + KeyBindingEnum::ChangeCardStatusToActive => { + self.change_card_status_to_active = keybinding + } + KeyBindingEnum::ChangeCardStatusToCompleted => { + self.change_card_status_to_completed = keybinding + } + KeyBindingEnum::ChangeCardStatusToStale => { + self.change_card_status_to_stale = keybinding + } + KeyBindingEnum::ClearAllToasts => self.clear_all_toasts = keybinding, + KeyBindingEnum::DeleteBoard => self.delete_board = keybinding, + KeyBindingEnum::DeleteCard => self.delete_card = keybinding, + KeyBindingEnum::Down => self.down = keybinding, + KeyBindingEnum::GoToMainMenu => self.go_to_main_menu = keybinding, + KeyBindingEnum::HideUiElement => self.hide_ui_element = keybinding, + KeyBindingEnum::Left => self.left = keybinding, + KeyBindingEnum::NewBoard => self.new_board = keybinding, + KeyBindingEnum::NewCard => self.new_card = keybinding, + KeyBindingEnum::NextFocus => self.next_focus = keybinding, + KeyBindingEnum::OpenConfigMenu => self.open_config_menu = keybinding, + KeyBindingEnum::PrvFocus => self.prev_focus = keybinding, + KeyBindingEnum::Quit => self.quit = keybinding, + KeyBindingEnum::Redo => self.redo = keybinding, + KeyBindingEnum::ResetUI => self.reset_ui = keybinding, + KeyBindingEnum::Right => self.right = keybinding, + KeyBindingEnum::SaveState => self.save_state = keybinding, + KeyBindingEnum::StopUserInput => self.stop_user_input = keybinding, + KeyBindingEnum::TakeUserInput => self.take_user_input = keybinding, + KeyBindingEnum::ToggleCommandPalette => self.toggle_command_palette = keybinding, + KeyBindingEnum::Undo => self.undo = keybinding, + KeyBindingEnum::Up => self.up = keybinding, + } + } else { + debug!("Invalid keybinding: {}", key); } self } pub fn get_keybinding(&self, action: &str) -> Option<&Vec> { - match action { - "quit" => Some(&self.quit), - "next_focus" => Some(&self.next_focus), - "prev_focus" => Some(&self.prev_focus), - "open_config_menu" => Some(&self.open_config_menu), - "up" => Some(&self.up), - "down" => Some(&self.down), - "right" => Some(&self.right), - "left" => Some(&self.left), - "take_user_input" => Some(&self.take_user_input), - "stop_user_input" => Some(&self.stop_user_input), - "hide_ui_element" => Some(&self.hide_ui_element), - "save_state" => Some(&self.save_state), - "new_board" => Some(&self.new_board), - "new_card" => Some(&self.new_card), - "delete_card" => Some(&self.delete_card), - "delete_board" => Some(&self.delete_board), - "change_card_status_to_completed" => Some(&self.change_card_status_to_completed), - "change_card_status_to_active" => Some(&self.change_card_status_to_active), - "change_card_status_to_stale" => Some(&self.change_card_status_to_stale), - "reset_ui" => Some(&self.reset_ui), - "go_to_main_menu" => Some(&self.go_to_main_menu), - "toggle_command_palette" => Some(&self.toggle_command_palette), - "clear_all_toasts" => Some(&self.clear_all_toasts), - "undo" => Some(&self.undo), - "redo" => Some(&self.redo), - _ => None, + let keybinding_enum = KeyBindingEnum::from_str(action); + if let Some(keybinding_enum) = keybinding_enum { + return match keybinding_enum { + KeyBindingEnum::ChangeCardStatusToActive => { + Some(&self.change_card_status_to_active) + } + KeyBindingEnum::ChangeCardStatusToCompleted => { + Some(&self.change_card_status_to_completed) + } + KeyBindingEnum::ChangeCardStatusToStale => Some(&self.change_card_status_to_stale), + KeyBindingEnum::ClearAllToasts => Some(&self.clear_all_toasts), + KeyBindingEnum::DeleteBoard => Some(&self.delete_board), + KeyBindingEnum::DeleteCard => Some(&self.delete_card), + KeyBindingEnum::Down => Some(&self.down), + KeyBindingEnum::GoToMainMenu => Some(&self.go_to_main_menu), + KeyBindingEnum::HideUiElement => Some(&self.hide_ui_element), + KeyBindingEnum::Left => Some(&self.left), + KeyBindingEnum::NewBoard => Some(&self.new_board), + KeyBindingEnum::NewCard => Some(&self.new_card), + KeyBindingEnum::NextFocus => Some(&self.next_focus), + KeyBindingEnum::OpenConfigMenu => Some(&self.open_config_menu), + KeyBindingEnum::PrvFocus => Some(&self.prev_focus), + KeyBindingEnum::Quit => Some(&self.quit), + KeyBindingEnum::Redo => Some(&self.redo), + KeyBindingEnum::ResetUI => Some(&self.reset_ui), + KeyBindingEnum::Right => Some(&self.right), + KeyBindingEnum::SaveState => Some(&self.save_state), + KeyBindingEnum::StopUserInput => Some(&self.stop_user_input), + KeyBindingEnum::TakeUserInput => Some(&self.take_user_input), + KeyBindingEnum::ToggleCommandPalette => Some(&self.toggle_command_palette), + KeyBindingEnum::Undo => Some(&self.undo), + KeyBindingEnum::Up => Some(&self.up), + }; + } else { + debug!("Invalid keybinding: {}", action); + None } } } @@ -662,31 +760,31 @@ impl KeyBindings { impl Default for KeyBindings { fn default() -> Self { Self { - quit: vec![Key::Ctrl('c'), Key::Char('q')], - next_focus: vec![Key::Tab], - prev_focus: vec![Key::BackTab], - open_config_menu: vec![Key::Char('c')], - up: vec![Key::Up], + change_card_status_to_active: vec![Key::Char('2')], + change_card_status_to_completed: vec![Key::Char('1')], + change_card_status_to_stale: vec![Key::Char('3')], + clear_all_toasts: vec![Key::Char('t')], + delete_board: vec![Key::Char('D')], + delete_card: vec![Key::Char('d')], down: vec![Key::Down], - right: vec![Key::Right], - left: vec![Key::Left], - take_user_input: vec![Key::Char('i')], - stop_user_input: vec![Key::Ins], + go_to_main_menu: vec![Key::Char('m')], hide_ui_element: vec![Key::Char('h')], - save_state: vec![Key::Ctrl('s')], + left: vec![Key::Left], new_board: vec![Key::Char('b')], new_card: vec![Key::Char('n')], - delete_card: vec![Key::Char('d')], - delete_board: vec![Key::Char('D')], - change_card_status_to_completed: vec![Key::Char('1')], - change_card_status_to_active: vec![Key::Char('2')], - change_card_status_to_stale: vec![Key::Char('3')], + next_focus: vec![Key::Tab], + open_config_menu: vec![Key::Char('c')], + prev_focus: vec![Key::BackTab], + quit: vec![Key::Ctrl('c'), Key::Char('q')], + redo: vec![Key::Ctrl('y')], reset_ui: vec![Key::Char('r')], - go_to_main_menu: vec![Key::Char('m')], + right: vec![Key::Right], + save_state: vec![Key::Ctrl('s')], + stop_user_input: vec![Key::Ins], + take_user_input: vec![Key::Char('i')], toggle_command_palette: vec![Key::Ctrl('p')], - clear_all_toasts: vec![Key::Char('t')], undo: vec![Key::Ctrl('z')], - redo: vec![Key::Ctrl('y')], + up: vec![Key::Up], } } } diff --git a/src/constants.rs b/src/constants.rs index 55b73f5..602041e 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,213 +1,57 @@ use crate::app::state::UiMode; -use ratatui::style::{Color, Modifier, Style}; -pub const FIELD_NOT_SET: &str = "Not Set"; -pub const FIELD_NA: &str = "N/A"; -pub const CONFIG_FILE_NAME: &str = "config.json"; +pub const REFRESH_TOKEN_FILE_NAME: &str = "kanban_token"; +pub const REFRESH_TOKEN_SEPARATOR: &str = "<<>>"; +pub const APP_TITLE: &str = "Rust 🦀 Kanban"; pub const CONFIG_DIR_NAME: &str = "rust_kanban"; -pub const SAVE_DIR_NAME: &str = "kanban_saves"; -pub const SAVE_FILE_NAME: &str = "kanban"; -pub const NO_OF_BOARDS_PER_PAGE: u16 = 3; -pub const MIN_NO_BOARDS_PER_PAGE: u16 = 1; -pub const MAX_NO_BOARDS_PER_PAGE: u16 = 5; -pub const NO_OF_CARDS_PER_BOARD: u16 = 2; -pub const MIN_NO_CARDS_PER_BOARD: u16 = 1; -pub const MAX_NO_CARDS_PER_BOARD: u16 = 4; +pub const CONFIG_FILE_NAME: &str = "config.json"; pub const DEFAULT_BOARD_TITLE_LENGTH: u16 = 20; pub const DEFAULT_CARD_TITLE_LENGTH: u16 = 20; -pub const APP_TITLE: &str = "Rust 🦀 Kanban"; -pub const MIN_TERM_WIDTH: u16 = 110; -pub const MIN_TERM_HEIGHT: u16 = 30; -pub const LIST_SELECTED_SYMBOL: &str = ">> "; -pub const VERTICAL_SCROLL_BAR_SYMBOL: &str = "█"; pub const DEFAULT_CARD_WARNING_DUE_DATE_DAYS: u16 = 3; -pub const MAX_TOASTS_TO_DISPLAY: usize = 5; -pub const SCREEN_TO_TOAST_WIDTH_RATIO: u16 = 3; // 1/3rd of the screen width -pub const TOAST_FADE_OUT_TIME: u64 = 400; -pub const TOAST_FADE_IN_TIME: u64 = 200; pub const DEFAULT_TICKRATE: u64 = 50; pub const DEFAULT_TOAST_DURATION: u64 = 5; +pub const DEFAULT_UI_MODE: UiMode = UiMode::TitleBodyHelpLog; +pub const ENCRYPTION_KEY_FILE_NAME: &str = "kanban_encryption_key"; +pub const FIELD_NA: &str = "N/A"; +pub const FIELD_NOT_SET: &str = "Not Set"; +pub const HIDDEN_PASSWORD_SYMBOL: char = '•'; pub const IO_EVENT_WAIT_TIME: u64 = 5; // ms +pub const LIST_SELECTED_SYMBOL: &str = ">> "; +pub const LOGIN_FORM_DEFAULT_STATE: ([&str; 2], bool) = (["", ""], false); +pub const MAX_NO_BOARDS_PER_PAGE: u16 = 5; +pub const MAX_NO_CARDS_PER_BOARD: u16 = 4; +pub const MAX_TOASTS_TO_DISPLAY: usize = 5; +pub const MIN_NO_BOARDS_PER_PAGE: u16 = 1; +pub const MIN_NO_CARDS_PER_BOARD: u16 = 1; +pub const MIN_TERM_HEIGHT: u16 = 30; +pub const MIN_TERM_WIDTH: u16 = 110; pub const MOUSE_OUT_OF_BOUNDS_COORDINATES: (u16, u16) = (9999, 9999); -pub const NEW_CARD_FORM_DEFAULT_STATE: [&str; 3] = ["", "", ""]; pub const NEW_BOARD_FORM_DEFAULT_STATE: [&str; 2] = ["", ""]; -pub const LOGIN_FORM_DEFAULT_STATE: ([&str; 2], bool) = (["", ""], false); -pub const SIGNUP_FORM_DEFAULT_STATE: ([&str; 3], bool) = (["", "", ""], false); +pub const NEW_CARD_FORM_DEFAULT_STATE: [&str; 3] = ["", "", ""]; +pub const NO_OF_BOARDS_PER_PAGE: u16 = 3; +pub const NO_OF_CARDS_PER_BOARD: u16 = 2; +pub const PATTERN_CHANGE_INTERVAL: u64 = 1000; // ms +pub const RANDOM_SEARCH_TERM: &str = "iibnigivirneiivure"; pub const RESET_PASSWORD_FORM_DEFAULT_STATE: ([&str; 4], bool) = (["", "", "", ""], false); pub const SAMPLE_TEXT: &str = "Sample Text"; +pub const SAVE_DIR_NAME: &str = "kanban_saves"; +pub const SAVE_FILE_NAME: &str = "kanban"; +pub const SAVE_FILE_REGEX: &str = r"^kanban_\d{2}-\d{2}-\d{4}_v\d+.json"; +pub const SCREEN_TO_TOAST_WIDTH_RATIO: u16 = 3; // 1/3rd of the screen width +pub const SIGNUP_FORM_DEFAULT_STATE: ([&str; 3], bool) = (["", "", ""], false); pub const THEME_DIR_NAME: &str = "themes"; pub const THEME_FILE_NAME: &str = "kanban_theme"; -pub const RANDOM_SEARCH_TERM: &str = "iibnigivirneiivure"; -pub const DEFAULT_UI_MODE: UiMode = UiMode::TitleBodyHelpLog; -pub const HIDDEN_PASSWORD_SYMBOL: char = '•'; -pub const SAVE_FILE_REGEX: &str = r"^kanban_\d{2}-\d{2}-\d{4}_v\d+.json"; -pub const ENCRYPTION_KEY_FILE_NAME: &str = "kanban_encryption_key"; -pub const ACCESS_TOKEN_FILE_NAME: &str = "kanban_access_token"; -pub const ACCESS_TOKEN_SEPARATOR: &str = "<<>>"; -pub const PATTERN_CHANGE_INTERVAL: u64 = 1000; // ms +pub const TOAST_FADE_IN_TIME: u64 = 200; +pub const TOAST_FADE_OUT_TIME: u64 = 400; +pub const VERTICAL_SCROLL_BAR_SYMBOL: &str = "█"; +pub const SPINNER_FRAMES: [&str; 7] = [ + "[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", +]; // Cloud Stuff +pub const MAX_PASSWORD_LENGTH: usize = 32; +pub const MIN_PASSWORD_LENGTH: usize = 8; pub const MIN_TIME_BETWEEN_SENDING_RESET_LINK: u64 = 60; // seconds -pub const SUPABASE_URL: &str = "https://kcpkbdobsyrtkawocudz.supabase.co"; pub const SUPABASE_ANON_KEY: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtjcGtiZG9ic3lydGthd29jdWR6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODA5NDkzOTksImV4cCI6MTk5NjUyNTM5OX0.N1jDZ2rFUDw9VtQbGQhBjonI0zy10lfJL-O2rBJlUOs"; -pub const MIN_PASSWORD_LENGTH: usize = 8; -pub const MAX_PASSWORD_LENGTH: usize = 32; +pub const SUPABASE_URL: &str = "https://kcpkbdobsyrtkawocudz.supabase.co"; -// Styles -pub const GENERAL_STYLE: Style = Style { - fg: Some(Color::White), - bg: Some(Color::Reset), - add_modifier: Modifier::empty(), - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LIST_SELECT_STYLE: Style = Style { - fg: Some(Color::White), - bg: Some(Color::LightMagenta), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_DUE_DATE_DEFAULT_STYLE: Style = Style { - fg: Some(Color::LightGreen), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_DUE_DATE_WARNING_STYLE: Style = Style { - fg: Some(Color::LightYellow), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_DUE_DATE_CRITICAL_STYLE: Style = Style { - fg: Some(Color::LightRed), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_ACTIVE_STATUS_STYLE: Style = Style { - fg: Some(Color::LightCyan), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_COMPLETED_STATUS_STYLE: Style = Style { - fg: Some(Color::LightGreen), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_STALE_STATUS_STYLE: Style = Style { - fg: Some(Color::DarkGray), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const KEYBOARD_FOCUS_STYLE: Style = Style { - fg: Some(Color::LightCyan), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const MOUSE_HIGHLIGHT_STYLE: Style = Style { - fg: Some(Color::Rgb(255, 165, 0)), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const HELP_KEY_STYLE: Style = Style { - fg: Some(Color::LightCyan), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LOG_ERROR_STYLE: Style = Style { - fg: Some(Color::LightRed), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LOG_DEBUG_STYLE: Style = Style { - fg: Some(Color::LightGreen), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LOG_WARN_STYLE: Style = Style { - fg: Some(Color::LightYellow), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LOG_TRACE_STYLE: Style = Style { - fg: Some(Color::Gray), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const LOG_INFO_STYLE: Style = Style { - fg: Some(Color::LightCyan), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const PROGRESS_BAR_STYLE: Style = Style { - fg: Some(Color::LightGreen), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const ERROR_TEXT_STYLE: Style = Style { - fg: Some(Color::LightRed), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const INACTIVE_TEXT_STYLE: Style = Style { - fg: Some(Color::Rgb(40, 40, 40)), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_PRIORITY_LOW_STYLE: Style = Style { - fg: Some(Color::LightGreen), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_PRIORITY_MEDIUM_STYLE: Style = Style { - fg: Some(Color::LightYellow), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const CARD_PRIORITY_HIGH_STYLE: Style = Style { - fg: Some(Color::LightRed), - bg: Some(Color::Reset), - add_modifier: Modifier::BOLD, - sub_modifier: Modifier::empty(), - underline_color: None, -}; -pub const SPINNER_FRAMES: [&str; 7] = [ - "[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", -]; diff --git a/src/inputs/key.rs b/src/inputs/key.rs index 0142bd6..59ee79a 100644 --- a/src/inputs/key.rs +++ b/src/inputs/key.rs @@ -5,45 +5,32 @@ use std::fmt::{self, Display, Formatter}; #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug, Serialize, Deserialize)] pub enum Key { - Esc, - - Backspace, + Alt(char), AltBackspace, - - Up, - ShiftUp, - CtrlUp, + AltDelete, + BackTab, + Backspace, + Char(char), + Ctrl(char), + CtrlAlt(char), + CtrlAltDown, + CtrlAltLeft, + CtrlAltRight, CtrlAltUp, - PageUp, - - Down, - ShiftDown, CtrlDown, - CtrlAltDown, - PageDown, - - Left, - ShiftLeft, CtrlLeft, - CtrlAltLeft, - - Right, - ShiftRight, CtrlRight, - CtrlAltRight, - - Enter, - - Tab, - BackTab, - - Space, - Ins, + CtrlUp, Delete, - Home, + Down, End, + Enter, + Esc, F0, F1, + F10, + F11, + F12, F2, F3, F4, @@ -52,15 +39,20 @@ pub enum Key { F7, F8, F9, - F10, - F11, - F12, - Char(char), - Ctrl(char), - Alt(char), - AltDelete, - CtrlAlt(char), + Home, + Ins, + Left, + PageDown, + PageUp, + Right, + ShiftDown, + ShiftLeft, + ShiftRight, + ShiftUp, + Space, + Tab, Unknown, + Up, } impl Key { @@ -82,29 +74,46 @@ impl Key { _ => panic!("unknown function key: F{}", n), } } - pub fn to_digit(&self) -> u8 { - match self { - Key::Char(c) => c.to_digit(10).unwrap() as u8, - _ => panic!("not a digit"), - } - } } impl Display for Key { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { - Key::Alt(' ') => write!(f, ""), - Key::Ctrl(' ') => write!(f, ""), - Key::Char(' ') => write!(f, ""), Key::Alt(c) => write!(f, "", c), - Key::Ctrl(c) => write!(f, "", c), - Key::Char(c) => write!(f, "<{}>", c), - Key::Tab => write!(f, ""), + Key::AltBackspace => write!(f, ""), + Key::AltDelete => write!(f, ""), Key::BackTab => write!(f, ""), - Key::ShiftUp => write!(f, ""), + Key::Backspace => write!(f, ""), + Key::Char(c) => write!(f, "<{}>", c), + Key::Ctrl(c) => write!(f, "", c), + Key::CtrlAlt(c) => write!(f, "", c), + Key::CtrlAltDown => write!(f, ""), + Key::CtrlAltLeft => write!(f, ""), + Key::CtrlAltRight => write!(f, ""), + Key::CtrlAltUp => write!(f, ""), + Key::CtrlDown => write!(f, ""), + Key::CtrlLeft => write!(f, ""), + Key::CtrlRight => write!(f, ""), + Key::CtrlUp => write!(f, ""), + Key::Delete => write!(f, ""), + Key::Down => write!(f, ""), + Key::End => write!(f, ""), + Key::Enter => write!(f, ""), + Key::Esc => write!(f, ""), + Key::Home => write!(f, ""), + Key::Ins => write!(f, ""), + Key::Left => write!(f, ""), + Key::PageDown => write!(f, ""), + Key::PageUp => write!(f, ""), + Key::Right => write!(f, ""), Key::ShiftDown => write!(f, ""), Key::ShiftLeft => write!(f, ""), Key::ShiftRight => write!(f, ""), + Key::ShiftUp => write!(f, ""), + Key::Space => write!(f, ""), + Key::Tab => write!(f, ""), + Key::Unknown => write!(f, ""), + Key::Up => write!(f, ""), _ => write!(f, "<{:?}>", self), } } @@ -279,40 +288,53 @@ impl From for Key { impl From<&str> for Key { fn from(s: &str) -> Self { + // handle char + if s.len() == 1 { + return Key::Char(s.chars().next().unwrap()); + } + // handle alt+char + if s.len() == 6 && s.starts_with("') { + return Key::Alt(s.chars().nth(5).unwrap()); + } + // handle ctrl+char + if s.len() == 7 && s.starts_with("') { + return Key::Ctrl(s.chars().nth(6).unwrap()); + } + // handle ctrl+alt+char + if s.len() == 10 && s.starts_with("') { + return Key::CtrlAlt(s.chars().nth(9).unwrap()); + } match s { - "Enter" => Key::Enter, - "Tab" => Key::Tab, - "Backspace" => Key::Backspace, - "Esc" => Key::Esc, - "Space" => Key::Space, - "Left" => Key::Left, - "Right" => Key::Right, - "Up" => Key::Up, - "Down" => Key::Down, - "Ins" => Key::Ins, - "Delete" => Key::Delete, - "Home" => Key::Home, - "End" => Key::End, - "PageUp" => Key::PageUp, - "PageDown" => Key::PageDown, - "F0" => Key::F0, - "F1" => Key::F1, - "F2" => Key::F2, - "F3" => Key::F3, - "F4" => Key::F4, - "F5" => Key::F5, - "F6" => Key::F6, - "F7" => Key::F7, - "F8" => Key::F8, - "F9" => Key::F9, - "F10" => Key::F10, - "F11" => Key::F11, - "F12" => Key::F12, - "BackTab" => Key::BackTab, - "ShiftUp" => Key::ShiftUp, - "ShiftDown" => Key::ShiftDown, - "ShiftLeft" => Key::ShiftLeft, - "ShiftRight" => Key::ShiftRight, + "" => Key::AltBackspace, + "" => Key::AltDelete, + "" => Key::Backspace, + "" => Key::CtrlAltDown, + "" => Key::CtrlAltLeft, + "" => Key::CtrlAltRight, + "" => Key::CtrlAltUp, + "" => Key::CtrlDown, + "" => Key::CtrlLeft, + "" => Key::CtrlRight, + "" => Key::CtrlUp, + "" => Key::Delete, + "" => Key::Down, + "" => Key::End, + "" => Key::Enter, + "" => Key::Esc, + "" => Key::Home, + "" => Key::Ins, + "" => Key::Left, + "" => Key::PageDown, + "" => Key::PageUp, + "" => Key::Right, + "" => Key::ShiftDown, + "" => Key::ShiftLeft, + "" => Key::ShiftRight, + "" => Key::ShiftUp, + "" => Key::Space, + "" => Key::Tab, + "" => Key::Unknown, + "" => Key::Up, _ => Key::Unknown, } } diff --git a/src/inputs/mouse.rs b/src/inputs/mouse.rs index 7b75b88..99bad72 100644 --- a/src/inputs/mouse.rs +++ b/src/inputs/mouse.rs @@ -4,30 +4,30 @@ use std::fmt::{self, Display, Formatter}; #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug, Serialize, Deserialize)] pub enum Mouse { + Drag(u16, u16), LeftPress, - RightPress, MiddlePress, - ScrollUp, + Move(u16, u16), + RightPress, ScrollDown, ScrollLeft, ScrollRight, - Move(u16, u16), - Drag(u16, u16), + ScrollUp, Unknown, } impl Display for Mouse { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { + Mouse::Drag(x, y) => write!(f, "", x, y), Mouse::LeftPress => write!(f, ""), - Mouse::RightPress => write!(f, ""), Mouse::MiddlePress => write!(f, ""), - Mouse::ScrollUp => write!(f, ""), + Mouse::Move(x, y) => write!(f, "", x, y), + Mouse::RightPress => write!(f, ""), Mouse::ScrollDown => write!(f, ""), Mouse::ScrollLeft => write!(f, ""), Mouse::ScrollRight => write!(f, ""), - Mouse::Move(x, y) => write!(f, "", x, y), - Mouse::Drag(x, y) => write!(f, "", x, y), + Mouse::ScrollUp => write!(f, ""), Mouse::Unknown => write!(f, ""), } } diff --git a/src/io/data_handler.rs b/src/io/data_handler.rs index 10a2804..6bd8560 100644 --- a/src/io/data_handler.rs +++ b/src/io/data_handler.rs @@ -277,9 +277,9 @@ pub fn export_kanban_to_json( config.date_format.to_human_readable_string() ); let export_struct = ExportStruct { - kanban_version: version.to_string(), - export_date: date, boards: boards.to_vec(), + export_date: date, + kanban_version: version.to_string(), }; let file_path = config.save_directory.join(file_name); let write_status = fs::write( @@ -380,7 +380,7 @@ fn write_default_config() { #[derive(Serialize, Deserialize, Debug)] pub struct ExportStruct { - pub kanban_version: String, - pub export_date: String, pub boards: Vec, + pub export_date: String, + pub kanban_version: String, } diff --git a/src/io/io_handler.rs b/src/io/io_handler.rs index 2797a84..cce1b23 100644 --- a/src/io/io_handler.rs +++ b/src/io/io_handler.rs @@ -8,9 +8,9 @@ use crate::{ UserLoginData, }, constants::{ - ACCESS_TOKEN_FILE_NAME, ACCESS_TOKEN_SEPARATOR, CONFIG_DIR_NAME, CONFIG_FILE_NAME, - ENCRYPTION_KEY_FILE_NAME, MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH, - MIN_TIME_BETWEEN_SENDING_RESET_LINK, SAVE_DIR_NAME, SUPABASE_ANON_KEY, SUPABASE_URL, + CONFIG_DIR_NAME, CONFIG_FILE_NAME, ENCRYPTION_KEY_FILE_NAME, MAX_PASSWORD_LENGTH, + MIN_PASSWORD_LENGTH, MIN_TIME_BETWEEN_SENDING_RESET_LINK, REFRESH_TOKEN_FILE_NAME, + REFRESH_TOKEN_SEPARATOR, SAVE_DIR_NAME, SUPABASE_ANON_KEY, SUPABASE_URL, }, io::data_handler::{get_default_save_directory, get_saved_themes, save_kanban_state_locally}, ui::TextColorOptions, @@ -99,8 +99,8 @@ impl IoAsyncHandler<'_> { app.keybinding_list_maker(); app.dispatch(IoEvent::ResetVisibleBoardsandCards).await; let saved_themes = get_saved_themes(); - if saved_themes.is_some() { - app.all_themes.extend(saved_themes.unwrap()); + if let Some(saved_themes) = saved_themes { + app.all_themes.extend(saved_themes); } let default_theme = app.config.default_theme.clone(); for theme in &app.all_themes { @@ -129,20 +129,20 @@ impl IoAsyncHandler<'_> { if app.config.auto_login { app.send_info_toast("Attempting to auto login", None); let user_login_data = - test_access_token_on_disk(app.state.encryption_key_from_arguments.clone()).await; + test_refresh_token_on_disk(app.state.encryption_key_from_arguments.clone()).await; if user_login_data.is_err() { - let access_token_file_path = get_config_dir(); - if access_token_file_path.is_err() { + let refresh_token_file_path = get_config_dir(); + if refresh_token_file_path.is_err() { error!("Cannot get config directory"); app.send_error_toast("Cannot get config directory", None); return Ok(()); } - let mut access_token_file_path = access_token_file_path.unwrap(); - access_token_file_path.push(ACCESS_TOKEN_FILE_NAME); - if access_token_file_path.exists() { - if let Err(err) = std::fs::remove_file(access_token_file_path) { - error!("Cannot delete access token file: {:?}", err); - app.send_error_toast("Cannot delete access token file", None); + let mut refresh_token_file_path = refresh_token_file_path.unwrap(); + refresh_token_file_path.push(REFRESH_TOKEN_FILE_NAME); + if refresh_token_file_path.exists() { + if let Err(err) = std::fs::remove_file(refresh_token_file_path) { + error!("Cannot delete refresh token file: {:?}", err); + app.send_error_toast("Cannot delete refresh token file", None); return Ok(()); } else { warn!("Previous access token has expired or does not exist. Please login again"); @@ -193,14 +193,14 @@ impl IoAsyncHandler<'_> { async fn load_save_file_local(&mut self) -> Result<()> { let mut app = self.app.lock().await; - let save_file_index = app.state.load_save_state.selected().unwrap_or(0); + let save_file_index = app.state.app_list_states.load_save.selected().unwrap_or(0); let local_files = get_available_local_save_files(&app.config); - let local_files = if local_files.is_none() { + let local_files = if let Some(local_files) = local_files { + local_files + } else { error!("Could not get local save files"); app.send_error_toast("Could not get local save files", None); vec![] - } else { - local_files.unwrap() }; if save_file_index >= local_files.len() { error!("Cannot load save file: No such file"); @@ -229,19 +229,19 @@ impl IoAsyncHandler<'_> { async fn delete_local_save_file(&mut self) -> Result<()> { let mut app = self.app.lock().await; let file_list = get_available_local_save_files(&app.config); - let file_list = if file_list.is_none() { + let file_list = if let Some(file_list) = file_list { + file_list + } else { error!("Cannot delete save file: no save files found"); app.send_error_toast("Cannot delete save file: no save files found", None); return Ok(()); - } else { - file_list.unwrap() }; - if app.state.load_save_state.selected().is_none() { + if app.state.app_list_states.load_save.selected().is_none() { error!("Cannot delete save file: no save file selected"); app.send_error_toast("Cannot delete save file: no save file selected", None); return Ok(()); } - let selected = app.state.load_save_state.selected().unwrap_or(0); + let selected = app.state.app_list_states.load_save.selected().unwrap_or(0); if selected >= file_list.len() { debug!("Cannot delete save file: index out of range"); app.send_error_toast("Cannot delete save file: Something went wrong", None); @@ -257,24 +257,27 @@ impl IoAsyncHandler<'_> { } else if let Err(err) = std::fs::remove_file(&path) { debug!("Cannot delete save file: {:?}", err); app.send_error_toast("Cannot delete save file: Something went wrong", None); - app.state.load_save_state = ListState::default(); + app.state.app_list_states.load_save = ListState::default(); return Ok(()); } else { info!("👍 Save file deleted"); app.send_info_toast("👍 Save file deleted", None); } let file_list = get_available_local_save_files(&app.config); - let file_list = if file_list.is_none() { - app.state.load_save_state = ListState::default(); - return Ok(()); + let file_list = if let Some(file_list) = file_list { + file_list } else { - file_list.unwrap() + app.state.app_list_states.load_save = ListState::default(); + return Ok(()); }; if selected >= file_list.len() { if file_list.is_empty() { - app.state.load_save_state = ListState::default(); + app.state.app_list_states.load_save = ListState::default(); } else { - app.state.load_save_state.select(Some(file_list.len() - 1)); + app.state + .app_list_states + .load_save + .select(Some(file_list.len() - 1)); } } Ok(()) @@ -296,19 +299,19 @@ impl IoAsyncHandler<'_> { async fn load_local_preview(&mut self) -> Result<()> { let mut app = self.app.lock().await; - if app.state.load_save_state.selected().is_none() { + if app.state.app_list_states.load_save.selected().is_none() { return Ok(()); } app.state.preview_boards_and_cards = None; - let save_file_index = app.state.load_save_state.selected().unwrap_or(0); + let save_file_index = app.state.app_list_states.load_save.selected().unwrap_or(0); let local_files = get_available_local_save_files(&app.config); - let local_files = if local_files.is_none() { + let local_files = if let Some(local_files) = local_files { + local_files + } else { error!("Could not get local save files"); app.send_error_toast("Could not get local save files", None); vec![] - } else { - local_files.unwrap() }; if save_file_index >= local_files.len() { error!("Cannot load preview: No such file"); @@ -394,16 +397,17 @@ impl IoAsyncHandler<'_> { app.send_error_toast("Error logging in", None); return Ok(()); } - let (access_token, user_id) = login_for_user_status.unwrap(); + let (access_token, user_id, refresh_token) = login_for_user_status.unwrap(); let mut app = self.app.lock().await; app.state.user_login_data.auth_token = Some(access_token.to_string()); + app.state.user_login_data.refresh_token = Some(refresh_token.to_string()); app.state.user_login_data.email_id = Some(email_id.to_string()); app.state.user_login_data.user_id = Some(user_id.to_string()); app.main_menu.logged_in = true; if app.config.auto_login { - save_access_token_to_disk( - &access_token, + save_refresh_token_to_disk( + &refresh_token, &email_id, app.state.encryption_key_from_arguments.clone(), ) @@ -466,7 +470,7 @@ impl IoAsyncHandler<'_> { let mut app = self.app.lock().await; app.send_error_toast("Error logging out", None); } - delete_access_token_from_disk().await?; + delete_refresh_token_from_disk().await?; Ok(()) } @@ -814,6 +818,7 @@ impl IoAsyncHandler<'_> { } let error_url = error_url.unwrap(); let error_url = error_url.to_string(); + debug!("Error verifying reset password link: {}", error_url); let access_token = error_url.split("access_token="); let access_token = access_token.last(); if access_token.is_none() { @@ -893,10 +898,10 @@ impl IoAsyncHandler<'_> { let save_ids = self.get_save_ids_for_user().await?; let max_save_id = save_ids.iter().max(); - let max_save_id = if max_save_id.is_none() { - 0 + let max_save_id = if let Some(max_save_id) = max_save_id { + max_save_id + 1 } else { - max_save_id.unwrap() + 1 + 0 }; let mut app = self.app.lock().await; @@ -1050,7 +1055,7 @@ impl IoAsyncHandler<'_> { async fn preview_cloud_save(&mut self) -> Result<()> { { let mut app = self.app.lock().await; - if app.state.load_save_state.selected().is_none() { + if app.state.app_list_states.load_save.selected().is_none() { error!("No save selected to preview"); app.send_error_toast("No save selected to preview", None); return Ok(()); @@ -1058,7 +1063,7 @@ impl IoAsyncHandler<'_> { } let mut app = self.app.lock().await; - let selected_index = app.state.load_save_state.selected().unwrap(); + let selected_index = app.state.app_list_states.load_save.selected().unwrap(); let cloud_data = app.state.cloud_data.clone(); if cloud_data.is_none() { debug!("No cloud data preview found to select"); @@ -1145,14 +1150,14 @@ impl IoAsyncHandler<'_> { async fn load_save_file_cloud(&mut self) -> Result<()> { let mut app = self.app.lock().await; - let save_file_index = app.state.load_save_state.selected().unwrap_or(0); + let save_file_index = app.state.app_list_states.load_save.selected().unwrap_or(0); let cloud_saves = app.state.cloud_data.clone(); - let local_files = if cloud_saves.is_none() { + let local_files = if let Some(cloud_saves) = cloud_saves { + cloud_saves + } else { error!("Could not get local save files"); app.send_error_toast("Could not get local save files", None); vec![] - } else { - cloud_saves.unwrap() }; if save_file_index >= local_files.len() { error!("Cannot load save file: No such file"); @@ -1210,15 +1215,15 @@ impl IoAsyncHandler<'_> { } let mut app = self.app.lock().await; - let save_file_index = app.state.load_save_state.selected().unwrap_or(0); + let save_file_index = app.state.app_list_states.load_save.selected().unwrap_or(0); let user_access_token = app.state.user_login_data.auth_token.clone().unwrap(); let cloud_saves = app.state.cloud_data.clone(); - let cloud_saves = if cloud_saves.is_none() { + let cloud_saves = if let Some(cloud_saves) = cloud_saves { + cloud_saves + } else { error!("Could not get local save files"); app.send_error_toast("Could not get local save files", None); return Ok(()); - } else { - cloud_saves.unwrap() }; if save_file_index >= cloud_saves.len() { error!("Cannot delete save file: No such file"); @@ -1871,7 +1876,7 @@ pub async fn login_for_user( email_id: &str, password: &str, cli_mode: bool, -) -> Result<(String, String), String> { +) -> Result<(String, String, String), String> { let request_body = json!( { "email": email_id, @@ -1906,7 +1911,8 @@ pub async fn login_for_user( match body { Ok(body) => { let access_token = body.get("access_token"); - match access_token { + let refresh_token = body.get("refresh_token"); + let access_token_result = match access_token { Some(access_token) => { let access_token = access_token.as_str().unwrap(); if cli_mode { @@ -1937,6 +1943,45 @@ pub async fn login_for_user( } Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()) } + }; + let refresh_token_result = match refresh_token { + Some(refresh_token) => { + let refresh_token = refresh_token.as_str().unwrap(); + if cli_mode { + print_debug(&format!("Refresh token: {}", refresh_token)); + } else { + debug!("Refresh token: {}", refresh_token); + } + Ok(refresh_token.to_string()) + } + None => { + if cli_mode { + print_error("Error logging in"); + print_debug(&format!( + "status code {}, response body: {:?}, could not find refresh token", + status, body + )); + } else { + error!("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer"); + debug!( + "status code {}, response body: {:?}, could not find refresh token", + status, body + ); + } + Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()) + } + }; + + if access_token_result.is_err() || refresh_token_result.is_err() { + return Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()); + } else { + let access_token_result = access_token_result.unwrap(); + let refresh_token_result = refresh_token_result.unwrap(); + Ok(( + access_token_result.0, + access_token_result.1, + refresh_token_result, + )) } } Err(e) => Err(format!("Error logging in: {}", e)), @@ -1999,22 +2044,22 @@ pub async fn login_for_user( } } -async fn save_access_token_to_disk( - access_token: &str, +async fn save_refresh_token_to_disk( + refresh_token: &str, email_id: &str, encryption_key_from_arguments: Option, ) -> Result<()> { let base64_engine = base64::engine::general_purpose::URL_SAFE_NO_PAD; - let access_token_path = get_config_dir(); - if access_token_path.is_err() { + let refresh_token_path = get_config_dir(); + if refresh_token_path.is_err() { return Err(anyhow!("Error getting config directory")); } - let mut access_token_path = access_token_path.unwrap(); - access_token_path.push(ACCESS_TOKEN_FILE_NAME); - if access_token_path.exists() { - let delete_file_status = std::fs::remove_file(&access_token_path); + let mut refresh_token_path = refresh_token_path.unwrap(); + refresh_token_path.push(REFRESH_TOKEN_FILE_NAME); + if refresh_token_path.exists() { + let delete_file_status = std::fs::remove_file(&refresh_token_path); if delete_file_status.is_err() { - return Err(anyhow!("Error deleting access token file")); + return Err(anyhow!("Error deleting refresh token file")); } } let encryption_key = get_user_encryption_key(encryption_key_from_arguments); @@ -2025,73 +2070,73 @@ async fn save_access_token_to_disk( let key = Key::::from_slice(&encryption_key); let cipher = Aes256Gcm::new(key); let nonce = Aes256Gcm::generate_nonce(&mut OsRng); - let encrypted_access_token = cipher.encrypt(&nonce, access_token.as_bytes()); - if encrypted_access_token.is_err() { - return Err(anyhow!("Error encrypting access token")); + let encrypted_refresh_token = cipher.encrypt(&nonce, refresh_token.as_bytes()); + if encrypted_refresh_token.is_err() { + return Err(anyhow!("Error encrypting refresh token")); } - let encrypted_access_token = encrypted_access_token.unwrap(); + let encrypted_refresh_token = encrypted_refresh_token.unwrap(); let nonce = nonce.to_vec(); let nonce = base64_engine.encode(nonce); - let encrypted_access_token = base64_engine.encode(encrypted_access_token); + let encrypted_refresh_token = base64_engine.encode(encrypted_refresh_token); let encoded_email_id = base64_engine.encode(email_id.as_bytes()); - let access_token_data = format!( + let refresh_token_data = format!( "{}{}{}{}{}", nonce, - ACCESS_TOKEN_SEPARATOR, - encrypted_access_token, - ACCESS_TOKEN_SEPARATOR, + REFRESH_TOKEN_SEPARATOR, + encrypted_refresh_token, + REFRESH_TOKEN_SEPARATOR, encoded_email_id ); - let file_creation_status = std::fs::write(&access_token_path, access_token_data); + let file_creation_status = std::fs::write(&refresh_token_path, refresh_token_data); if file_creation_status.is_err() { - return Err(anyhow!("Error creating access token file")); + return Err(anyhow!("Error creating refresh token file")); } Ok(()) } -fn get_access_token_from_disk( +fn get_refresh_token_from_disk( encryption_key_from_arguments: Option, ) -> Result<(String, String)> { let base64_engine = base64::engine::general_purpose::URL_SAFE_NO_PAD; - let access_token_path = get_config_dir(); - if access_token_path.is_err() { + let refresh_token_path = get_config_dir(); + if refresh_token_path.is_err() { return Err(anyhow!("Error getting config directory")); } - let mut access_token_path = access_token_path.unwrap(); - access_token_path.push(ACCESS_TOKEN_FILE_NAME); - let access_token_data = std::fs::read_to_string(&access_token_path); - if access_token_data.is_err() { - return Err(anyhow!("Error reading access token file")); + let mut refresh_token_path = refresh_token_path.unwrap(); + refresh_token_path.push(REFRESH_TOKEN_FILE_NAME); + let refresh_token_data = std::fs::read_to_string(&refresh_token_path); + if refresh_token_data.is_err() { + return Err(anyhow!("Error reading refresh token file")); } - let access_token_data = access_token_data.unwrap(); - let access_token_data = access_token_data - .split(ACCESS_TOKEN_SEPARATOR) + let refresh_token_data = refresh_token_data.unwrap(); + let refresh_token_data = refresh_token_data + .split(REFRESH_TOKEN_SEPARATOR) .collect::>(); - if access_token_data.len() != 3 { - return Err(anyhow!("Error reading access token file")); + if refresh_token_data.len() != 3 { + return Err(anyhow!("Error reading refresh token file")); } - let nonce = access_token_data[0]; + let nonce = refresh_token_data[0]; let nonce = base64_engine.decode(nonce); if nonce.is_err() { - return Err(anyhow!("Error reading access token file")); + return Err(anyhow!("Error reading refresh token file")); } let nonce = nonce.unwrap(); let nonce = GenericArray::from_slice(&nonce); - let encrypted_access_token = access_token_data[1]; - let encrypted_access_token = base64_engine.decode(encrypted_access_token); - if encrypted_access_token.is_err() { - return Err(anyhow!("Error reading access token file")); + let encrypted_refresh_token = refresh_token_data[1]; + let encrypted_refresh_token = base64_engine.decode(encrypted_refresh_token); + if encrypted_refresh_token.is_err() { + return Err(anyhow!("Error reading refresh token file")); } - let encrypted_access_token = encrypted_access_token.unwrap(); - let email_id = access_token_data[2]; + let encrypted_refresh_token = encrypted_refresh_token.unwrap(); + let email_id = refresh_token_data[2]; let email_id = base64_engine.decode(email_id); if email_id.is_err() { - return Err(anyhow!("Error reading access token file")); + return Err(anyhow!("Error reading refresh token file")); } let email_id = email_id.unwrap(); let email_id = String::from_utf8(email_id); if email_id.is_err() { - return Err(anyhow!("Error reading access token file")); + return Err(anyhow!("Error reading refresh token file")); } let email_id = email_id.unwrap(); let encryption_key = get_user_encryption_key(encryption_key_from_arguments); @@ -2101,45 +2146,172 @@ fn get_access_token_from_disk( let encryption_key = encryption_key.unwrap(); let key = Key::::from_slice(&encryption_key); let cipher = Aes256Gcm::new(key); - let decrypted_access_token = cipher.decrypt(nonce, encrypted_access_token.as_slice()); - if decrypted_access_token.is_err() { - return Err(anyhow!("Error decrypting access token")); - } - let decrypted_access_token = decrypted_access_token.unwrap(); - let decrypted_access_token = String::from_utf8(decrypted_access_token); - if decrypted_access_token.is_err() { - return Err(anyhow!("Error converting decrypted access token to string")); - } - let decrypted_access_token = decrypted_access_token.unwrap(); - Ok((decrypted_access_token, email_id)) + let decrypted_refresh_token = cipher.decrypt(nonce, encrypted_refresh_token.as_slice()); + if decrypted_refresh_token.is_err() { + return Err(anyhow!("Error decrypting refresh token")); + } + let decrypted_refresh_token = decrypted_refresh_token.unwrap(); + let decrypted_refresh_token = String::from_utf8(decrypted_refresh_token); + if decrypted_refresh_token.is_err() { + return Err(anyhow!( + "Error converting decrypted refresh token to string" + )); + } + let decrypted_refresh_token = decrypted_refresh_token.unwrap(); + Ok((decrypted_refresh_token, email_id)) } -async fn delete_access_token_from_disk() -> Result<()> { - let access_token_path = get_config_dir(); - if access_token_path.is_err() { +async fn delete_refresh_token_from_disk() -> Result<()> { + let refresh_token_path = get_config_dir(); + if refresh_token_path.is_err() { return Err(anyhow!("Error getting config directory")); } - let mut access_token_path = access_token_path.unwrap(); - access_token_path.push(ACCESS_TOKEN_FILE_NAME); - if !access_token_path.exists() { + let mut refresh_token_path = refresh_token_path.unwrap(); + refresh_token_path.push(REFRESH_TOKEN_FILE_NAME); + if !refresh_token_path.exists() { return Ok(()); } - let delete_file_status = std::fs::remove_file(&access_token_path); + let delete_file_status = std::fs::remove_file(&refresh_token_path); if delete_file_status.is_err() { - return Err(anyhow!("Error deleting access token file")); + return Err(anyhow!("Error deleting refresh token file")); } Ok(()) } -async fn test_access_token_on_disk( +async fn refresh_access_token(refresh_token: &str) -> Result<(String, String, String), String> { + let request_body = json!( + { + "grant_type": "refresh_token", + "refresh_token": refresh_token + } + ); + let client = reqwest::Client::new(); + let response = client + .post(format!( + "{}/auth/v1/token?grant_type=refresh_token", + SUPABASE_URL + )) + .header("apikey", SUPABASE_ANON_KEY) + .header("Content-Type", "application/json") + .body(request_body.to_string()) + .send() + .await; + if let Err(e) = response { + debug!("Error logging in: {}", e); + error!("Error logging in, Something went wrong, please try again later"); + return Err("Error logging in, Something went wrong, please try again later".to_string()); + } + let response = response.unwrap(); + let status = response.status(); + let body = response.json::().await; + if status == StatusCode::OK { + match body { + Ok(body) => { + let access_token = body.get("access_token"); + let refresh_token = body.get("refresh_token"); + let access_token_result = match access_token { + Some(access_token) => { + let access_token = access_token.as_str().unwrap(); + info!("🚀 Login successful"); + debug!("Access token: {}", access_token); + let user_id = get_user_id_from_database(access_token, false) + .await + .unwrap_or_else(|_| "Error getting user id".to_string()); + Ok((access_token.to_string(), user_id)) + } + None => { + error!("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer"); + debug!( + "status code {}, response body: {:?}, could not find access token", + status, body + ); + Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()) + } + }; + let refresh_token_result = match refresh_token { + Some(refresh_token) => { + let refresh_token = refresh_token.as_str().unwrap(); + debug!("Refresh token: {}", refresh_token); + Ok(refresh_token.to_string()) + } + None => { + error!("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer"); + debug!( + "status code {}, response body: {:?}, could not find refresh token", + status, body + ); + Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()) + } + }; + + if access_token_result.is_err() || refresh_token_result.is_err() { + return Err("Error logging in, If this is your first login attempt after signup please login again, if it is not please contact the developer".to_string()); + } else { + let access_token_result = access_token_result.unwrap(); + let refresh_token_result = refresh_token_result.unwrap(); + Ok(( + access_token_result.0, + access_token_result.1, + refresh_token_result, + )) + } + } + Err(e) => Err(format!("Error logging in: {}", e)), + } + } else if status == StatusCode::TOO_MANY_REQUESTS { + error!("Too many requests, please try again later. Due to the free nature of supabase i am limited to only 4 signup requests per hour. Sorry! 😢"); + debug!("status code {}, response body: {:?}", status, body); + Err("Too many requests, please try again later. Due to the free nature of supabase i am limited to only 4 signup requests per hour. Sorry! 😢".to_string()) + } else { + match body { + Ok(body) => { + let error_description = body.get("error_description"); + match error_description { + Some(error_description) => { + let error_description = error_description.to_string(); + error!("{}", error_description); + debug!("status code {}, response body: {:?}", status, body); + Err(format!("Error logging in: {}", error_description)) + } + None => { + error!("Error logging in"); + debug!("status code {}, response body: {:?}", status, body); + Err("Error logging in".to_string()) + } + } + } + Err(e) => { + error!("Error logging in: {}", e); + Err(format!("Error logging in: {}", e)) + } + } + } +} + +async fn test_refresh_token_on_disk( encryption_key_from_arguments: Option, ) -> Result { - let (access_token, email_id) = get_access_token_from_disk(encryption_key_from_arguments)?; - let user_id = get_user_id_from_database(&access_token, false).await?; + let (refresh_token, email_id) = + get_refresh_token_from_disk(encryption_key_from_arguments.clone())?; + debug!("refresh_token: {:?}", refresh_token); + let status = refresh_access_token(&refresh_token).await; + if status.is_err() { + return Err(anyhow!(status.err().unwrap())); + } + let status = status.unwrap(); + let access_token = status.0; + let user_id = status.1; + let refresh_token = status.2; + let save_status = + save_refresh_token_to_disk(&refresh_token, &email_id, encryption_key_from_arguments).await; + if save_status.is_err() { + error!("Error saving refresh token to disk"); + } let user_data = UserLoginData { - auth_token: Some(access_token.clone()), - email_id: Some(email_id.clone()), - user_id: Some(user_id.clone()), + auth_token: Some(access_token), + email_id: Some(email_id), + refresh_token: Some(refresh_token), + user_id: Some(user_id), }; Ok(user_data) } diff --git a/src/io/mod.rs b/src/io/mod.rs index eeccf67..2b3c5d8 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -4,21 +4,21 @@ pub mod logger; #[derive(Debug, Clone)] pub enum IoEvent { - Initialize, - SaveLocalData, - LoadSaveLocal, - LoadSaveCloud, - DeleteLocalSave, - ResetVisibleBoardsandCards, AutoSave, - LoadLocalPreview, - Login(String, String), - SignUp(String, String, String), - SendResetPasswordEmail(String), - ResetPassword(String, String, String), - SyncLocalData, DeleteCloudSave, + DeleteLocalSave, GetCloudData, + Initialize, LoadCloudPreview, + LoadLocalPreview, + LoadSaveCloud, + LoadSaveLocal, + Login(String, String), Logout, + ResetPassword(String, String, String), + ResetVisibleBoardsandCards, + SaveLocalData, + SendResetPasswordEmail(String), + SignUp(String, String, String), + SyncLocalData, } diff --git a/src/main.rs b/src/main.rs index fcf978d..afcac1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use rust_kanban::{ app::App, constants::APP_TITLE, io::{io_handler::IoAsyncHandler, logger, IoEvent}, - util::{gen_new_key_main, reset_app_main, start_ui}, + util::{gen_new_key_main, print_error, reset_app_main, start_ui}, }; use std::{io::stdout, sync::Arc}; @@ -82,7 +82,9 @@ async fn main() -> Result<()> { if args.generate_new_encryption_key { if args.email_id.is_none() || args.password.is_none() { println!(); - println!("[ERROR] - Please provide email id (-e) and password (-p) to reset you encryption key"); + print_error( + "Please provide your email id (-e) and password (-p) to reset your encryption key", + ); println!(); return Ok(()); } @@ -90,7 +92,7 @@ async fn main() -> Result<()> { return Ok(()); } else if args.email_id.is_some() || args.password.is_some() { println!(); - println!("[ERROR] - Please provide the -g or --generate-new-encryption-key flag to generate a new encryption key"); + print_error("Please provide the -g or --generate-new-encryption-key flag to generate a new encryption key"); println!(); return Ok(()); } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index a8033e5..70f11f6 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,12 +1,9 @@ use crate::{ app::App, - constants::{ - CARD_ACTIVE_STATUS_STYLE, CARD_COMPLETED_STATUS_STYLE, CARD_DUE_DATE_CRITICAL_STYLE, - CARD_DUE_DATE_DEFAULT_STYLE, CARD_DUE_DATE_WARNING_STYLE, CARD_PRIORITY_HIGH_STYLE, - CARD_PRIORITY_LOW_STYLE, CARD_PRIORITY_MEDIUM_STYLE, CARD_STALE_STATUS_STYLE, - ERROR_TEXT_STYLE, GENERAL_STYLE, HELP_KEY_STYLE, INACTIVE_TEXT_STYLE, KEYBOARD_FOCUS_STYLE, - LIST_SELECT_STYLE, LOG_DEBUG_STYLE, LOG_ERROR_STYLE, LOG_INFO_STYLE, LOG_TRACE_STYLE, - LOG_WARN_STYLE, MOUSE_HIGHLIGHT_STYLE, PROGRESS_BAR_STYLE, SAMPLE_TEXT, + constants::SAMPLE_TEXT, + ui::themes::{ + cyberpunk_theme, default_theme, dracula_theme, light_theme, matrix_theme, metro_theme, + midnight_blue_theme, slate_theme, }, }; use log::debug; @@ -19,470 +16,56 @@ use serde::{Deserialize, Serialize}; use std::fmt::{self, Display}; pub mod text_box; +pub mod themes; pub mod ui_helper; pub mod ui_main; pub mod widgets; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Theme { - pub name: String, - pub general_style: Style, - pub list_select_style: Style, pub card_due_default_style: Style, - pub card_due_warning_style: Style, pub card_due_overdue_style: Style, + pub card_due_warning_style: Style, + pub card_priority_high_style: Style, + pub card_priority_low_style: Style, + pub card_priority_medium_style: Style, pub card_status_active_style: Style, pub card_status_completed_style: Style, pub card_status_stale_style: Style, - pub keyboard_focus_style: Style, - pub mouse_focus_style: Style, + pub error_text_style: Style, + pub general_style: Style, pub help_key_style: Style, pub help_text_style: Style, - pub log_error_style: Style, + pub inactive_text_style: Style, + pub keyboard_focus_style: Style, + pub list_select_style: Style, pub log_debug_style: Style, - pub log_warn_style: Style, - pub log_trace_style: Style, + pub log_error_style: Style, pub log_info_style: Style, + pub log_trace_style: Style, + pub log_warn_style: Style, + pub mouse_focus_style: Style, + pub name: String, pub progress_bar_style: Style, - pub error_text_style: Style, - pub inactive_text_style: Style, - pub card_priority_low_style: Style, - pub card_priority_medium_style: Style, - pub card_priority_high_style: Style, } impl Default for Theme { - fn default() -> Theme { - Theme { - name: "Default Theme".to_string(), - general_style: GENERAL_STYLE, - list_select_style: LIST_SELECT_STYLE, - card_due_default_style: CARD_DUE_DATE_DEFAULT_STYLE, - card_due_warning_style: CARD_DUE_DATE_WARNING_STYLE, - card_due_overdue_style: CARD_DUE_DATE_CRITICAL_STYLE, - card_status_active_style: CARD_ACTIVE_STATUS_STYLE, - card_status_completed_style: CARD_COMPLETED_STATUS_STYLE, - card_status_stale_style: CARD_STALE_STATUS_STYLE, - keyboard_focus_style: KEYBOARD_FOCUS_STYLE, - mouse_focus_style: MOUSE_HIGHLIGHT_STYLE, - help_key_style: HELP_KEY_STYLE, - help_text_style: GENERAL_STYLE, - log_error_style: LOG_ERROR_STYLE, - log_debug_style: LOG_DEBUG_STYLE, - log_warn_style: LOG_WARN_STYLE, - log_trace_style: LOG_TRACE_STYLE, - log_info_style: LOG_INFO_STYLE, - progress_bar_style: PROGRESS_BAR_STYLE, - error_text_style: ERROR_TEXT_STYLE, - inactive_text_style: INACTIVE_TEXT_STYLE, - card_priority_low_style: CARD_PRIORITY_LOW_STYLE, - card_priority_medium_style: CARD_PRIORITY_MEDIUM_STYLE, - card_priority_high_style: CARD_PRIORITY_HIGH_STYLE, - } + fn default() -> Self { + default_theme() } } impl Theme { - fn midnight_blue() -> Theme { - Theme { - name: "Midnight Blue".to_string(), - general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), - list_select_style: Style::default() - .fg(Color::Gray) - .bg(Color::Rgb(70, 130, 180)), - card_due_default_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), - card_due_warning_style: Style::default() - .fg(Color::LightYellow) - .bg(Color::Rgb(25, 25, 112)), - card_due_overdue_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 112)), - card_status_active_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(25, 25, 112)), - card_status_completed_style: Style::default() - .fg(Color::Gray) - .bg(Color::Rgb(25, 25, 112)), - card_status_stale_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(25, 25, 112)), - keyboard_focus_style: Style::default() - .fg(Color::LightBlue) - .bg(Color::Rgb(25, 25, 112)) - .add_modifier(Modifier::BOLD), - mouse_focus_style: Style::default() - .fg(Color::LightBlue) - .bg(Color::Rgb(25, 25, 112)) - .add_modifier(Modifier::BOLD), - help_key_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), - help_text_style: Style::default() - .fg(Color::DarkGray) - .bg(Color::Rgb(25, 25, 112)), - log_error_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 112)), - log_debug_style: Style::default() - .fg(Color::LightBlue) - .bg(Color::Rgb(25, 25, 112)), - log_warn_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(25, 25, 112)), - log_trace_style: Style::default() - .fg(Color::LightCyan) - .bg(Color::Rgb(25, 25, 112)), - log_info_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(25, 25, 112)), - progress_bar_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(25, 25, 112)), - error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), - inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_priority_low_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(25, 25, 112)), - card_priority_medium_style: Style::default() - .fg(Color::LightYellow) - .bg(Color::Rgb(25, 25, 112)), - card_priority_high_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 112)), - } - } - fn slate() -> Theme { - Theme { - name: "Slate".to_string(), - general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), - list_select_style: Style::default() - .fg(Color::Gray) - .bg(Color::Rgb(70, 130, 180)), - card_due_default_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), - card_due_warning_style: Style::default() - .fg(Color::LightYellow) - .bg(Color::Rgb(47, 79, 79)), - card_due_overdue_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(47, 79, 79)), - card_status_active_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(47, 79, 79)), - card_status_completed_style: Style::default() - .fg(Color::Gray) - .bg(Color::Rgb(47, 79, 79)), - card_status_stale_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(47, 79, 79)), - keyboard_focus_style: Style::default() - .fg(Color::LightCyan) - .bg(Color::Rgb(47, 79, 79)) - .add_modifier(Modifier::BOLD), - mouse_focus_style: Style::default() - .fg(Color::LightCyan) - .bg(Color::Rgb(47, 79, 79)) - .add_modifier(Modifier::BOLD), - help_key_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), - help_text_style: Style::default() - .fg(Color::DarkGray) - .bg(Color::Rgb(47, 79, 79)), - log_error_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(47, 79, 79)), - log_debug_style: Style::default() - .fg(Color::LightBlue) - .bg(Color::Rgb(47, 79, 79)), - log_warn_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(47, 79, 79)), - log_trace_style: Style::default() - .fg(Color::LightCyan) - .bg(Color::Rgb(47, 79, 79)), - log_info_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(47, 79, 79)), - progress_bar_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(47, 79, 79)), - error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), - inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_priority_low_style: Style::default() - .fg(Color::LightGreen) - .bg(Color::Rgb(47, 79, 79)), - card_priority_medium_style: Style::default() - .fg(Color::LightYellow) - .bg(Color::Rgb(47, 79, 79)), - card_priority_high_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(47, 79, 79)), - } - } - fn metro() -> Theme { - Theme { - name: "Metro".to_string(), - general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(20, 20, 20)), - list_select_style: Style::default() - .fg(Color::Black) - .bg(Color::Rgb(124, 252, 0)), - card_due_default_style: Style::default().fg(Color::White).bg(Color::Rgb(25, 25, 25)), - card_due_warning_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(25, 25, 25)), - card_due_overdue_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 25)), - card_status_active_style: Style::default().fg(Color::Cyan).bg(Color::Rgb(25, 25, 25)), - card_status_completed_style: Style::default() - .fg(Color::DarkGray) - .bg(Color::Rgb(25, 25, 25)), - card_status_stale_style: Style::default() - .fg(Color::LightYellow) - .bg(Color::Rgb(25, 25, 25)), - keyboard_focus_style: Style::default() - .fg(Color::Green) - .bg(Color::Rgb(25, 25, 25)) - .add_modifier(Modifier::BOLD), - mouse_focus_style: Style::default() - .fg(Color::Green) - .bg(Color::Rgb(25, 25, 25)) - .add_modifier(Modifier::BOLD), - help_key_style: Style::default() - .fg(Color::DarkGray) - .bg(Color::Rgb(25, 25, 25)), - help_text_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 25)), - log_error_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 25)), - log_debug_style: Style::default().fg(Color::Cyan).bg(Color::Rgb(25, 25, 25)), - log_warn_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(25, 25, 25)), - log_trace_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), - log_info_style: Style::default().fg(Color::White).bg(Color::Rgb(25, 25, 25)), - progress_bar_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), - error_text_style: Style::default() - .fg(Color::LightRed) - .bg(Color::Rgb(25, 25, 25)), - inactive_text_style: Style::default() - .fg(Color::DarkGray) - .bg(Color::Rgb(25, 25, 25)), - card_priority_low_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), - card_priority_medium_style: Style::default() - .fg(Color::Yellow) - .bg(Color::Rgb(25, 25, 25)), - card_priority_high_style: Style::default().fg(Color::Red).bg(Color::Rgb(25, 25, 25)), - } - } - fn matrix() -> Theme { - Theme { - name: "Matrix".to_string(), - general_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - list_select_style: Style::default().fg(Color::Black).bg(Color::LightGreen), - card_due_default_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - card_due_warning_style: Style::default().fg(Color::Yellow).bg(Color::Black), - card_due_overdue_style: Style::default().fg(Color::LightRed).bg(Color::Black), - card_status_active_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - card_status_completed_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_status_stale_style: Style::default().fg(Color::Yellow).bg(Color::Black), - keyboard_focus_style: Style::default() - .fg(Color::Black) - .bg(Color::LightGreen) - .add_modifier(Modifier::BOLD), - mouse_focus_style: Style::default() - .fg(Color::Black) - .bg(Color::LightGreen) - .add_modifier(Modifier::BOLD), - help_key_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - help_text_style: Style::default().fg(Color::Green).bg(Color::Black), - log_error_style: Style::default().fg(Color::LightRed).bg(Color::Black), - log_debug_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - log_warn_style: Style::default().fg(Color::Yellow).bg(Color::Black), - log_trace_style: Style::default().fg(Color::LightCyan).bg(Color::Black), - log_info_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - progress_bar_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), - inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_priority_low_style: Style::default().fg(Color::LightGreen).bg(Color::Black), - card_priority_medium_style: Style::default().fg(Color::Yellow).bg(Color::Black), - card_priority_high_style: Style::default().fg(Color::LightRed).bg(Color::Black), - } - } - fn cyberpunk() -> Theme { - Theme { - name: "Cyberpunk".to_string(), - general_style: Style::default() - .fg(Color::Rgb(248, 12, 228)) - .bg(Color::Black), - list_select_style: Style::default() - .fg(Color::Black) - .bg(Color::Rgb(253, 248, 0)), - card_due_default_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - card_due_warning_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black), - card_due_overdue_style: Style::default() - .fg(Color::Rgb(255, 28, 92)) - .bg(Color::Black), - card_status_active_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - card_status_completed_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_status_stale_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black), - keyboard_focus_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black) - .add_modifier(Modifier::BOLD), - mouse_focus_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black) - .add_modifier(Modifier::BOLD), - help_key_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - help_text_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black), - log_error_style: Style::default() - .fg(Color::Rgb(255, 28, 92)) - .bg(Color::Black), - log_debug_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - log_warn_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black), - log_trace_style: Style::default().fg(Color::LightCyan).bg(Color::Black), - log_info_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - progress_bar_style: Style::default() - .fg(Color::Rgb(248, 12, 228)) - .bg(Color::Black), - error_text_style: Style::default() - .fg(Color::Black) - .bg(Color::Rgb(255, 28, 92)), - inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), - card_priority_low_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), - card_priority_medium_style: Style::default() - .fg(Color::Rgb(253, 248, 0)) - .bg(Color::Black), - card_priority_high_style: Style::default() - .fg(Color::Rgb(255, 28, 92)) - .bg(Color::Black), - } - } - fn light() -> Theme { - Theme { - name: "Light".to_string(), - general_style: Style::default().fg(Color::Black).bg(Color::White), - list_select_style: Style::default().fg(Color::White).bg(Color::LightMagenta), - card_due_default_style: Style::default().fg(Color::LightGreen).bg(Color::White), - card_due_warning_style: Style::default() - .fg(Color::Rgb(255, 165, 0)) - .bg(Color::White), - card_due_overdue_style: Style::default().fg(Color::LightRed).bg(Color::White), - card_status_active_style: Style::default().fg(Color::Cyan).bg(Color::White), - card_status_completed_style: Style::default().fg(Color::LightGreen).bg(Color::White), - card_status_stale_style: Style::default().fg(Color::DarkGray).bg(Color::White), - keyboard_focus_style: Style::default().fg(Color::Blue).bg(Color::White), - mouse_focus_style: Style::default() - .fg(Color::Rgb(255, 165, 0)) - .bg(Color::White), - help_key_style: Style::default().fg(Color::LightMagenta).bg(Color::White), - help_text_style: Style::default().fg(Color::Black).bg(Color::White), - log_error_style: Style::default().fg(Color::LightRed).bg(Color::White), - log_debug_style: Style::default().fg(Color::LightGreen).bg(Color::White), - log_warn_style: Style::default() - .fg(Color::Rgb(255, 165, 0)) - .bg(Color::White), - log_trace_style: Style::default().fg(Color::DarkGray).bg(Color::White), - log_info_style: Style::default().fg(Color::Blue).bg(Color::White), - progress_bar_style: Style::default().fg(Color::Green).bg(Color::White), - error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), - inactive_text_style: Style::default().fg(Color::Gray).bg(Color::DarkGray), - card_priority_low_style: Style::default().fg(Color::LightGreen).bg(Color::White), - card_priority_medium_style: Style::default() - .fg(Color::Rgb(255, 165, 0)) - .bg(Color::White), - card_priority_high_style: Style::default().fg(Color::LightRed).bg(Color::White), - } - } - fn dracula() -> Theme { - Theme { - name: "Dracula".to_string(), - general_style: Style::default() - .fg(Color::Rgb(248, 248, 242)) - .bg(Color::Rgb(40, 42, 54)), - list_select_style: Style::default() - .fg(Color::Rgb(248, 248, 242)) - .bg(Color::Rgb(68, 71, 90)), - card_due_default_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - card_due_warning_style: Style::default() - .fg(Color::Rgb(255, 184, 108)) - .bg(Color::Rgb(40, 42, 54)), - card_due_overdue_style: Style::default() - .fg(Color::Rgb(255, 85, 85)) - .bg(Color::Rgb(40, 42, 54)), - card_status_active_style: Style::default() - .fg(Color::Rgb(139, 233, 253)) - .bg(Color::Rgb(40, 42, 54)), - card_status_completed_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - card_status_stale_style: Style::default() - .fg(Color::Rgb(68, 71, 90)) - .bg(Color::Rgb(40, 42, 54)), - keyboard_focus_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - mouse_focus_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - help_key_style: Style::default() - .fg(Color::Rgb(255, 121, 198)) - .bg(Color::Rgb(40, 42, 54)), - help_text_style: Style::default() - .fg(Color::Rgb(248, 248, 242)) - .bg(Color::Rgb(40, 42, 54)), - log_error_style: Style::default() - .fg(Color::Rgb(248, 248, 242)) - .bg(Color::Rgb(40, 42, 54)), - log_debug_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - log_warn_style: Style::default() - .fg(Color::Rgb(255, 184, 108)) - .bg(Color::Rgb(40, 42, 54)), - log_trace_style: Style::default() - .fg(Color::Rgb(68, 71, 90)) - .bg(Color::Rgb(40, 42, 54)), - log_info_style: Style::default() - .fg(Color::Rgb(139, 233, 253)) - .bg(Color::Rgb(40, 42, 54)), - progress_bar_style: Style::default() - .fg(Color::Rgb(189, 147, 249)) - .bg(Color::Rgb(68, 71, 90)), - error_text_style: Style::default() - .fg(Color::Rgb(40, 42, 54)) - .bg(Color::Rgb(255, 85, 85)), - inactive_text_style: Style::default() - .fg(Color::Rgb(68, 71, 90)) - .bg(Color::Rgb(40, 42, 54)), - card_priority_low_style: Style::default() - .fg(Color::Rgb(80, 250, 123)) - .bg(Color::Rgb(40, 42, 54)), - card_priority_medium_style: Style::default() - .fg(Color::Rgb(255, 184, 108)) - .bg(Color::Rgb(40, 42, 54)), - card_priority_high_style: Style::default() - .fg(Color::Rgb(255, 85, 85)) - .bg(Color::Rgb(40, 42, 54)), - } - } pub fn all_default_themes() -> Vec { vec![ - Theme::default(), - Theme::light(), - Theme::midnight_blue(), - Theme::slate(), - Theme::metro(), - Theme::matrix(), - Theme::cyberpunk(), - Theme::dracula(), + cyberpunk_theme(), + default_theme(), + dracula_theme(), + light_theme(), + matrix_theme(), + metro_theme(), + midnight_blue_theme(), + slate_theme(), ] } @@ -520,32 +103,12 @@ impl Theme { Span::styled("Card Priority High Style: ", text_style), ]; let theme_style_list = if popup_mode { - vec![ - Span::styled(&self.name, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - Span::styled(SAMPLE_TEXT, self.inactive_text_style), - ] + let mut return_vec = vec![Span::styled(&self.name, self.inactive_text_style)]; + let sample_text = Span::styled(&self.name, self.inactive_text_style); + for _ in 0..23 { + return_vec.push(sample_text.clone()); + } + return_vec } else { vec![ Span::styled(&self.name, self.general_style), @@ -614,6 +177,32 @@ impl Theme { ] } + pub fn update_style( + style: &mut Style, + fg_color: Option, + bg_color: Option, + modifier: Option, + ) { + if let Some(fg) = fg_color { + style.fg = Some(fg); + } else { + style.fg = None; + } + + if let Some(bg) = bg_color { + style.bg = Some(bg); + } else { + style.bg = None; + } + + if let Some(modifier) = modifier { + style.add_modifier(modifier); + } else { + style.sub_modifier = Modifier::empty(); + style.add_modifier = Modifier::empty(); + } + } + pub fn edit_style( &self, style_being_edited: &str, @@ -625,431 +214,123 @@ impl Theme { match style_being_edited { "name" => debug!("Cannot edit name"), "general_style" => { - if let Some(fg_color) = fg_color { - theme.general_style = theme.general_style.fg(fg_color); - } else { - theme.general_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.general_style = theme.general_style.bg(bg_color); - } else { - theme.general_style.bg = None; - } - if let Some(modifier) = modifier { - theme.general_style = theme.general_style.add_modifier(modifier); - } else { - theme.general_style.sub_modifier = Modifier::empty(); - theme.general_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.general_style, fg_color, bg_color, modifier); } "list_select_style" => { - if let Some(fg_color) = fg_color { - theme.list_select_style = theme.list_select_style.fg(fg_color); - } else { - theme.list_select_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.list_select_style = theme.list_select_style.bg(bg_color); - } else { - theme.list_select_style.bg = None; - } - if let Some(modifier) = modifier { - theme.list_select_style = theme.list_select_style.add_modifier(modifier); - } else { - theme.list_select_style.sub_modifier = Modifier::empty(); - theme.list_select_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.list_select_style, fg_color, bg_color, modifier); } "card_due_default_style" => { - if let Some(fg_color) = fg_color { - theme.card_due_default_style = theme.card_due_default_style.fg(fg_color); - } else { - theme.card_due_default_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_due_default_style = theme.card_due_default_style.bg(bg_color); - } else { - theme.card_due_default_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_due_default_style = - theme.card_due_default_style.add_modifier(modifier); - } else { - theme.card_due_default_style.sub_modifier = Modifier::empty(); - theme.card_due_default_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_due_default_style, + fg_color, + bg_color, + modifier, + ); } "card_due_warning_style" => { - if let Some(fg_color) = fg_color { - theme.card_due_warning_style = theme.card_due_warning_style.fg(fg_color); - } else { - theme.card_due_warning_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_due_warning_style = theme.card_due_warning_style.bg(bg_color); - } else { - theme.card_due_warning_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_due_warning_style = - theme.card_due_warning_style.add_modifier(modifier); - } else { - theme.card_due_warning_style.sub_modifier = Modifier::empty(); - theme.card_due_warning_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_due_warning_style, + fg_color, + bg_color, + modifier, + ); } "card_due_overdue_style" => { - if let Some(fg_color) = fg_color { - theme.card_due_overdue_style = theme.card_due_overdue_style.fg(fg_color); - } else { - theme.card_due_overdue_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_due_overdue_style = theme.card_due_overdue_style.bg(bg_color); - } else { - theme.card_due_overdue_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_due_overdue_style = - theme.card_due_overdue_style.add_modifier(modifier); - } else { - theme.card_due_overdue_style.sub_modifier = Modifier::empty(); - theme.card_due_overdue_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_due_overdue_style, + fg_color, + bg_color, + modifier, + ); } "card_status_active_style" => { - if let Some(fg_color) = fg_color { - theme.card_status_active_style = theme.card_status_active_style.fg(fg_color); - } else { - theme.card_status_active_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_status_active_style = theme.card_status_active_style.bg(bg_color); - } else { - theme.card_status_active_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_status_active_style = - theme.card_status_active_style.add_modifier(modifier); - } else { - theme.card_status_active_style.sub_modifier = Modifier::empty(); - theme.card_status_active_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_status_active_style, + fg_color, + bg_color, + modifier, + ); } "card_status_completed_style" => { - if let Some(fg_color) = fg_color { - theme.card_status_completed_style = - theme.card_status_completed_style.fg(fg_color); - } else { - theme.card_status_completed_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_status_completed_style = - theme.card_status_completed_style.bg(bg_color); - } else { - theme.card_status_completed_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_status_completed_style = - theme.card_status_completed_style.add_modifier(modifier); - } else { - theme.card_status_completed_style.sub_modifier = Modifier::empty(); - theme.card_status_completed_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_status_completed_style, + fg_color, + bg_color, + modifier, + ); } "card_status_stale_style" => { - if let Some(fg_color) = fg_color { - theme.card_status_stale_style = theme.card_status_stale_style.fg(fg_color); - } else { - theme.card_status_stale_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_status_stale_style = theme.card_status_stale_style.bg(bg_color); - } else { - theme.card_status_stale_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_status_stale_style = - theme.card_status_stale_style.add_modifier(modifier); - } else { - theme.card_status_stale_style.sub_modifier = Modifier::empty(); - theme.card_status_stale_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_status_stale_style, + fg_color, + bg_color, + modifier, + ); } "keyboard_focus_style" => { - if let Some(fg_color) = fg_color { - theme.keyboard_focus_style = theme.keyboard_focus_style.fg(fg_color); - } else { - theme.keyboard_focus_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.keyboard_focus_style = theme.keyboard_focus_style.bg(bg_color); - } else { - theme.keyboard_focus_style.bg = None; - } - if let Some(modifier) = modifier { - theme.keyboard_focus_style = theme.keyboard_focus_style.add_modifier(modifier); - } else { - theme.keyboard_focus_style.sub_modifier = Modifier::empty(); - theme.keyboard_focus_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.keyboard_focus_style, + fg_color, + bg_color, + modifier, + ); } "mouse_focus_style" => { - if let Some(fg_color) = fg_color { - theme.mouse_focus_style = theme.mouse_focus_style.fg(fg_color); - } else { - theme.mouse_focus_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.mouse_focus_style = theme.mouse_focus_style.bg(bg_color); - } else { - theme.mouse_focus_style.bg = None; - } - if let Some(modifier) = modifier { - theme.mouse_focus_style = theme.mouse_focus_style.add_modifier(modifier); - } else { - theme.mouse_focus_style.sub_modifier = Modifier::empty(); - theme.mouse_focus_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.mouse_focus_style, fg_color, bg_color, modifier); } "help_key_style" => { - if let Some(fg_color) = fg_color { - theme.help_key_style = theme.help_key_style.fg(fg_color); - } else { - theme.help_key_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.help_key_style = theme.help_key_style.bg(bg_color); - } else { - theme.help_key_style.bg = None; - } - if let Some(modifier) = modifier { - theme.help_key_style = theme.help_key_style.add_modifier(modifier); - } else { - theme.help_key_style.sub_modifier = Modifier::empty(); - theme.help_key_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.help_key_style, fg_color, bg_color, modifier); } "help_text_style" => { - if let Some(fg_color) = fg_color { - theme.help_text_style = theme.help_text_style.fg(fg_color); - } else { - theme.help_text_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.help_text_style = theme.help_text_style.bg(bg_color); - } else { - theme.help_text_style.bg = None; - } - if let Some(modifier) = modifier { - theme.help_text_style = theme.help_text_style.add_modifier(modifier); - } else { - theme.help_text_style.sub_modifier = Modifier::empty(); - theme.help_text_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.help_text_style, fg_color, bg_color, modifier); } "log_error_style" => { - if let Some(fg_color) = fg_color { - theme.log_error_style = theme.log_error_style.fg(fg_color); - } else { - theme.log_error_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.log_error_style = theme.log_error_style.bg(bg_color); - } else { - theme.log_error_style.bg = None; - } - if let Some(modifier) = modifier { - theme.log_error_style = theme.log_error_style.add_modifier(modifier); - } else { - theme.log_error_style.sub_modifier = Modifier::empty(); - theme.log_error_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.log_error_style, fg_color, bg_color, modifier); } "log_debug_style" => { - if let Some(fg_color) = fg_color { - theme.log_debug_style = theme.log_debug_style.fg(fg_color); - } else { - theme.log_debug_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.log_debug_style = theme.log_debug_style.bg(bg_color); - } else { - theme.log_debug_style.bg = None; - } - if let Some(modifier) = modifier { - theme.log_debug_style = theme.log_debug_style.add_modifier(modifier); - } else { - theme.log_debug_style.sub_modifier = Modifier::empty(); - theme.log_debug_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.log_debug_style, fg_color, bg_color, modifier); } "log_warn_style" => { - if let Some(fg_color) = fg_color { - theme.log_warn_style = theme.log_warn_style.fg(fg_color); - } else { - theme.log_warn_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.log_warn_style = theme.log_warn_style.bg(bg_color); - } else { - theme.log_warn_style.bg = None; - } - if let Some(modifier) = modifier { - theme.log_warn_style = theme.log_warn_style.add_modifier(modifier); - } else { - theme.log_warn_style.sub_modifier = Modifier::empty(); - theme.log_warn_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.log_warn_style, fg_color, bg_color, modifier); } "log_trace_style" => { - if let Some(fg_color) = fg_color { - theme.log_trace_style = theme.log_trace_style.fg(fg_color); - } else { - theme.log_trace_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.log_trace_style = theme.log_trace_style.bg(bg_color); - } else { - theme.log_trace_style.bg = None; - } - if let Some(modifier) = modifier { - theme.log_trace_style = theme.log_trace_style.add_modifier(modifier); - } else { - theme.log_trace_style.sub_modifier = Modifier::empty(); - theme.log_trace_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.log_trace_style, fg_color, bg_color, modifier); } "log_info_style" => { - if let Some(fg_color) = fg_color { - theme.log_info_style = theme.log_info_style.fg(fg_color); - } else { - theme.log_info_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.log_info_style = theme.log_info_style.bg(bg_color); - } else { - theme.log_info_style.bg = None; - } - if let Some(modifier) = modifier { - theme.log_info_style = theme.log_info_style.add_modifier(modifier); - } else { - theme.log_info_style.sub_modifier = Modifier::empty(); - theme.log_info_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.log_info_style, fg_color, bg_color, modifier); } "progress_bar_style" => { - if let Some(fg_color) = fg_color { - theme.progress_bar_style = theme.progress_bar_style.fg(fg_color); - } else { - theme.progress_bar_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.progress_bar_style = theme.progress_bar_style.bg(bg_color); - } else { - theme.progress_bar_style.bg = None; - } - if let Some(modifier) = modifier { - theme.progress_bar_style = theme.progress_bar_style.add_modifier(modifier); - } else { - theme.progress_bar_style.sub_modifier = Modifier::empty(); - theme.progress_bar_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.progress_bar_style, fg_color, bg_color, modifier); } "error_text_style" => { - if let Some(fg_color) = fg_color { - theme.error_text_style = theme.error_text_style.fg(fg_color); - } else { - theme.error_text_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.error_text_style = theme.error_text_style.bg(bg_color); - } else { - theme.error_text_style.bg = None; - } - if let Some(modifier) = modifier { - theme.error_text_style = theme.error_text_style.add_modifier(modifier); - } else { - theme.error_text_style.sub_modifier = Modifier::empty(); - theme.error_text_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.error_text_style, fg_color, bg_color, modifier); } "inactive_text_style" => { - if let Some(fg_color) = fg_color { - theme.inactive_text_style = theme.inactive_text_style.fg(fg_color); - } else { - theme.inactive_text_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.inactive_text_style = theme.inactive_text_style.bg(bg_color); - } else { - theme.inactive_text_style.bg = None; - } - if let Some(modifier) = modifier { - theme.inactive_text_style = theme.inactive_text_style.add_modifier(modifier); - } else { - theme.inactive_text_style.sub_modifier = Modifier::empty(); - theme.inactive_text_style.add_modifier = Modifier::empty(); - } + Theme::update_style(&mut theme.inactive_text_style, fg_color, bg_color, modifier); } "card_priority_low_style" => { - if let Some(fg_color) = fg_color { - theme.card_priority_low_style = theme.card_priority_low_style.fg(fg_color); - } else { - theme.card_priority_low_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_priority_low_style = theme.card_priority_low_style.bg(bg_color); - } else { - theme.card_priority_low_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_priority_low_style = - theme.card_priority_low_style.add_modifier(modifier); - } else { - theme.card_priority_low_style.sub_modifier = Modifier::empty(); - theme.card_priority_low_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_priority_low_style, + fg_color, + bg_color, + modifier, + ); } "card_priority_medium_style" => { - if let Some(fg_color) = fg_color { - theme.card_priority_medium_style = - theme.card_priority_medium_style.fg(fg_color); - } else { - theme.card_priority_medium_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_priority_medium_style = - theme.card_priority_medium_style.bg(bg_color); - } else { - theme.card_priority_medium_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_priority_medium_style = - theme.card_priority_medium_style.add_modifier(modifier); - } else { - theme.card_priority_medium_style.sub_modifier = Modifier::empty(); - theme.card_priority_medium_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_priority_medium_style, + fg_color, + bg_color, + modifier, + ); } "card_priority_high_style" => { - if let Some(fg_color) = fg_color { - theme.card_priority_high_style = theme.card_priority_high_style.fg(fg_color); - } else { - theme.card_priority_high_style.fg = None; - } - if let Some(bg_color) = bg_color { - theme.card_priority_high_style = theme.card_priority_high_style.bg(bg_color); - } else { - theme.card_priority_high_style.bg = None; - } - if let Some(modifier) = modifier { - theme.card_priority_high_style = - theme.card_priority_high_style.add_modifier(modifier); - } else { - theme.card_priority_high_style.sub_modifier = Modifier::empty(); - theme.card_priority_high_style.add_modifier = Modifier::empty(); - } + Theme::update_style( + &mut theme.card_priority_high_style, + fg_color, + bg_color, + modifier, + ); } _ => { debug!("Style not found: {}", style_being_edited); @@ -1062,46 +343,46 @@ impl Theme { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TextColorOptions { Black, - Red, - Green, - Yellow, Blue, - Magenta, Cyan, - Gray, DarkGray, - LightRed, - LightGreen, - LightYellow, + Gray, + Green, LightBlue, - LightMagenta, LightCyan, - White, - RGB(u8, u8, u8), + LightGreen, + LightMagenta, + LightRed, + LightYellow, + Magenta, None, + RGB(u8, u8, u8), + Red, + White, + Yellow, } impl Display for TextColorOptions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - TextColorOptions::White => write!(f, "White"), TextColorOptions::Black => write!(f, "Black"), - TextColorOptions::Red => write!(f, "Red"), - TextColorOptions::Green => write!(f, "Green"), - TextColorOptions::Yellow => write!(f, "Yellow"), TextColorOptions::Blue => write!(f, "Blue"), - TextColorOptions::Magenta => write!(f, "Magenta"), TextColorOptions::Cyan => write!(f, "Cyan"), - TextColorOptions::Gray => write!(f, "Gray"), TextColorOptions::DarkGray => write!(f, "DarkGray"), - TextColorOptions::LightRed => write!(f, "LightRed"), - TextColorOptions::LightGreen => write!(f, "LightGreen"), - TextColorOptions::LightYellow => write!(f, "LightYellow"), + TextColorOptions::Gray => write!(f, "Gray"), + TextColorOptions::Green => write!(f, "Green"), TextColorOptions::LightBlue => write!(f, "LightBlue"), - TextColorOptions::LightMagenta => write!(f, "LightMagenta"), TextColorOptions::LightCyan => write!(f, "LightCyan"), - TextColorOptions::RGB(r, g, b) => write!(f, "RGB({}, {}, {})", r, g, b), + TextColorOptions::LightGreen => write!(f, "LightGreen"), + TextColorOptions::LightMagenta => write!(f, "LightMagenta"), + TextColorOptions::LightRed => write!(f, "LightRed"), + TextColorOptions::LightYellow => write!(f, "LightYellow"), + TextColorOptions::Magenta => write!(f, "Magenta"), TextColorOptions::None => write!(f, "None"), + TextColorOptions::Red => write!(f, "Red"), + TextColorOptions::RGB(r, g, b) => write!(f, "RGB({}, {}, {})", r, g, b), + TextColorOptions::White => write!(f, "White"), + TextColorOptions::Yellow => write!(f, "Yellow"), } } } @@ -1109,94 +390,93 @@ impl Display for TextColorOptions { impl TextColorOptions { pub fn to_color(&self) -> Option { match self { - TextColorOptions::White => Some(Color::White), TextColorOptions::Black => Some(Color::Black), - TextColorOptions::Red => Some(Color::Red), - TextColorOptions::Green => Some(Color::Green), - TextColorOptions::Yellow => Some(Color::Yellow), TextColorOptions::Blue => Some(Color::Blue), - TextColorOptions::Magenta => Some(Color::Magenta), TextColorOptions::Cyan => Some(Color::Cyan), - TextColorOptions::Gray => Some(Color::Gray), TextColorOptions::DarkGray => Some(Color::DarkGray), - TextColorOptions::LightRed => Some(Color::LightRed), - TextColorOptions::LightGreen => Some(Color::LightGreen), - TextColorOptions::LightYellow => Some(Color::LightYellow), + TextColorOptions::Gray => Some(Color::Gray), + TextColorOptions::Green => Some(Color::Green), TextColorOptions::LightBlue => Some(Color::LightBlue), - TextColorOptions::LightMagenta => Some(Color::LightMagenta), TextColorOptions::LightCyan => Some(Color::LightCyan), - TextColorOptions::RGB(r, g, b) => Some(Color::Rgb(*r, *g, *b)), + TextColorOptions::LightGreen => Some(Color::LightGreen), + TextColorOptions::LightMagenta => Some(Color::LightMagenta), + TextColorOptions::LightRed => Some(Color::LightRed), + TextColorOptions::LightYellow => Some(Color::LightYellow), + TextColorOptions::Magenta => Some(Color::Magenta), TextColorOptions::None => None, + TextColorOptions::Red => Some(Color::Red), + TextColorOptions::RGB(r, g, b) => Some(Color::Rgb(*r, *g, *b)), + TextColorOptions::White => Some(Color::White), + TextColorOptions::Yellow => Some(Color::Yellow), } } pub fn to_iter() -> impl Iterator { vec![ - TextColorOptions::White, TextColorOptions::Black, - TextColorOptions::Red, - TextColorOptions::Green, - TextColorOptions::Yellow, TextColorOptions::Blue, - TextColorOptions::Magenta, TextColorOptions::Cyan, - TextColorOptions::Gray, TextColorOptions::DarkGray, - TextColorOptions::LightRed, - TextColorOptions::LightGreen, - TextColorOptions::LightYellow, + TextColorOptions::Gray, + TextColorOptions::Green, TextColorOptions::LightBlue, - TextColorOptions::LightMagenta, TextColorOptions::LightCyan, - TextColorOptions::Black, - TextColorOptions::RGB(128, 128, 128), + TextColorOptions::LightGreen, + TextColorOptions::LightMagenta, + TextColorOptions::LightRed, + TextColorOptions::LightYellow, + TextColorOptions::Magenta, TextColorOptions::None, + TextColorOptions::Red, + TextColorOptions::RGB(128, 128, 128), + TextColorOptions::White, + TextColorOptions::Yellow, ] .into_iter() } pub fn from(color: Color) -> TextColorOptions { match color { - Color::White => TextColorOptions::White, Color::Black => TextColorOptions::Black, - Color::Red => TextColorOptions::Red, - Color::Green => TextColorOptions::Green, - Color::Yellow => TextColorOptions::Yellow, Color::Blue => TextColorOptions::Blue, - Color::Magenta => TextColorOptions::Magenta, Color::Cyan => TextColorOptions::Cyan, - Color::Gray => TextColorOptions::Gray, Color::DarkGray => TextColorOptions::DarkGray, - Color::LightRed => TextColorOptions::LightRed, - Color::LightGreen => TextColorOptions::LightGreen, - Color::LightYellow => TextColorOptions::LightYellow, + Color::Gray => TextColorOptions::Gray, + Color::Green => TextColorOptions::Green, Color::LightBlue => TextColorOptions::LightBlue, - Color::LightMagenta => TextColorOptions::LightMagenta, Color::LightCyan => TextColorOptions::LightCyan, - Color::Rgb(r, g, b) => TextColorOptions::RGB(r, g, b), + Color::LightGreen => TextColorOptions::LightGreen, + Color::LightMagenta => TextColorOptions::LightMagenta, + Color::LightRed => TextColorOptions::LightRed, + Color::LightYellow => TextColorOptions::LightYellow, + Color::Magenta => TextColorOptions::Magenta, + Color::Red => TextColorOptions::Red, Color::Reset => TextColorOptions::None, + Color::Rgb(r, g, b) => TextColorOptions::RGB(r, g, b), + Color::White => TextColorOptions::White, + Color::Yellow => TextColorOptions::Yellow, _ => TextColorOptions::None, } } // TODO: This is a hack to get around the fact that the Color struct doesn't have a way to get the RGB values, find a better way to do this pub fn to_rgb(&self) -> (u8, u8, u8) { match self { - TextColorOptions::White => (255, 255, 255), TextColorOptions::Black => (0, 0, 0), - TextColorOptions::Red => (128, 0, 0), - TextColorOptions::Green => (0, 128, 0), - TextColorOptions::Yellow => (128, 128, 0), TextColorOptions::Blue => (0, 0, 128), - TextColorOptions::Magenta => (128, 0, 128), TextColorOptions::Cyan => (0, 128, 128), - TextColorOptions::Gray => (192, 192, 192), TextColorOptions::DarkGray => (128, 128, 128), - TextColorOptions::LightRed => (255, 0, 0), - TextColorOptions::LightGreen => (255, 255, 0), - TextColorOptions::LightYellow => (0, 255, 0), + TextColorOptions::Gray => (192, 192, 192), + TextColorOptions::Green => (0, 128, 0), TextColorOptions::LightBlue => (0, 0, 255), - TextColorOptions::LightMagenta => (255, 0, 255), TextColorOptions::LightCyan => (0, 255, 255), - TextColorOptions::RGB(r, g, b) => (*r, *g, *b), + TextColorOptions::LightGreen => (255, 255, 0), + TextColorOptions::LightMagenta => (255, 0, 255), + TextColorOptions::LightRed => (255, 0, 0), + TextColorOptions::LightYellow => (0, 255, 0), + TextColorOptions::Magenta => (128, 0, 128), TextColorOptions::None => (0, 0, 0), + TextColorOptions::Red => (128, 0, 0), + TextColorOptions::RGB(r, g, b) => (*r, *g, *b), + TextColorOptions::White => (255, 255, 255), + TextColorOptions::Yellow => (128, 128, 0), } } } @@ -1204,30 +484,30 @@ impl TextColorOptions { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TextModifierOptions { Bold, + CrossedOut, Dim, + Hidden, Italic, - Underlined, - SlowBlink, + None, RapidBlink, Reversed, - Hidden, - CrossedOut, - None, + SlowBlink, + Underlined, } impl Display for TextModifierOptions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TextModifierOptions::Bold => write!(f, "Bold"), + TextModifierOptions::CrossedOut => write!(f, "CrossedOut"), TextModifierOptions::Dim => write!(f, "Dim"), + TextModifierOptions::Hidden => write!(f, "Hidden"), TextModifierOptions::Italic => write!(f, "Italic"), - TextModifierOptions::Underlined => write!(f, "Underlined"), - TextModifierOptions::SlowBlink => write!(f, "SlowBlink"), + TextModifierOptions::None => write!(f, "None"), TextModifierOptions::RapidBlink => write!(f, "RapidBlink"), TextModifierOptions::Reversed => write!(f, "Reversed"), - TextModifierOptions::Hidden => write!(f, "Hidden"), - TextModifierOptions::CrossedOut => write!(f, "CrossedOut"), - TextModifierOptions::None => write!(f, "None"), + TextModifierOptions::SlowBlink => write!(f, "SlowBlink"), + TextModifierOptions::Underlined => write!(f, "Underlined"), } } } @@ -1236,29 +516,29 @@ impl TextModifierOptions { pub fn to_modifier(&self) -> Modifier { match self { TextModifierOptions::Bold => Modifier::BOLD, + TextModifierOptions::CrossedOut => Modifier::CROSSED_OUT, TextModifierOptions::Dim => Modifier::DIM, + TextModifierOptions::Hidden => Modifier::HIDDEN, TextModifierOptions::Italic => Modifier::ITALIC, - TextModifierOptions::Underlined => Modifier::UNDERLINED, - TextModifierOptions::SlowBlink => Modifier::SLOW_BLINK, + TextModifierOptions::None => Modifier::empty(), TextModifierOptions::RapidBlink => Modifier::RAPID_BLINK, TextModifierOptions::Reversed => Modifier::REVERSED, - TextModifierOptions::Hidden => Modifier::HIDDEN, - TextModifierOptions::CrossedOut => Modifier::CROSSED_OUT, - TextModifierOptions::None => Modifier::empty(), + TextModifierOptions::SlowBlink => Modifier::SLOW_BLINK, + TextModifierOptions::Underlined => Modifier::UNDERLINED, } } pub fn to_iter() -> impl Iterator { vec![ TextModifierOptions::Bold, + TextModifierOptions::CrossedOut, TextModifierOptions::Dim, + TextModifierOptions::Hidden, TextModifierOptions::Italic, - TextModifierOptions::Underlined, - TextModifierOptions::SlowBlink, + TextModifierOptions::None, TextModifierOptions::RapidBlink, TextModifierOptions::Reversed, - TextModifierOptions::Hidden, - TextModifierOptions::CrossedOut, - TextModifierOptions::None, + TextModifierOptions::SlowBlink, + TextModifierOptions::Underlined, ] .into_iter() } diff --git a/src/ui/themes.rs b/src/ui/themes.rs new file mode 100644 index 0000000..f5128c9 --- /dev/null +++ b/src/ui/themes.rs @@ -0,0 +1,480 @@ +use super::Theme; +use ratatui::style::{Color, Modifier, Style}; + +pub fn default_theme() -> Theme { + Theme { + card_due_default_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_due_overdue_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_due_warning_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_priority_high_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_priority_low_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_priority_medium_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_status_active_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_status_completed_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + card_status_stale_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + error_text_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + general_style: Style::default().fg(Color::White).bg(Color::Reset), + help_key_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + help_text_style: Style::default().fg(Color::White).bg(Color::Reset), + inactive_text_style: Style::default() + .fg(Color::Rgb(40, 40, 40)) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + keyboard_focus_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default() + .fg(Color::White) + .bg(Color::LightMagenta) + .add_modifier(Modifier::BOLD), + log_debug_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + log_error_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + log_info_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + log_trace_style: Style::default() + .fg(Color::Gray) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + log_warn_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + mouse_focus_style: Style::default() + .fg(Color::Rgb(255, 165, 0)) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + name: "Default Theme".to_string(), + progress_bar_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Reset) + .add_modifier(Modifier::BOLD), + } +} +pub fn midnight_blue_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), + card_due_overdue_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 112)), + card_due_warning_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Rgb(25, 25, 112)), + card_priority_high_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 112)), + card_priority_low_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(25, 25, 112)), + card_priority_medium_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Rgb(25, 25, 112)), + card_status_active_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(25, 25, 112)), + card_status_completed_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), + card_status_stale_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(25, 25, 112)), + error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), + general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), + help_key_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 112)), + help_text_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Rgb(25, 25, 112)), + inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + keyboard_focus_style: Style::default() + .fg(Color::LightBlue) + .bg(Color::Rgb(25, 25, 112)) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default() + .fg(Color::Gray) + .bg(Color::Rgb(70, 130, 180)), + log_debug_style: Style::default() + .fg(Color::LightBlue) + .bg(Color::Rgb(25, 25, 112)), + log_error_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 112)), + log_info_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(25, 25, 112)), + log_trace_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Rgb(25, 25, 112)), + log_warn_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(25, 25, 112)), + mouse_focus_style: Style::default() + .fg(Color::LightBlue) + .bg(Color::Rgb(25, 25, 112)) + .add_modifier(Modifier::BOLD), + name: "Midnight Blue".to_string(), + progress_bar_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(25, 25, 112)), + } +} +pub fn slate_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), + card_due_overdue_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(47, 79, 79)), + card_due_warning_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Rgb(47, 79, 79)), + card_priority_high_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(47, 79, 79)), + card_priority_low_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(47, 79, 79)), + card_priority_medium_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Rgb(47, 79, 79)), + card_status_active_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(47, 79, 79)), + card_status_completed_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), + card_status_stale_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(47, 79, 79)), + error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), + general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), + help_key_style: Style::default().fg(Color::Gray).bg(Color::Rgb(47, 79, 79)), + help_text_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Rgb(47, 79, 79)), + inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + keyboard_focus_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Rgb(47, 79, 79)) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default() + .fg(Color::Gray) + .bg(Color::Rgb(70, 130, 180)), + log_debug_style: Style::default() + .fg(Color::LightBlue) + .bg(Color::Rgb(47, 79, 79)), + log_error_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(47, 79, 79)), + log_info_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(47, 79, 79)), + log_trace_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Rgb(47, 79, 79)), + log_warn_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(47, 79, 79)), + mouse_focus_style: Style::default() + .fg(Color::LightCyan) + .bg(Color::Rgb(47, 79, 79)) + .add_modifier(Modifier::BOLD), + name: "Slate".to_string(), + progress_bar_style: Style::default() + .fg(Color::LightGreen) + .bg(Color::Rgb(47, 79, 79)), + } +} +pub fn metro_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::White).bg(Color::Rgb(25, 25, 25)), + card_due_overdue_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 25)), + card_due_warning_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(25, 25, 25)), + card_priority_high_style: Style::default().fg(Color::Red).bg(Color::Rgb(25, 25, 25)), + card_priority_low_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), + card_priority_medium_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(25, 25, 25)), + card_status_active_style: Style::default().fg(Color::Cyan).bg(Color::Rgb(25, 25, 25)), + card_status_completed_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Rgb(25, 25, 25)), + card_status_stale_style: Style::default() + .fg(Color::LightYellow) + .bg(Color::Rgb(25, 25, 25)), + error_text_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 25)), + general_style: Style::default().fg(Color::Gray).bg(Color::Rgb(20, 20, 20)), + help_key_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Rgb(25, 25, 25)), + help_text_style: Style::default().fg(Color::Gray).bg(Color::Rgb(25, 25, 25)), + inactive_text_style: Style::default() + .fg(Color::DarkGray) + .bg(Color::Rgb(25, 25, 25)), + keyboard_focus_style: Style::default() + .fg(Color::Green) + .bg(Color::Rgb(25, 25, 25)) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default() + .fg(Color::Black) + .bg(Color::Rgb(124, 252, 0)), + log_debug_style: Style::default().fg(Color::Cyan).bg(Color::Rgb(25, 25, 25)), + log_error_style: Style::default() + .fg(Color::LightRed) + .bg(Color::Rgb(25, 25, 25)), + log_info_style: Style::default().fg(Color::White).bg(Color::Rgb(25, 25, 25)), + log_trace_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), + log_warn_style: Style::default() + .fg(Color::Yellow) + .bg(Color::Rgb(25, 25, 25)), + mouse_focus_style: Style::default() + .fg(Color::Green) + .bg(Color::Rgb(25, 25, 25)) + .add_modifier(Modifier::BOLD), + name: "Metro".to_string(), + progress_bar_style: Style::default().fg(Color::Green).bg(Color::Rgb(25, 25, 25)), + } +} +pub fn matrix_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + card_due_overdue_style: Style::default().fg(Color::LightRed).bg(Color::Black), + card_due_warning_style: Style::default().fg(Color::Yellow).bg(Color::Black), + card_priority_high_style: Style::default().fg(Color::LightRed).bg(Color::Black), + card_priority_low_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + card_priority_medium_style: Style::default().fg(Color::Yellow).bg(Color::Black), + card_status_active_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + card_status_completed_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + card_status_stale_style: Style::default().fg(Color::Yellow).bg(Color::Black), + error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), + general_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + help_key_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + help_text_style: Style::default().fg(Color::Green).bg(Color::Black), + inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + keyboard_focus_style: Style::default() + .fg(Color::Black) + .bg(Color::LightGreen) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default().fg(Color::Black).bg(Color::LightGreen), + log_debug_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + log_error_style: Style::default().fg(Color::LightRed).bg(Color::Black), + log_info_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + log_trace_style: Style::default().fg(Color::LightCyan).bg(Color::Black), + log_warn_style: Style::default().fg(Color::Yellow).bg(Color::Black), + mouse_focus_style: Style::default() + .fg(Color::Black) + .bg(Color::LightGreen) + .add_modifier(Modifier::BOLD), + name: "Matrix".to_string(), + progress_bar_style: Style::default().fg(Color::LightGreen).bg(Color::Black), + } +} +pub fn cyberpunk_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + card_due_overdue_style: Style::default() + .fg(Color::Rgb(255, 28, 92)) + .bg(Color::Black), + card_due_warning_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black), + card_priority_high_style: Style::default() + .fg(Color::Rgb(255, 28, 92)) + .bg(Color::Black), + card_priority_low_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + card_priority_medium_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black), + card_status_active_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + card_status_completed_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + card_status_stale_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black), + error_text_style: Style::default() + .fg(Color::Black) + .bg(Color::Rgb(255, 28, 92)), + general_style: Style::default() + .fg(Color::Rgb(248, 12, 228)) + .bg(Color::Black), + help_key_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + help_text_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black), + inactive_text_style: Style::default().fg(Color::DarkGray).bg(Color::Black), + keyboard_focus_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black) + .add_modifier(Modifier::BOLD), + list_select_style: Style::default() + .fg(Color::Black) + .bg(Color::Rgb(253, 248, 0)), + log_debug_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + log_error_style: Style::default() + .fg(Color::Rgb(255, 28, 92)) + .bg(Color::Black), + log_info_style: Style::default().fg(Color::Rgb(24, 252, 4)).bg(Color::Black), + log_trace_style: Style::default().fg(Color::LightCyan).bg(Color::Black), + log_warn_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black), + mouse_focus_style: Style::default() + .fg(Color::Rgb(253, 248, 0)) + .bg(Color::Black) + .add_modifier(Modifier::BOLD), + name: "Cyberpunk".to_string(), + progress_bar_style: Style::default() + .fg(Color::Rgb(248, 12, 228)) + .bg(Color::Black), + } +} +pub fn light_theme() -> Theme { + Theme { + card_due_default_style: Style::default().fg(Color::LightGreen).bg(Color::White), + card_due_overdue_style: Style::default().fg(Color::LightRed).bg(Color::White), + card_due_warning_style: Style::default() + .fg(Color::Rgb(255, 165, 0)) + .bg(Color::White), + card_priority_high_style: Style::default().fg(Color::LightRed).bg(Color::White), + card_priority_low_style: Style::default().fg(Color::LightGreen).bg(Color::White), + card_priority_medium_style: Style::default() + .fg(Color::Rgb(255, 165, 0)) + .bg(Color::White), + card_status_active_style: Style::default().fg(Color::Cyan).bg(Color::White), + card_status_completed_style: Style::default().fg(Color::LightGreen).bg(Color::White), + card_status_stale_style: Style::default().fg(Color::DarkGray).bg(Color::White), + error_text_style: Style::default().fg(Color::Black).bg(Color::LightRed), + general_style: Style::default().fg(Color::Black).bg(Color::White), + help_key_style: Style::default().fg(Color::LightMagenta).bg(Color::White), + help_text_style: Style::default().fg(Color::Black).bg(Color::White), + inactive_text_style: Style::default().fg(Color::Gray).bg(Color::DarkGray), + keyboard_focus_style: Style::default().fg(Color::Blue).bg(Color::White), + list_select_style: Style::default().fg(Color::White).bg(Color::LightMagenta), + log_debug_style: Style::default().fg(Color::LightGreen).bg(Color::White), + log_error_style: Style::default().fg(Color::LightRed).bg(Color::White), + log_info_style: Style::default().fg(Color::Blue).bg(Color::White), + log_trace_style: Style::default().fg(Color::DarkGray).bg(Color::White), + log_warn_style: Style::default() + .fg(Color::Rgb(255, 165, 0)) + .bg(Color::White), + mouse_focus_style: Style::default() + .fg(Color::Rgb(255, 165, 0)) + .bg(Color::White), + name: "Light".to_string(), + progress_bar_style: Style::default().fg(Color::Green).bg(Color::White), + } +} +pub fn dracula_theme() -> Theme { + Theme { + card_due_default_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + card_due_overdue_style: Style::default() + .fg(Color::Rgb(255, 85, 85)) + .bg(Color::Rgb(40, 42, 54)), + card_due_warning_style: Style::default() + .fg(Color::Rgb(255, 184, 108)) + .bg(Color::Rgb(40, 42, 54)), + card_priority_high_style: Style::default() + .fg(Color::Rgb(255, 85, 85)) + .bg(Color::Rgb(40, 42, 54)), + card_priority_low_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + card_priority_medium_style: Style::default() + .fg(Color::Rgb(255, 184, 108)) + .bg(Color::Rgb(40, 42, 54)), + card_status_active_style: Style::default() + .fg(Color::Rgb(139, 233, 253)) + .bg(Color::Rgb(40, 42, 54)), + card_status_completed_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + card_status_stale_style: Style::default() + .fg(Color::Rgb(68, 71, 90)) + .bg(Color::Rgb(40, 42, 54)), + error_text_style: Style::default() + .fg(Color::Rgb(40, 42, 54)) + .bg(Color::Rgb(255, 85, 85)), + general_style: Style::default() + .fg(Color::Rgb(248, 248, 242)) + .bg(Color::Rgb(40, 42, 54)), + help_key_style: Style::default() + .fg(Color::Rgb(255, 121, 198)) + .bg(Color::Rgb(40, 42, 54)), + help_text_style: Style::default() + .fg(Color::Rgb(248, 248, 242)) + .bg(Color::Rgb(40, 42, 54)), + inactive_text_style: Style::default() + .fg(Color::Rgb(68, 71, 90)) + .bg(Color::Rgb(40, 42, 54)), + keyboard_focus_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + list_select_style: Style::default() + .fg(Color::Rgb(248, 248, 242)) + .bg(Color::Rgb(68, 71, 90)), + log_debug_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + log_error_style: Style::default() + .fg(Color::Rgb(248, 248, 242)) + .bg(Color::Rgb(40, 42, 54)), + log_info_style: Style::default() + .fg(Color::Rgb(139, 233, 253)) + .bg(Color::Rgb(40, 42, 54)), + log_trace_style: Style::default() + .fg(Color::Rgb(68, 71, 90)) + .bg(Color::Rgb(40, 42, 54)), + log_warn_style: Style::default() + .fg(Color::Rgb(255, 184, 108)) + .bg(Color::Rgb(40, 42, 54)), + mouse_focus_style: Style::default() + .fg(Color::Rgb(80, 250, 123)) + .bg(Color::Rgb(40, 42, 54)), + name: "Dracula".to_string(), + progress_bar_style: Style::default() + .fg(Color::Rgb(189, 147, 249)) + .bg(Color::Rgb(68, 71, 90)), + } +} diff --git a/src/ui/ui_helper.rs b/src/ui/ui_helper.rs index 24a17c6..524ba69 100644 --- a/src/ui/ui_helper.rs +++ b/src/ui/ui_helper.rs @@ -25,7 +25,6 @@ use crate::{ use chrono::{Local, NaiveDate, NaiveDateTime}; use log::{debug, Level}; use ratatui::{ - backend::Backend, layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Line, Span}, @@ -39,10 +38,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -pub fn render_zen_mode(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_zen_mode(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Percentage(100)].as_ref()) @@ -55,10 +51,7 @@ where } } -pub fn render_title_body(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_title_body(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Percentage(80)].as_ref()) @@ -81,10 +74,7 @@ where } } -pub fn render_body_help(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_body_help(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -115,19 +105,16 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(help.0, chunks[1]); - rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.app_table_states.help); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.app_table_states.help); if app.config.enable_mouse_support { render_close_button(rect, app) } } -pub fn render_body_log(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_body_log(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Percentage(80), Constraint::Length(8)].as_ref()) @@ -141,10 +128,7 @@ where } } -pub fn render_title_body_help(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_title_body_help(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -192,19 +176,16 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(help.0, chunks[2]); - rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.app_table_states.help); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.app_table_states.help); if app.config.enable_mouse_support { render_close_button(rect, app) } } -pub fn render_title_body_log(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_title_body_log(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints( @@ -235,10 +216,7 @@ where } } -pub fn render_body_help_log(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_body_help_log(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -276,9 +254,9 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(help.0, chunks[1]); - rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.app_table_states.help); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.app_table_states.help); render_logs(app, true, chunks[2], rect, app.state.popup_mode.is_some()); @@ -287,10 +265,7 @@ where } } -pub fn render_title_body_help_log(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_title_body_help_log(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -339,9 +314,9 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(help.0, chunks[2]); - rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget(help.1, help_chunks[0], &mut app.state.app_table_states.help); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget(help.2, help_chunks[2], &mut app.state.app_table_states.help); render_logs(app, true, chunks[3], rect, app.state.popup_mode.is_some()); @@ -350,10 +325,7 @@ where } } -pub fn render_config(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_config(rect: &mut Frame, app: &mut App) { let popup_mode = app.state.popup_mode.is_some(); let chunks = Layout::default() .direction(Direction::Vertical) @@ -442,9 +414,13 @@ where .border_style(default_style) .border_type(BorderType::Rounded); rect.render_widget(config_border, chunks[1]); - rect.render_stateful_widget(config_table, table_chunks[0], &mut app.state.config_state); + rect.render_stateful_widget( + config_table, + table_chunks[0], + &mut app.state.app_table_states.config, + ); - let current_index = app.state.config_state.selected().unwrap_or(0); + let current_index = app.state.app_table_states.config.selected().unwrap_or(0); let total_rows = app.config.to_view_list().len(); let visible_rows = (table_chunks[1].height - 1) as usize; let percentage = ((current_index + 1) as f32 / total_rows as f32) * 100.0; @@ -517,10 +493,7 @@ fn draw_config_table_selector(app: &mut App) -> Table<'static> { .widths(&[Constraint::Percentage(40), Constraint::Percentage(60)]) } -pub fn render_edit_config(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_edit_config(rect: &mut Frame, app: &mut App) { let area = centered_rect_with_percentage(70, 70, rect.size()); let clear_area = centered_rect_with_percentage(80, 80, rect.size()); let clear_area_border = Block::default() @@ -588,7 +561,7 @@ where } else { &app.state.theme_being_edited.name }; - let paragraph_text = format!("Current Value is {}\n\n{}",config_item_value, + let paragraph_text = format!("Current Value is {}\n{}",config_item_value, "Press 'i' to edit, or 'Esc' to cancel, Press 'Ins' to stop editing and press 'Enter' on Submit to save"); let paragraph_title = Line::from(vec![Span::raw(config_item_name)]); let config_item = Paragraph::new(paragraph_text) @@ -653,10 +626,7 @@ where } } -pub fn render_select_default_view(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_select_default_view(rect: &mut Frame, app: &mut App) { let render_area = centered_rect_with_percentage(70, 70, rect.size()); let mouse_coordinates = app.state.current_mouse_coordinates; let clear_area = centered_rect_with_percentage(80, 80, rect.size()); @@ -690,7 +660,8 @@ where let mouse_y = mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .default_view_state + .app_list_states + .default_view .select(Some((mouse_y - top_of_list) as usize)); } } @@ -755,7 +726,7 @@ where rect.render_stateful_widget( default_view_list, chunks[0], - &mut app.state.default_view_state, + &mut app.state.app_list_states.default_view, ); rect.render_widget(config_help, chunks[1]); @@ -764,10 +735,7 @@ where } } -pub fn render_edit_keybindings(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_edit_keybindings(rect: &mut Frame, app: &mut App) { let popup_mode = app.state.popup_mode.is_some(); let chunks = Layout::default() .constraints( @@ -849,7 +817,12 @@ where }); // TODO use ratatui's new scroll bar feature - let current_index = app.state.edit_keybindings_state.selected().unwrap_or(0); + let current_index = app + .state + .app_table_states + .edit_keybindings + .selected() + .unwrap_or(0); let total_rows = table_items.len(); let visible_rows = (table_chunks[1].height - 1) as usize; let percentage = ((current_index + 1) as f32 / total_rows as f32) * 100.0; @@ -979,7 +952,11 @@ where .style(reset_style) .alignment(Alignment::Center); - rect.render_stateful_widget(t, chunks[1], &mut app.state.edit_keybindings_state); + rect.render_stateful_widget( + t, + chunks[1], + &mut app.state.app_table_states.edit_keybindings, + ); rect.render_widget(edit_keybinding_help, chunks[2]); rect.render_widget(reset_button, chunks[3]); @@ -988,10 +965,7 @@ where } } -pub fn render_edit_specific_keybinding(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_edit_specific_keybinding(rect: &mut Frame, app: &mut App) { let area = centered_rect_with_percentage(70, 70, rect.size()); let clear_area = centered_rect_with_percentage(80, 80, rect.size()); let clear_area_border = Block::default() @@ -1040,7 +1014,12 @@ where app.current_theme.general_style }; - let key_id = app.state.edit_keybindings_state.selected().unwrap_or(0); + let key_id = app + .state + .app_table_states + .edit_keybindings + .selected() + .unwrap_or(0); let current_bindings = app.config.keybindings.clone(); let mut key_list = vec![]; @@ -1135,10 +1114,7 @@ where } } -pub fn render_main_menu(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_main_menu(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -1252,9 +1228,17 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(main_menu_help.0, chunks[2]); - rect.render_stateful_widget(main_menu_help.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget( + main_menu_help.1, + help_chunks[0], + &mut app.state.app_table_states.help, + ); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(main_menu_help.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget( + main_menu_help.2, + help_chunks[2], + &mut app.state.app_table_states.help, + ); render_logs(app, true, chunks[3], rect, app.state.popup_mode.is_some()); @@ -1263,10 +1247,7 @@ where } } -pub fn render_help_menu(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_help_menu(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -1295,9 +1276,17 @@ where .borders(Borders::LEFT) .border_style(default_style); rect.render_widget(help_menu.0, chunks[0]); - rect.render_stateful_widget(help_menu.1, help_chunks[0], &mut app.state.help_state); + rect.render_stateful_widget( + help_menu.1, + help_chunks[0], + &mut app.state.app_table_states.help, + ); rect.render_widget(help_separator, help_chunks[1]); - rect.render_stateful_widget(help_menu.2, help_chunks[2], &mut app.state.help_state); + rect.render_stateful_widget( + help_menu.2, + help_chunks[2], + &mut app.state.app_table_states.help, + ); render_logs(app, true, chunks[1], rect, app.state.popup_mode.is_some()); if app.config.enable_mouse_support { @@ -1305,10 +1294,7 @@ where } } -pub fn render_logs_only(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_logs_only(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Percentage(100)].as_ref()) @@ -1487,10 +1473,7 @@ fn draw_config_help<'a>(focus: &'a Focus, popup_mode: bool, app: &'a App) -> Par .wrap(ratatui::widgets::Wrap { trim: true }) } -fn draw_main_menu(app: &mut App, render_area: Rect, rect: &mut Frame) -where - B: Backend, -{ +fn draw_main_menu(app: &mut App, render_area: Rect, rect: &mut Frame) { let main_menu_items = app.main_menu.all(); let popup_mode = app.state.popup_mode.is_some(); let focus = app.state.focus; @@ -1511,7 +1494,8 @@ where let mouse_y = mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .main_menu_state + .app_list_states + .main_menu .select(Some((mouse_y - top_of_list) as usize)); } } @@ -1546,13 +1530,14 @@ where ) .highlight_style(highlight_style) .highlight_symbol(LIST_SELECTED_SYMBOL); - rect.render_stateful_widget(main_menu, render_area, &mut app.state.main_menu_state); + rect.render_stateful_widget( + main_menu, + render_area, + &mut app.state.app_list_states.main_menu, + ); } -pub fn render_body(rect: &mut Frame, area: Rect, app: &mut App, preview_mode: bool) -where - B: Backend, -{ +pub fn render_body(rect: &mut Frame, area: Rect, app: &mut App, preview_mode: bool) { let fallback_boards = vec![]; let focus = app.state.focus; let boards = if preview_mode { @@ -1585,6 +1570,13 @@ where .find(|x| x[1] == "Create new board") .unwrap_or(&vec!["".to_string(), "".to_string()])[0] .clone(); + let new_card_key = app + .state + .keybinding_store + .iter() + .find(|x| x[1] == "Create new card in current board") + .unwrap_or(&vec!["".to_string(), "".to_string()])[0] + .clone(); if preview_mode { if app.state.preview_boards_and_cards.is_none() @@ -1636,7 +1628,7 @@ where } else { Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Length(1), Constraint::Percentage(99)].as_ref()) + .constraints([Constraint::Length(1), Constraint::Length(area.height - 1)].as_ref()) .split(area) }; @@ -1648,7 +1640,13 @@ where } else { Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Percentage(99), Constraint::Length(1)].as_ref()) + .constraints( + [ + Constraint::Length(filter_chunks[1].height - 1), + Constraint::Length(1), + ] + .as_ref(), + ) .split(filter_chunks[1]) }; @@ -1675,7 +1673,7 @@ where } let board_chunks = Layout::default() .direction(Direction::Horizontal) - .constraints(constraints.as_ref()) + .constraints(AsRef::<[Constraint]>::as_ref(&constraints)) .split(chunks[0]); let visible_boards_and_cards = if preview_mode { app.state.preview_visible_boards_and_cards.clone() @@ -1723,6 +1721,8 @@ where for _i in 0..app.config.no_of_cards_to_show { card_constraints.push(Constraint::Percentage(90 / app.config.no_of_cards_to_show)); } + } else if board_cards.len() == 0 { + card_constraints.push(Constraint::Percentage(100)); } else { for _i in 0..board_cards.len() { card_constraints.push(Constraint::Percentage(100 / board_cards.len() as u16)); @@ -1781,16 +1781,39 @@ where Layout::default() .direction(Direction::Vertical) .margin(1) - .constraints(card_constraints.as_ref()) + .constraints(AsRef::<[Constraint]>::as_ref(&card_constraints)) .split(card_area_chunks[0]) } else { Layout::default() .direction(Direction::Vertical) .margin(1) - .constraints(card_constraints.as_ref()) + .constraints(AsRef::<[Constraint]>::as_ref(&card_constraints)) .split(card_area_chunks[1]) }; - + if board_cards.is_empty() { + let available_width = card_chunks[0].width - 2; + let empty_card_text = if preview_mode { + "No cards found".to_string() + } else { + "No cards found, press ".to_string() + &new_card_key + "to add a new card" + }; + let mut usuable_length = empty_card_text.len() as u16; + let mut usable_height = 1.0; + if empty_card_text.len() > available_width.into() { + usuable_length = available_width; + usable_height = empty_card_text.len() as f32 / available_width as f32; + usable_height = usable_height.ceil(); + } + let message_centered_rect = + centered_rect_with_length(usuable_length, usable_height as u16, card_chunks[0]); + let empty_card_paragraph = Paragraph::new(empty_card_text) + .alignment(Alignment::Center) + .block(Block::default()) + .style(board_style) + .wrap(ratatui::widgets::Wrap { trim: true }); + rect.render_widget(empty_card_paragraph, message_centered_rect); + continue; + } if !app.config.disable_scroll_bar { let all_board_cards = boards .iter() @@ -2121,10 +2144,7 @@ fn top_left_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { .split(popup_layout[0])[0] } -pub fn draw_size_error(rect: &mut Frame, size: &Rect, msg: String, app: &mut App) -where - B: Backend, -{ +pub fn draw_size_error(rect: &mut Frame, size: &Rect, msg: String, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Min(10)].as_ref()) @@ -2147,10 +2167,7 @@ where rect.render_widget(body, chunks[1]); } -pub fn draw_loading_screen(rect: &mut Frame, size: &Rect, app: &mut App) -where - B: Backend, -{ +pub fn draw_loading_screen(rect: &mut Frame, size: &Rect, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Min(10)].as_ref()) @@ -2232,10 +2249,7 @@ pub fn check_size(rect: &Rect) -> String { msg } -pub fn render_new_board_form(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_new_board_form(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints( @@ -2319,14 +2333,18 @@ where ); rect.render_widget(title_paragraph, chunks[0]); - let wrapped_title_text = - textwrap::wrap(&app.state.new_board_form[0], (chunks[1].width - 2) as usize); + let wrapped_title_text = textwrap::wrap( + &app.state.app_form_states.new_board[0], + (chunks[1].width - 2) as usize, + ); let board_name_field = wrapped_title_text .iter() .map(|x| Line::from(Span::raw(&**x))) .collect::>(); - let wrapped_description_text = - textwrap::wrap(&app.state.new_board_form[1], (chunks[2].width - 2) as usize); + let wrapped_description_text = textwrap::wrap( + &app.state.app_form_states.new_board[1], + (chunks[2].width - 2) as usize, + ); let board_description_field = wrapped_description_text .iter() .map(|x| Line::from(Span::raw(&**x))) @@ -2418,7 +2436,7 @@ where wrapped_title_text, app.state .current_cursor_position - .unwrap_or_else(|| app.state.new_board_form[0].len()), + .unwrap_or_else(|| app.state.app_form_states.new_board[0].len()), chunks[1], ); rect.set_cursor(x_pos, y_pos); @@ -2433,7 +2451,7 @@ where wrapped_description_text, app.state .current_cursor_position - .unwrap_or_else(|| app.state.new_board_form[1].len()), + .unwrap_or_else(|| app.state.app_form_states.new_board[1].len()), chunks[2], ); rect.set_cursor(x_pos, y_pos); @@ -2447,10 +2465,7 @@ where } } -pub fn render_new_card_form(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_new_card_form(rect: &mut Frame, app: &mut App) { let chunks = Layout::default() .direction(Direction::Vertical) .constraints( @@ -2550,14 +2565,18 @@ where ); rect.render_widget(title_paragraph, chunks[0]); - let wrapped_card_name_text = - textwrap::wrap(&app.state.new_card_form[0], (chunks[1].width - 2) as usize); + let wrapped_card_name_text = textwrap::wrap( + &app.state.app_form_states.new_card[0], + (chunks[1].width - 2) as usize, + ); let card_name_field = wrapped_card_name_text .iter() .map(|x| Line::from(Span::raw(&**x))) .collect::>(); - let wrapped_card_due_date_text = - textwrap::wrap(&app.state.new_card_form[2], (chunks[3].width - 2) as usize); + let wrapped_card_due_date_text = textwrap::wrap( + &app.state.app_form_states.new_card[2], + (chunks[3].width - 2) as usize, + ); let card_due_date_field = wrapped_card_due_date_text .iter() .map(|x| Line::from(Span::raw(&**x))) @@ -2595,7 +2614,7 @@ where } else { let mut textarea = TextBox::default(); textarea.set_block(description_block.clone()); - textarea.insert_str(&app.state.new_card_form[1]); + textarea.insert_str(&app.state.app_form_states.new_card[1]); textarea.move_cursor(CursorMove::Jump(0, 0)); if app.config.show_line_numbers { textarea.set_line_number_style(app.current_theme.general_style) @@ -2615,8 +2634,10 @@ where }; rect.render_widget(card_description.widget(), chunks[2]); - let parsed_due_date = - date_format_converter(app.state.new_card_form[2].trim(), app.config.date_format); + let parsed_due_date = date_format_converter( + app.state.app_form_states.new_card[2].trim(), + app.config.date_format, + ); let card_due_date = Paragraph::new(card_due_date_field) .alignment(Alignment::Left) .block( @@ -2626,7 +2647,7 @@ where .border_type(BorderType::Rounded) .title("Card Due Date (DD/MM/YYYY-HH:MM:SS), (DD/MM/YYYY), (YYYY/MM/DD-HH:MM:SS), or (YYYY/MM/DD)"), ); - if parsed_due_date.is_err() && !app.state.new_card_form[2].is_empty() { + if parsed_due_date.is_err() && !app.state.app_form_states.new_card[2].is_empty() { let new_chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(70), Constraint::Length(20)].as_ref()) @@ -2711,7 +2732,7 @@ where wrapped_card_name_text, app.state .current_cursor_position - .unwrap_or_else(|| app.state.new_card_form[0].len()), + .unwrap_or_else(|| app.state.app_form_states.new_card[0].len()), chunks[1], ); rect.set_cursor(x_pos, y_pos); @@ -2725,7 +2746,7 @@ where wrapped_card_due_date_text, app.state .current_cursor_position - .unwrap_or_else(|| app.state.new_card_form[2].len()), + .unwrap_or_else(|| app.state.app_form_states.new_card[2].len()), chunks[3], ); rect.set_cursor(x_pos, y_pos); @@ -2739,10 +2760,7 @@ where } } -pub fn render_load_a_save(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_load_a_save(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -2842,11 +2860,16 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .load_save_state + .app_list_states + .load_save .select(Some((mouse_y - top_of_list) as usize)); } } - rect.render_stateful_widget(choice_list, chunks[1], &mut app.state.load_save_state); + rect.render_stateful_widget( + choice_list, + chunks[1], + &mut app.state.app_list_states.load_save, + ); } let delete_key = app @@ -2899,7 +2922,7 @@ where .wrap(ratatui::widgets::Wrap { trim: true }); rect.render_widget(help_paragraph, chunks[2]); - if app.state.load_save_state.selected().is_none() { + if app.state.app_list_states.load_save.selected().is_none() { let preview_paragraph = Paragraph::new(format!("Select a save file with {}or {}to preview or Click on a save file to preview if using a mouse", up_key, down_key)) .alignment(Alignment::Center) @@ -2961,10 +2984,7 @@ where } } -pub fn render_toast(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_toast(rect: &mut Frame, app: &mut App) { let all_toasts = app.state.toasts.clone(); let mut loading_toasts = all_toasts .iter() @@ -3126,10 +3146,7 @@ where rect.render_widget(toast_count_paragraph, message_area); } -pub fn render_view_card(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_view_card(rect: &mut Frame, app: &mut App) { let popup_area = centered_rect_with_percentage(90, 90, rect.size()); render_blank_styled_canvas(rect, app, popup_area, false); @@ -3402,7 +3419,13 @@ where let card_tag_lines = { let card_tags = if app.state.focus == Focus::CardTags { let mut tags = vec![]; - if app.state.card_view_tag_list_state.selected().is_none() { + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_none() + { for (index, tag) in card.tags.iter().enumerate() { tags.push(Span::styled( format!("{}) {} ", index + 1, tag), @@ -3410,7 +3433,12 @@ where )); } } else { - let selected_tag = app.state.card_view_tag_list_state.selected().unwrap(); + let selected_tag = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); for (index, tag) in card.tags.iter().enumerate() { if index == selected_tag { tags.push(Span::styled( @@ -3469,7 +3497,13 @@ where let card_comment_lines = { let card_comments = if app.state.focus == Focus::CardComments { let mut comments = vec![]; - if app.state.card_view_comment_list_state.selected().is_none() { + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_none() + { for (index, comment) in card.comments.iter().enumerate() { comments.push(Span::styled( format!("{}) {} ", index + 1, comment), @@ -3477,7 +3511,12 @@ where )); } } else { - let selected_comment = app.state.card_view_comment_list_state.selected().unwrap(); + let selected_comment = app + .state + .app_list_states + .card_view_comment_list + .selected() + .unwrap(); for (index, comment) in card.comments.iter().enumerate() { if index == selected_comment { comments.push(Span::styled( @@ -3586,7 +3625,6 @@ where card_description_height = remaining_height - card_tags_height - card_comments_height; } - if app.state.card_being_edited.is_some() { Layout::default() .direction(Direction::Vertical) @@ -3627,22 +3665,31 @@ where 2 => { app.state.focus = Focus::CardDueDate; app.state.mouse_focus = Some(Focus::CardDueDate); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } 4 => { app.state.focus = Focus::CardPriority; app.state.mouse_focus = Some(Focus::CardPriority); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } 5 => { app.state.focus = Focus::CardStatus; app.state.mouse_focus = Some(Focus::CardStatus); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } _ => { @@ -3651,24 +3698,31 @@ where } } app.state - .card_view_list_state + .app_list_states + .card_view_list .select(Some((mouse_y - top_of_list) as usize)); } else { - app.state.card_view_list_state.select(None); + app.state.app_list_states.card_view_list.select(None); } }; if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, card_chunks[0]) { app.state.focus = Focus::CardName; app.state.mouse_focus = Some(Focus::CardName); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, card_chunks[1]) { app.state.focus = Focus::CardDescription; app.state.mouse_focus = Some(Focus::CardDescription); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } let card_tags_style = if app.state.focus == Focus::CardTags { @@ -3705,13 +3759,16 @@ where if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, card_chunks[3]) { app.state.focus = Focus::CardTags; app.state.mouse_focus = Some(Focus::CardTags); - app.state.card_view_comment_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); } if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, card_chunks[4]) { app.state.focus = Focus::CardComments; app.state.mouse_focus = Some(Focus::CardComments); - app.state.card_view_tag_list_state.select(None); + app.state.app_list_states.card_view_tag_list.select(None); } if app.state.app_status == AppStatus::UserInput { @@ -3733,8 +3790,19 @@ where rect.set_cursor(x_pos + 5, y_pos + 2); // +5 and +2 are to account for the "Due: " text and extra info position offset } Focus::CardTags => { - if app.state.card_view_tag_list_state.selected().is_some() { - let selected_index = app.state.card_view_tag_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_tag_list + .selected() + .is_some() + { + let selected_index = app + .state + .app_list_states + .card_view_tag_list + .selected() + .unwrap(); let mut counter = 0; let mut y_index = 0; let mut length_before_selected_tag = 0; @@ -3770,8 +3838,19 @@ where } } Focus::CardComments => { - if app.state.card_view_comment_list_state.selected().is_some() { - let selected_index = app.state.card_view_comment_list_state.selected().unwrap(); + if app + .state + .app_list_states + .card_view_comment_list + .selected() + .is_some() + { + let selected_index = app + .state + .app_list_states + .card_view_comment_list + .selected() + .unwrap(); let mut counter = 0; let mut y_index = 0; let mut length_before_selected_comment = 0; @@ -3823,8 +3902,11 @@ where if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, card_chunks[5]) { app.state.focus = Focus::SubmitButton; app.state.mouse_focus = Some(Focus::SubmitButton); - app.state.card_view_comment_list_state.select(None); - app.state.card_view_tag_list_state.select(None); + app.state + .app_list_states + .card_view_comment_list + .select(None); + app.state.app_list_states.card_view_tag_list.select(None); app.state.current_cursor_position = None; } let save_changes_style = if app.state.focus == Focus::SubmitButton { @@ -3849,16 +3931,14 @@ where } } -pub fn render_command_palette(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_command_palette(rect: &mut Frame, app: &mut App) { // Housekeeping match app.state.focus { Focus::CommandPaletteCommand => { if app .state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .selected() .is_none() && app.command_palette.command_search_results.is_some() @@ -3870,14 +3950,16 @@ where .is_empty() { app.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(Some(0)); } } Focus::CommandPaletteCard => { if app .state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .selected() .is_none() && app.command_palette.card_search_results.is_some() @@ -3889,14 +3971,16 @@ where .is_empty() { app.state - .command_palette_card_search_list_state + .app_list_states + .command_palette_card_search .select(Some(0)); } } Focus::CommandPaletteBoard => { if app .state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .selected() .is_none() && app.command_palette.board_search_results.is_some() @@ -3908,7 +3992,8 @@ where .is_empty() { app.state - .command_palette_board_search_list_state + .app_list_states + .command_palette_board_search .select(Some(0)); } } @@ -4314,17 +4399,17 @@ where rect.render_stateful_widget( command_search_results, search_results_chunks[0], - &mut app.state.command_palette_command_search_list_state, + &mut app.state.app_list_states.command_palette_command_search, ); rect.render_stateful_widget( card_search_results, search_results_chunks[1], - &mut app.state.command_palette_card_search_list_state, + &mut app.state.app_list_states.command_palette_card_search, ); rect.render_stateful_widget( board_search_results, search_results_chunks[2], - &mut app.state.command_palette_board_search_list_state, + &mut app.state.app_list_states.command_palette_board_search, ); let up_key = app @@ -4414,10 +4499,7 @@ where } } -pub fn render_change_ui_mode_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_change_ui_mode_popup(rect: &mut Frame, app: &mut App) { let all_ui_modes = UiMode::view_modes_as_string() .iter() .map(|s| ListItem::new(vec![Line::from(s.as_str().to_string())])) @@ -4436,7 +4518,8 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .default_view_state + .app_list_states + .default_view .select(Some((mouse_y - top_of_list) as usize)); } } @@ -4452,17 +4535,18 @@ where .highlight_symbol(LIST_SELECTED_SYMBOL); render_blank_styled_canvas(rect, app, popup_area, false); - rect.render_stateful_widget(ui_modes, popup_area, &mut app.state.default_view_state); + rect.render_stateful_widget( + ui_modes, + popup_area, + &mut app.state.app_list_states.default_view, + ); if app.config.enable_mouse_support { render_close_button(rect, app); } } -pub fn render_change_date_format_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_change_date_format_popup(rect: &mut Frame, app: &mut App) { let all_date_formats = DateFormat::get_all_date_formats(); let all_date_formats = all_date_formats .iter() @@ -4482,7 +4566,8 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .date_format_selector_state + .app_list_states + .date_format_selector .select(Some((mouse_y - top_of_list) as usize)); } } @@ -4501,7 +4586,7 @@ where rect.render_stateful_widget( date_formats, popup_area, - &mut app.state.date_format_selector_state, + &mut app.state.app_list_states.date_format_selector, ); if app.config.enable_mouse_support { @@ -4509,10 +4594,7 @@ where } } -pub fn render_change_card_status_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_change_card_status_popup(rect: &mut Frame, app: &mut App) { let mut card_name = String::new(); let mut board_name = String::new(); let boards = if app.filtered_boards.is_empty() { @@ -4550,7 +4632,8 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .card_status_selector_state + .app_list_states + .card_status_selector .select(Some((mouse_y - top_of_list) as usize)); } } @@ -4572,7 +4655,7 @@ where rect.render_stateful_widget( statuses, popup_area, - &mut app.state.card_status_selector_state, + &mut app.state.app_list_states.card_status_selector, ); if app.config.enable_mouse_support { @@ -4580,10 +4663,7 @@ where } } -pub fn render_card_priority_selector(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_card_priority_selector(rect: &mut Frame, app: &mut App) { let mut card_name = String::new(); let mut board_name = String::new(); let boards = if app.filtered_boards.is_empty() { @@ -4621,7 +4701,8 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .card_priority_selector_state + .app_list_states + .card_priority_selector .select(Some((mouse_y - top_of_list) as usize)); } } @@ -4643,7 +4724,7 @@ where rect.render_stateful_widget( priorities, popup_area, - &mut app.state.card_priority_selector_state, + &mut app.state.app_list_states.card_priority_selector, ); if app.config.enable_mouse_support { @@ -4651,10 +4732,7 @@ where } } -pub fn render_filter_by_tag_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_filter_by_tag_popup(rect: &mut Frame, app: &mut App) { if app.state.all_available_tags.is_some() { let submit_style = if app.state.focus == Focus::SubmitButton { app.current_theme.keyboard_focus_style @@ -4739,7 +4817,7 @@ where rect.render_stateful_widget( tags, filter_list_chunks[0], - &mut app.state.filter_by_tag_list_state, + &mut app.state.app_list_states.filter_by_tag_list, ); let up_key = app @@ -4837,7 +4915,12 @@ where if filter_list_chunks.len() > 1 { render_blank_styled_canvas(rect, app, filter_list_chunks[1], false); - let current_index = app.state.filter_by_tag_list_state.selected().unwrap_or(0); + let current_index = app + .state + .app_list_states + .filter_by_tag_list + .selected() + .unwrap_or(0); let total_rows = all_tags.len(); let visible_rows = (filter_list_chunks[1].height - 1) as usize; let percentage = ((current_index + 1) as f32 / total_rows as f32) * 100.0; @@ -4868,10 +4951,7 @@ where } } -pub fn render_debug_panel(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_debug_panel(rect: &mut Frame, app: &mut App) { let current_ui_mode = &app.state.ui_mode.to_string(); let popup_mode = if app.state.popup_mode.is_some() { app.state.popup_mode.as_ref().unwrap().to_string() @@ -4937,10 +5017,7 @@ pub fn check_if_mouse_is_in_area(mouse_coordinates: (u16, u16), rect_to_check: R false } -fn render_close_button(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +fn render_close_button(rect: &mut Frame, app: &mut App) { let close_btn_area = Rect::new(rect.size().width - 3, 0, 3, 3); let close_btn_style = if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, close_btn_area) { @@ -4961,10 +5038,7 @@ where rect.render_widget(close_btn, close_btn_area); } -pub fn render_change_theme_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_change_theme_popup(rect: &mut Frame, app: &mut App) { let render_area = centered_rect_with_percentage(70, 70, rect.size()); let clear_area = centered_rect_with_percentage(80, 80, rect.size()); let clear_area_border = Block::default() @@ -4998,15 +5072,16 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .theme_selector_state + .app_list_states + .theme_selector .select(Some((mouse_y - top_of_list) as usize)); let selected_theme = app .all_themes - .get(app.state.theme_selector_state.selected().unwrap()) + .get(app.state.app_list_states.theme_selector.selected().unwrap()) .unwrap(); app.current_theme = selected_theme.clone(); } else { - app.state.theme_selector_state.select(None); + app.state.app_list_states.theme_selector.select(None); } }; let themes = List::new(theme_list) @@ -5019,7 +5094,11 @@ where .highlight_style(app.current_theme.list_select_style) .highlight_symbol(LIST_SELECTED_SYMBOL); render_blank_styled_canvas(rect, app, chunks[0], false); - rect.render_stateful_widget(themes, chunks[0], &mut app.state.theme_selector_state); + rect.render_stateful_widget( + themes, + chunks[0], + &mut app.state.app_list_states.theme_selector, + ); let up_key = app .state @@ -5075,10 +5154,7 @@ where } } -pub fn render_create_theme(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_create_theme(rect: &mut Frame, app: &mut App) { let render_area = rect.size(); let main_chunks = Layout::default() .direction(Direction::Vertical) @@ -5107,13 +5183,14 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .theme_editor_state + .app_table_states + .theme_editor .select(Some((mouse_y - top_of_list) as usize)); } else { - app.state.theme_editor_state.select(None); + app.state.app_table_states.theme_editor.select(None); } app.current_theme.list_select_style - } else if app.state.theme_editor_state.selected().is_some() { + } else if app.state.app_table_states.theme_editor.selected().is_some() { app.current_theme.list_select_style } else { app.current_theme.general_style @@ -5155,7 +5232,7 @@ where rect.render_stateful_widget( theme_title_list, chunks[0], - &mut app.state.theme_editor_state, + &mut app.state.app_table_states.theme_editor, ); let theme_element_list = Table::new(theme_table_rows.1) .block(Block::default()) @@ -5163,7 +5240,7 @@ where rect.render_stateful_widget( theme_element_list, chunks[1], - &mut app.state.theme_editor_state, + &mut app.state.app_table_states.theme_editor, ); let submit_button = Paragraph::new(vec![Line::from("Create Theme")]) .block( @@ -5197,10 +5274,7 @@ where } } -pub fn render_edit_specific_style_popup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_edit_specific_style_popup(rect: &mut Frame, app: &mut App) { let popup_area = centered_rect_with_percentage(90, 80, rect.size()); let main_chunks = Layout::default() .direction(Direction::Vertical) @@ -5227,8 +5301,19 @@ where .split(main_chunks[0]); let fg_list_border_style = if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, chunks[0]) { - if app.state.edit_specific_style_state.0.selected().is_none() { - app.state.edit_specific_style_state.0.select(Some(0)); + if app + .state + .app_list_states + .edit_specific_style + .0 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .0 + .select(Some(0)); } app.state.mouse_focus = Some(Focus::StyleEditorFG); app.state.focus = Focus::StyleEditorFG; @@ -5240,8 +5325,19 @@ where }; let bg_list_border_style = if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, chunks[1]) { - if app.state.edit_specific_style_state.1.selected().is_none() { - app.state.edit_specific_style_state.1.select(Some(0)); + if app + .state + .app_list_states + .edit_specific_style + .1 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .1 + .select(Some(0)); } app.state.mouse_focus = Some(Focus::StyleEditorBG); app.state.focus = Focus::StyleEditorBG; @@ -5253,8 +5349,19 @@ where }; let modifiers_list_border_style = if check_if_mouse_is_in_area(app.state.current_mouse_coordinates, chunks[2]) { - if app.state.edit_specific_style_state.2.selected().is_none() { - app.state.edit_specific_style_state.2.select(Some(0)); + if app + .state + .app_list_states + .edit_specific_style + .2 + .selected() + .is_none() + { + app.state + .app_list_states + .edit_specific_style + .2 + .select(Some(0)); } app.state.mouse_focus = Some(Focus::StyleEditorModifier); app.state.focus = Focus::StyleEditorModifier; @@ -5412,7 +5519,7 @@ where ) .highlight_style(app.current_theme.list_select_style) .highlight_symbol(LIST_SELECTED_SYMBOL); - let theme_style_being_edited_index = app.state.theme_editor_state.selected(); + let theme_style_being_edited_index = app.state.app_table_states.theme_editor.selected(); let theme_style_being_edited = if let Some(index) = theme_style_being_edited_index { let theme_style_being_edited = app.state.theme_being_edited.to_vec_str(); if index < theme_style_being_edited.len() { @@ -5509,17 +5616,17 @@ where rect.render_stateful_widget( fg_list, chunks[0], - &mut app.state.edit_specific_style_state.0, + &mut app.state.app_list_states.edit_specific_style.0, ); rect.render_stateful_widget( bg_list, chunks[1], - &mut app.state.edit_specific_style_state.1, + &mut app.state.app_list_states.edit_specific_style.1, ); rect.render_stateful_widget( modifier_list, chunks[2], - &mut app.state.edit_specific_style_state.2, + &mut app.state.app_list_states.edit_specific_style.2, ); rect.render_widget(help_text, main_chunks[1]); rect.render_widget(submit_button, main_chunks[2]); @@ -5529,10 +5636,7 @@ where } } -pub fn render_save_theme_prompt(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_save_theme_prompt(rect: &mut Frame, app: &mut App) { let popup_area = centered_rect_with_length(40, 10, rect.size()); let chunks = Layout::default() .direction(Direction::Vertical) @@ -5592,10 +5696,7 @@ where } } -pub fn render_confirm_discard_card_changes(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_confirm_discard_card_changes(rect: &mut Frame, app: &mut App) { let popup_area = centered_rect_with_length(30, 7, rect.size()); render_blank_styled_canvas(rect, app, popup_area, true); let chunks = Layout::default() @@ -5655,10 +5756,7 @@ where } } -pub fn render_custom_rgb_color_prompt(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_custom_rgb_color_prompt(rect: &mut Frame, app: &mut App) { let popup_area = centered_rect_with_length(60, 18, rect.size()); let prompt_text = "Enter a custom RGB color in the format: r,g,b (0-254)"; @@ -5795,14 +5893,12 @@ where } } -pub fn render_blank_styled_canvas( - rect: &mut Frame, +pub fn render_blank_styled_canvas( + rect: &mut Frame, app: &mut App, render_area: Rect, popup_mode: bool, -) where - B: Backend, -{ +) { let mut styled_text = vec![]; for _ in 0..render_area.width + 1 { styled_text.push(" ".to_string()); @@ -5823,15 +5919,13 @@ pub fn render_blank_styled_canvas( rect.render_widget(styled_text, render_area); } -pub fn render_blank_styled_canvas_with_margin( - rect: &mut Frame, +pub fn render_blank_styled_canvas_with_margin( + rect: &mut Frame, app: &mut App, render_area: Rect, popup_mode: bool, margin: i16, -) where - B: Backend, -{ +) { let x = render_area.x as i16 + margin; let x = if x < 0 { 0 } else { x }; let y = render_area.y as i16 + margin; @@ -5863,15 +5957,13 @@ pub fn render_blank_styled_canvas_with_margin( rect.render_widget(styled_text, new_render_area); } -pub fn render_logs( +pub fn render_logs( app: &mut App, enable_focus_highlight: bool, render_area: Rect, - rect: &mut Frame, + rect: &mut Frame, popup_mode: bool, -) where - B: Backend, -{ +) { let date_format = app.config.date_format.to_parser_string(); let theme = &app.current_theme; let all_logs = get_logs(); @@ -5964,10 +6056,7 @@ pub fn render_logs( ); } -pub fn render_login(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_login(rect: &mut Frame, app: &mut App) { if app.state.popup_mode.is_none() { if app.state.focus == Focus::EmailIDField || app.state.focus == Focus::PasswordField { if app.state.app_status != AppStatus::UserInput { @@ -6198,21 +6287,21 @@ where .border_type(BorderType::Rounded) .border_style(separator_style); - let form_email_id_text = app.state.login_form.0[0].clone(); - let email_id_text = if app.state.login_form.0[0].is_empty() { + let form_email_id_text = app.state.app_form_states.login.0[0].clone(); + let email_id_text = if app.state.app_form_states.login.0[0].is_empty() { "Email ID" } else { &form_email_id_text }; - let form_password_text = app.state.login_form.0[1].clone(); + let form_password_text = app.state.app_form_states.login.0[1].clone(); let mut hidden_password = String::new(); - for _ in 0..app.state.login_form.0[1].len() { + for _ in 0..app.state.app_form_states.login.0[1].len() { hidden_password.push(HIDDEN_PASSWORD_SYMBOL); } - let password_text = if app.state.login_form.0[1].is_empty() { + let password_text = if app.state.app_form_states.login.0[1].is_empty() { "Password" - } else if app.state.login_form.1 { + } else if app.state.app_form_states.login.1 { &form_password_text } else { hidden_password.as_str() @@ -6239,7 +6328,11 @@ where .block(Block::default()) .alignment(Alignment::Right); - let show_password_checkbox_value = if app.state.login_form.1 { "[X]" } else { "[ ]" }; + let show_password_checkbox_value = if app.state.app_form_states.login.1 { + "[X]" + } else { + "[ ]" + }; let show_password_checkbox_paragraph = Paragraph::new(show_password_checkbox_value) .style(show_password_style) @@ -6292,7 +6385,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.login_form.0[0], + &app.state.app_form_states.login.0[0], email_id_field_chunk.width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -6301,7 +6394,7 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - email_id_field_chunk.x + 1 + app.state.login_form.0[0].len() as u16, + email_id_field_chunk.x + 1 + app.state.app_form_states.login.0[0].len() as u16, email_id_field_chunk.y + 1, ); } @@ -6309,7 +6402,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.login_form.0[1], + &app.state.app_form_states.login.0[1], password_field_chunk.width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -6318,7 +6411,7 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - password_field_chunk.x + 1 + app.state.login_form.0[1].len() as u16, + password_field_chunk.x + 1 + app.state.app_form_states.login.0[1].len() as u16, password_field_chunk.y + 1, ); } @@ -6326,10 +6419,7 @@ where } } -pub fn render_signup(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_signup(rect: &mut Frame, app: &mut App) { if app.state.popup_mode.is_none() { if app.state.focus == Focus::EmailIDField || app.state.focus == Focus::PasswordField @@ -6542,34 +6632,34 @@ where .border_type(BorderType::Rounded) .border_style(separator_style); - let form_email_id_text = app.state.signup_form.0[0].clone(); - let email_id_text = if app.state.signup_form.0[0].is_empty() { + let form_email_id_text = app.state.app_form_states.signup.0[0].clone(); + let email_id_text = if app.state.app_form_states.signup.0[0].is_empty() { "Email ID" } else { &form_email_id_text }; - let form_password_text = app.state.signup_form.0[1].clone(); + let form_password_text = app.state.app_form_states.signup.0[1].clone(); let mut hidden_password = String::new(); - for _ in 0..app.state.signup_form.0[1].len() { + for _ in 0..app.state.app_form_states.signup.0[1].len() { hidden_password.push(HIDDEN_PASSWORD_SYMBOL); } - let password_text = if app.state.signup_form.0[1].is_empty() { + let password_text = if app.state.app_form_states.signup.0[1].is_empty() { "Password" - } else if app.state.signup_form.1 { + } else if app.state.app_form_states.signup.1 { &form_password_text } else { hidden_password.as_str() }; - let form_confirm_password_text = app.state.signup_form.0[2].clone(); + let form_confirm_password_text = app.state.app_form_states.signup.0[2].clone(); let mut hidden_confirm_password = String::new(); - for _ in 0..app.state.signup_form.0[2].len() { + for _ in 0..app.state.app_form_states.signup.0[2].len() { hidden_confirm_password.push(HIDDEN_PASSWORD_SYMBOL); } - let confirm_password_text = if app.state.signup_form.0[2].is_empty() { + let confirm_password_text = if app.state.app_form_states.signup.0[2].is_empty() { "Confirm Password" - } else if app.state.signup_form.1 { + } else if app.state.app_form_states.signup.1 { &form_confirm_password_text } else { hidden_confirm_password.as_str() @@ -6604,7 +6694,7 @@ where .block(Block::default()) .alignment(Alignment::Right); - let show_password_checkbox_value = if app.state.signup_form.1 { + let show_password_checkbox_value = if app.state.app_form_states.signup.1 { "[X]" } else { "[ ]" @@ -6647,7 +6737,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.signup_form.0[0], + &app.state.app_form_states.signup.0[0], form_chunks[1].width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -6656,7 +6746,7 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - form_chunks[1].x + 1 + app.state.signup_form.0[0].len() as u16, + form_chunks[1].x + 1 + app.state.app_form_states.signup.0[0].len() as u16, form_chunks[1].y + 1, ); } @@ -6664,7 +6754,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.signup_form.0[1], + &app.state.app_form_states.signup.0[1], form_chunks[2].width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -6673,7 +6763,7 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - form_chunks[2].x + 1 + app.state.signup_form.0[1].len() as u16, + form_chunks[2].x + 1 + app.state.app_form_states.signup.0[1].len() as u16, form_chunks[2].y + 1, ); } @@ -6681,7 +6771,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.signup_form.0[2], + &app.state.app_form_states.signup.0[2], form_chunks[3].width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -6690,7 +6780,7 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - form_chunks[3].x + 1 + app.state.signup_form.0[2].len() as u16, + form_chunks[3].x + 1 + app.state.app_form_states.signup.0[2].len() as u16, form_chunks[3].y + 1, ); } @@ -6698,10 +6788,7 @@ where } } -pub fn render_reset_password(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_reset_password(rect: &mut Frame, app: &mut App) { if app.state.popup_mode.is_none() { if app.state.focus == Focus::EmailIDField || app.state.focus == Focus::ResetPasswordLinkField @@ -7012,8 +7099,8 @@ where .border_type(BorderType::Rounded) .border_style(separator_style); - let form_email_id_text = app.state.reset_password_form.0[0].clone(); - let email_id_text = if app.state.reset_password_form.0[0].is_empty() { + let form_email_id_text = app.state.app_form_states.reset_password.0[0].clone(); + let email_id_text = if app.state.app_form_states.reset_password.0[0].is_empty() { "Email ID" } else { &form_email_id_text @@ -7036,10 +7123,10 @@ where "Send Reset Link".to_string() }; - let reset_link_field_text = if app.state.reset_password_form.0[1].is_empty() { + let reset_link_field_text = if app.state.app_form_states.reset_password.0[1].is_empty() { "Reset Link".to_string() } else { - app.state.reset_password_form.0[1].clone() + app.state.app_form_states.reset_password.0[1].clone() }; let (windowed_reset_link, reset_link_cursor_pos_x) = get_sliding_window_over_text( &reset_link_field_text, @@ -7049,36 +7136,37 @@ where reset_link_chunk.width - 2, ); - let new_password_field_text = if app.state.reset_password_form.0[2].is_empty() { + let new_password_field_text = if app.state.app_form_states.reset_password.0[2].is_empty() { "New Password".to_string() - } else if app.state.reset_password_form.1 { - app.state.reset_password_form.0[2].clone() + } else if app.state.app_form_states.reset_password.1 { + app.state.app_form_states.reset_password.0[2].clone() } else { let mut hidden_password = String::new(); - for _ in 0..app.state.reset_password_form.0[2].len() { + for _ in 0..app.state.app_form_states.reset_password.0[2].len() { hidden_password.push(HIDDEN_PASSWORD_SYMBOL); } hidden_password }; - let confirm_new_password_field_text = if app.state.reset_password_form.0[3].is_empty() { - "Confirm New Password".to_string() - } else if app.state.reset_password_form.1 { - app.state.reset_password_form.0[3].clone() - } else { - let mut hidden_password = String::new(); - for _ in 0..app.state.reset_password_form.0[3].len() { - hidden_password.push(HIDDEN_PASSWORD_SYMBOL); - } - hidden_password - }; + let confirm_new_password_field_text = + if app.state.app_form_states.reset_password.0[3].is_empty() { + "Confirm New Password".to_string() + } else if app.state.app_form_states.reset_password.1 { + app.state.app_form_states.reset_password.0[3].clone() + } else { + let mut hidden_password = String::new(); + for _ in 0..app.state.app_form_states.reset_password.0[3].len() { + hidden_password.push(HIDDEN_PASSWORD_SYMBOL); + } + hidden_password + }; let show_password_paragraph = Paragraph::new("Show Password") .style(show_password_style) .block(Block::default()) .alignment(Alignment::Right); - let show_password_checkbox_value = if app.state.reset_password_form.1 { + let show_password_checkbox_value = if app.state.app_form_states.reset_password.1 { "[X]" } else { "[ ]" @@ -7164,7 +7252,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.reset_password_form.0[0], + &app.state.app_form_states.reset_password.0[0], email_id_chunk.width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -7173,7 +7261,9 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - email_id_chunk.x + 1 + app.state.reset_password_form.0[0].len() as u16, + email_id_chunk.x + + 1 + + app.state.app_form_states.reset_password.0[0].len() as u16, email_id_chunk.y + 1, ); } @@ -7186,7 +7276,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.reset_password_form.0[2], + &app.state.app_form_states.reset_password.0[2], new_password_chunk.width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -7195,7 +7285,9 @@ where rect.set_cursor(x_pos, y_pos); } else { rect.set_cursor( - new_password_chunk.x + 1 + app.state.reset_password_form.0[2].len() as u16, + new_password_chunk.x + + 1 + + app.state.app_form_states.reset_password.0[2].len() as u16, new_password_chunk.y + 1, ); } @@ -7203,7 +7295,7 @@ where if app.state.current_cursor_position.is_some() { let (x_pos, y_pos) = calculate_cursor_position( textwrap::wrap( - &app.state.reset_password_form.0[3], + &app.state.app_form_states.reset_password.0[3], confirm_new_password_chunk.width as usize - 2, ), app.state.current_cursor_position.unwrap_or(0), @@ -7214,7 +7306,7 @@ where rect.set_cursor( confirm_new_password_chunk.x + 1 - + app.state.reset_password_form.0[3].len() as u16, + + app.state.app_form_states.reset_password.0[3].len() as u16, confirm_new_password_chunk.y + 1, ); } @@ -7222,10 +7314,7 @@ where } } -pub fn render_load_cloud_save(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn render_load_cloud_save(rect: &mut Frame, app: &mut App) { let default_style = if app.state.popup_mode.is_some() { app.current_theme.inactive_text_style } else { @@ -7322,11 +7411,16 @@ where let mouse_y = app.state.current_mouse_coordinates.1; if mouse_y >= top_of_list && mouse_y <= bottom_of_list { app.state - .load_save_state + .app_list_states + .load_save .select(Some((mouse_y - top_of_list) as usize)); } } - rect.render_stateful_widget(choice_list, chunks[1], &mut app.state.load_save_state); + rect.render_stateful_widget( + choice_list, + chunks[1], + &mut app.state.app_list_states.load_save, + ); } } else { let no_saves_paragraph = Paragraph::new("Waiting for data from the cloud...") @@ -7390,7 +7484,7 @@ where .wrap(ratatui::widgets::Wrap { trim: true }); rect.render_widget(help_paragraph, chunks[2]); - if app.state.load_save_state.selected().is_none() { + if app.state.app_list_states.load_save.selected().is_none() { let preview_paragraph = Paragraph::new(format!("Select a save file with {}or {}to preview or Click on a save file to preview if using a mouse", up_key, down_key)) .alignment(Alignment::Center) diff --git a/src/ui/ui_main.rs b/src/ui/ui_main.rs index 1616d45..f59e9c0 100644 --- a/src/ui/ui_main.rs +++ b/src/ui/ui_main.rs @@ -1,12 +1,9 @@ use super::{super::app::state::AppStatus, ui_helper}; use crate::app::App; -use ratatui::{backend::Backend, Frame}; +use ratatui::Frame; /// Main UI Drawing handler -pub fn draw(rect: &mut Frame, app: &mut App) -where - B: Backend, -{ +pub fn draw(rect: &mut Frame, app: &mut App) { ui_helper::render_blank_styled_canvas(rect, app, rect.size(), app.state.popup_mode.is_some()); let msg = ui_helper::check_size(&rect.size()); if &msg != "Size OK" { diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs index 80aee84..24e31fe 100644 --- a/src/ui/widgets.rs +++ b/src/ui/widgets.rs @@ -22,23 +22,23 @@ use tokio::{sync::MutexGuard, time::Instant}; #[derive(Clone, Debug, PartialEq)] pub struct ToastWidget { - pub title: String, - pub message: String, pub duration: Duration, + pub message: String, pub start_time: Instant, - pub toast_type: ToastType, + pub title: String, pub toast_color: (u8, u8, u8), + pub toast_type: ToastType, } impl ToastWidget { pub fn new(message: String, duration: Duration, toast_type: ToastType, theme: Theme) -> Self { Self { - title: toast_type.as_str().to_string(), - message, duration, + message, start_time: Instant::now(), - toast_type: toast_type.clone(), + title: toast_type.as_str().to_string(), toast_color: toast_type.as_color(theme), + toast_type: toast_type.clone(), } } pub fn new_with_title( @@ -49,12 +49,12 @@ impl ToastWidget { theme: Theme, ) -> Self { Self { - title, - message, duration, + message, start_time: Instant::now(), - toast_type: toast_type.clone(), + title, toast_color: toast_type.as_color(theme), + toast_type: toast_type.clone(), } } @@ -100,18 +100,18 @@ impl ToastWidget { #[derive(Clone, Debug, PartialEq)] pub enum ToastType { Error, - Warning, Info, Loading, + Warning, } impl ToastType { pub fn as_str(&self) -> &str { match self { Self::Error => "Error", - Self::Warning => "Warning", Self::Info => "Info", Self::Loading => "Loading", + Self::Warning => "Warning", } } pub fn as_color(&self, theme: Theme) -> (u8, u8, u8) { @@ -165,14 +165,14 @@ impl WidgetManager<'_> { #[derive(Debug)] pub struct CommandPaletteWidget { - pub command_search_results: Option>, - pub card_search_results: Option>, - pub board_search_results: Option>, - pub last_search_string: String, - pub available_commands: Vec, pub already_in_user_input_mode: bool, - pub last_focus: Option, + pub available_commands: Vec, + pub board_search_results: Option>, + pub card_search_results: Option>, pub command_palette_actions_corpus: Corpus, + pub command_search_results: Option>, + pub last_focus: Option, + pub last_search_string: String, } impl CommandPaletteWidget { @@ -183,27 +183,29 @@ impl CommandPaletteWidget { corpus.add_text(command.to_string().to_lowercase().as_str()); } Self { - command_search_results: None, - card_search_results: None, - board_search_results: None, - last_search_string: RANDOM_SEARCH_TERM.to_string(), already_in_user_input_mode: false, - last_focus: None, available_commands: CommandPaletteActions::all(debug_mode), + board_search_results: None, + card_search_results: None, command_palette_actions_corpus: corpus, + command_search_results: None, + last_focus: None, + last_search_string: RANDOM_SEARCH_TERM.to_string(), } } pub async fn handle_command(app: &mut App<'_>) -> AppReturn { if app .state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .selected() .is_some() { let command_index = app .state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .selected() .unwrap(); let command = if app.command_palette.command_search_results.is_some() { @@ -218,29 +220,28 @@ impl CommandPaletteWidget { if command.is_some() { match command.unwrap() { CommandPaletteActions::Quit => { - handle_exit(app).await; info!("Quitting"); - return AppReturn::Exit; + return handle_exit(app).await; } - CommandPaletteActions::OpenConfigMenu => { + CommandPaletteActions::ConfigMenu => { app.state.popup_mode = None; app.state.prev_ui_mode = Some(app.state.ui_mode); app.state.ui_mode = UiMode::ConfigMenu; - app.state.config_state.select(Some(0)); + app.state.app_table_states.config.select(Some(0)); app.state.focus = Focus::ConfigTable; } - CommandPaletteActions::OpenMainMenu => { + CommandPaletteActions::MainMenu => { app.state.popup_mode = None; app.state.prev_ui_mode = Some(app.state.ui_mode); app.state.ui_mode = UiMode::MainMenu; - app.state.main_menu_state.select(Some(0)); + app.state.app_list_states.main_menu.select(Some(0)); app.state.focus = Focus::MainMenu; } - CommandPaletteActions::OpenHelpMenu => { + CommandPaletteActions::HelpMenu => { app.state.popup_mode = None; app.state.prev_ui_mode = Some(app.state.ui_mode); app.state.ui_mode = UiMode::HelpMenu; - app.state.help_state.select(Some(0)); + app.state.app_table_states.help.select(Some(0)); app.state.focus = Focus::Body; } CommandPaletteActions::SaveKanbanState => { @@ -298,7 +299,10 @@ impl CommandPaletteWidget { app.state.popup_mode = Some(PopupMode::CardStatusSelector); app.state.app_status = AppStatus::Initialized; - app.state.card_status_selector_state.select(Some(0)); + app.state + .app_list_states + .card_status_selector + .select(Some(0)); return AppReturn::Continue; } } @@ -349,7 +353,7 @@ impl CommandPaletteWidget { } app.state.filter_tags = None; app.state.all_available_tags = None; - app.state.filter_by_tag_list_state.select(None); + app.state.app_list_states.filter_by_tag_list.select(None); app.state.popup_mode = None; app.filtered_boards = vec![]; refresh_visible_boards_and_cards(app); @@ -544,14 +548,17 @@ impl CommandPaletteWidget { app.command_palette.command_search_results = Some(command_search_results); app.command_palette.last_search_string = current_search_string; - if app.command_palette.command_search_results.is_some() && !app + if app.command_palette.command_search_results.is_some() + && !app .command_palette .command_search_results .as_ref() .unwrap() - .is_empty() { + .is_empty() + { app.state - .command_palette_command_search_list_state + .app_list_states + .command_palette_command_search .select(Some(0)); } } @@ -591,59 +598,59 @@ impl CommandPaletteWidget { #[derive(Clone, Debug, PartialEq)] pub enum CommandPaletteActions { - OpenConfigMenu, - SaveKanbanState, - LoadASaveLocal, - NewBoard, - NewCard, - ResetUI, - OpenMainMenu, - OpenHelpMenu, - ChangeUIMode, ChangeCurrentCardStatus, - DebugMenu, + ChangeDateFormat, ChangeTheme, + ChangeUIMode, + ClearFilter, + ConfigMenu, CreateATheme, + DebugMenu, FilterByTag, - ClearFilter, - NoCommandsFound, - ChangeDateFormat, - Login, - SyncLocalData, + HelpMenu, LoadASaveCloud, + LoadASaveLocal, + Login, Logout, - SignUp, - ResetPassword, + MainMenu, + NewBoard, + NewCard, + NoCommandsFound, Quit, + ResetPassword, + ResetUI, + SaveKanbanState, + SignUp, + SyncLocalData, } impl Display for CommandPaletteActions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::OpenConfigMenu => write!(f, "Configure"), - Self::SaveKanbanState => write!(f, "Save Kanban State"), - Self::LoadASaveLocal => write!(f, "Load a Save (Local)"), - Self::NewBoard => write!(f, "New Board"), - Self::NewCard => write!(f, "New Card"), - Self::ResetUI => write!(f, "Reset UI"), - Self::OpenMainMenu => write!(f, "Open Main Menu"), - Self::OpenHelpMenu => write!(f, "Open Help Menu"), - Self::ChangeUIMode => write!(f, "Change UI Mode"), Self::ChangeCurrentCardStatus => write!(f, "Change Current Card Status"), - Self::DebugMenu => write!(f, "Toggle Debug Panel"), + Self::ChangeDateFormat => write!(f, "Change Date Format"), Self::ChangeTheme => write!(f, "Change Theme"), + Self::ChangeUIMode => write!(f, "Change UI Mode"), + Self::ClearFilter => write!(f, "Clear Filter"), Self::CreateATheme => write!(f, "Create a Theme"), + Self::DebugMenu => write!(f, "Toggle Debug Panel"), Self::FilterByTag => write!(f, "Filter by Tag"), - Self::ClearFilter => write!(f, "Clear Filter"), - Self::NoCommandsFound => write!(f, "No Commands Found"), - Self::ChangeDateFormat => write!(f, "Change Date Format"), - Self::Login => write!(f, "Login"), - Self::SyncLocalData => write!(f, "Sync Local Data"), Self::LoadASaveCloud => write!(f, "Load a Save (Cloud)"), + Self::LoadASaveLocal => write!(f, "Load a Save (Local)"), + Self::Login => write!(f, "Login"), Self::Logout => write!(f, "Logout"), - Self::SignUp => write!(f, "Sign Up"), - Self::ResetPassword => write!(f, "Reset Password"), + Self::NewBoard => write!(f, "New Board"), + Self::NewCard => write!(f, "New Card"), + Self::NoCommandsFound => write!(f, "No Commands Found"), + Self::ConfigMenu => write!(f, "Configure"), + Self::HelpMenu => write!(f, "Open Help Menu"), + Self::MainMenu => write!(f, "Open Main Menu"), Self::Quit => write!(f, "Quit"), + Self::ResetPassword => write!(f, "Reset Password"), + Self::ResetUI => write!(f, "Reset UI"), + Self::SaveKanbanState => write!(f, "Save Kanban State"), + Self::SignUp => write!(f, "Sign Up"), + Self::SyncLocalData => write!(f, "Sync Local Data"), } } } @@ -651,28 +658,28 @@ impl Display for CommandPaletteActions { impl CommandPaletteActions { pub fn all(debug_mode: bool) -> Vec { let all = vec![ - Self::OpenConfigMenu, - Self::SaveKanbanState, - Self::SyncLocalData, - Self::LoadASaveLocal, - Self::LoadASaveCloud, - Self::NewBoard, - Self::NewCard, - Self::ResetUI, - Self::OpenMainMenu, - Self::OpenHelpMenu, - Self::ChangeUIMode, Self::ChangeCurrentCardStatus, + Self::ChangeDateFormat, Self::ChangeTheme, + Self::ChangeUIMode, + Self::ClearFilter, + Self::ConfigMenu, Self::CreateATheme, Self::FilterByTag, - Self::ClearFilter, - Self::ChangeDateFormat, + Self::HelpMenu, + Self::LoadASaveCloud, + Self::LoadASaveLocal, Self::Login, Self::Logout, - Self::SignUp, - Self::ResetPassword, + Self::MainMenu, + Self::NewBoard, + Self::NewCard, Self::Quit, + Self::ResetPassword, + Self::ResetUI, + Self::SaveKanbanState, + Self::SignUp, + Self::SyncLocalData, ]; if cfg!(debug_assertions) || debug_mode { @@ -687,14 +694,14 @@ impl CommandPaletteActions { pub fn from_string(s: &str, lowercase_match: bool) -> Option { if lowercase_match { match s.to_lowercase().as_str() { - "configure" => Some(Self::OpenConfigMenu), + "configure" => Some(Self::ConfigMenu), "save kanban state" => Some(Self::SaveKanbanState), "load a save (local)" => Some(Self::LoadASaveLocal), "new board" => Some(Self::NewBoard), "new card" => Some(Self::NewCard), "reset ui" => Some(Self::ResetUI), - "open main menu" => Some(Self::OpenMainMenu), - "open help menu" => Some(Self::OpenHelpMenu), + "open main menu" => Some(Self::MainMenu), + "open help menu" => Some(Self::HelpMenu), "change ui mode" => Some(Self::ChangeUIMode), "change current card status" => Some(Self::ChangeCurrentCardStatus), "toggle debug panel" => Some(Self::DebugMenu), @@ -714,14 +721,14 @@ impl CommandPaletteActions { } } else { match s { - "Configure" => Some(Self::OpenConfigMenu), + "Configure" => Some(Self::ConfigMenu), "Save Kanban State" => Some(Self::SaveKanbanState), "Load a Save (Local)" => Some(Self::LoadASaveLocal), "New Board" => Some(Self::NewBoard), "New Card" => Some(Self::NewCard), "Reset UI" => Some(Self::ResetUI), - "Open Main Menu" => Some(Self::OpenMainMenu), - "Open Help Menu" => Some(Self::OpenHelpMenu), + "Open Main Menu" => Some(Self::MainMenu), + "Open Help Menu" => Some(Self::HelpMenu), "Change UI Mode" => Some(Self::ChangeUIMode), "Change Current Card Status" => Some(Self::ChangeCurrentCardStatus), "Toggle Debug Panel" => Some(Self::DebugMenu), diff --git a/src/util.rs b/src/util.rs index 3b2be7b..70359df 100644 --- a/src/util.rs +++ b/src/util.rs @@ -141,7 +141,7 @@ pub async fn gen_new_key_main(email_id: String, password: String) -> Result<()> print_error("Aborting..."); return Ok(()); } - let (access_token, user_id) = login_for_user_status.unwrap(); + let (access_token, user_id, _refresh_token) = login_for_user_status.unwrap(); let save_ids = get_all_save_ids_and_creation_dates_for_user(user_id.to_owned(), &access_token, true) .await?;