diff --git a/Cargo.lock b/Cargo.lock index 3fe7e64..36e9323 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,24 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "ansi_term" version = "0.11.0" @@ -17,34 +35,22 @@ version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -68,15 +74,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "blake2b_simd" -version = "0.5.11" +name = "bitflags" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -117,6 +118,21 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "castaway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.0.68" @@ -151,20 +167,33 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.2.1", "strsim", "textwrap", "unicode-width", "vec_map", ] +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa 1.0.10", + "ryu", + "static_assertions", +] + [[package]] name = "console" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" dependencies = [ - "encode_unicode", + "encode_unicode 0.3.6", "lazy_static", "libc", "regex", @@ -173,12 +202,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "core-foundation" version = "0.9.1" @@ -236,6 +259,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.4.2", + "crossterm_winapi", + "libc", + "mio 0.8.10", + "parking_lot 0.12.1", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "csv" version = "1.1.6" @@ -244,7 +292,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -280,10 +328,20 @@ dependencies = [ ] [[package]] -name = "dirs" -version = "1.0.5" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -296,12 +354,24 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.28" @@ -311,6 +381,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -383,7 +463,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 1.0.73", ] [[package]] @@ -436,17 +516,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -485,6 +554,16 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "heck" version = "0.3.3" @@ -494,6 +573,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -503,6 +588,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + [[package]] name = "home" version = "0.5.3" @@ -520,7 +611,7 @@ checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 0.4.7", ] [[package]] @@ -561,7 +652,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.7", "pin-project-lite", "socket2", "tokio", @@ -616,9 +707,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] +[[package]] +name = "indoc" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" + [[package]] name = "instant" version = "0.1.10" @@ -634,12 +731,38 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi 0.3.4", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "js-sys" version = "0.3.51" @@ -657,16 +780,34 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.98" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ + "autocfg", "scopeguard", ] @@ -679,6 +820,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "matches" version = "0.1.8" @@ -719,6 +869,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "miow" version = "0.3.7" @@ -780,7 +942,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -792,7 +954,7 @@ checksum = "80e47cfc4c0a1a519d9a025ebfbac3a2439d1b5cdf397d72dcb79b11d9920dab" dependencies = [ "base64", "chrono", - "getrandom 0.2.3", + "getrandom", "http", "rand", "reqwest", @@ -806,9 +968,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -822,7 +984,7 @@ version = "0.10.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cfg-if", "foreign-types", "libc", @@ -857,7 +1019,17 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.3", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", ] [[package]] @@ -874,6 +1046,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -906,13 +1097,13 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "prettytable-rs" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" dependencies = [ - "atty", "csv", - "encode_unicode", + "encode_unicode 1.0.0", + "is-terminal", "lazy_static", "term", "unicode-width", @@ -927,7 +1118,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.73", "version_check", ] @@ -956,18 +1147,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1000,7 +1191,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", + "getrandom", ] [[package]] @@ -1012,6 +1203,26 @@ dependencies = [ "rand_core", ] +[[package]] +name = "ratatui" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "154b85ef15a5d1719bcaa193c3c81fe645cd120c156874cd660fe49fd21d1373" +dependencies = [ + "bitflags 2.4.2", + "cassowary", + "compact_str", + "crossterm", + "indoc", + "itertools", + "lru", + "paste", + "stability", + "strum", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "rchore" version = "0.1.0" @@ -1020,11 +1231,13 @@ dependencies = [ "bincode", "chrono", "console", + "crossterm", "dialoguer", "dotenv", "home", "oauth2", "prettytable-rs", + "ratatui", "reqwest", "serde", "serde_json", @@ -1035,28 +1248,31 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags 1.2.1", +] [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "getrandom", + "libredox", + "thiserror", ] [[package]] @@ -1144,15 +1360,16 @@ dependencies = [ ] [[package]] -name = "rust-argon2" -version = "0.8.3" +name = "rustix" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1168,6 +1385,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.5" @@ -1206,7 +1429,7 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" dependencies = [ - "bitflags", + "bitflags 1.2.1", "core-foundation", "core-foundation-sys", "libc", @@ -1240,7 +1463,7 @@ checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.73", ] [[package]] @@ -1249,7 +1472,7 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1270,7 +1493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1288,6 +1511,36 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio 0.8.10", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.3" @@ -1307,7 +1560,7 @@ dependencies = [ "fxhash", "libc", "log", - "parking_lot", + "parking_lot 0.11.1", ] [[package]] @@ -1332,6 +1585,22 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "stability" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd1b177894da2a2d9120208c3386066af06a488255caabc5de8ddca22dbc3ce" +dependencies = [ + "quote", + "syn 1.0.73", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.8.0" @@ -1355,11 +1624,33 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.73", +] + +[[package]] +name = "strum" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", ] [[package]] @@ -1373,6 +1664,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.2.0" @@ -1389,12 +1691,12 @@ dependencies = [ [[package]] name = "term" -version = "0.5.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "byteorder", - "dirs", + "dirs-next", + "rustversion", "winapi", ] @@ -1434,7 +1736,7 @@ checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.73", ] [[package]] @@ -1473,7 +1775,7 @@ dependencies = [ "bytes", "libc", "memchr", - "mio", + "mio 0.7.13", "num_cpus", "pin-project-lite", "winapi", @@ -1561,6 +1863,12 @@ dependencies = [ "matches", ] +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -1572,9 +1880,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -1621,9 +1929,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" @@ -1637,15 +1945,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" @@ -1670,7 +1978,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 1.0.73", "wasm-bindgen-shared", ] @@ -1704,7 +2012,7 @@ checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.73", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1766,6 +2074,138 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winreg" version = "0.7.0" @@ -1775,6 +2215,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "zeroize" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index 5c828d2..694ff84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,9 @@ dialoguer = "0.8.0" console = "0.14.1" sled = "0.34.6" bincode = "1.3.3" -prettytable-rs = "0.8.0" +prettytable-rs = "0.10.0" +ratatui = "0.26.0" +crossterm = "0.27.0" [dependencies.serde] version = "1.0.64" diff --git a/build.rs b/build.rs index af8348a..e93a69d 100644 --- a/build.rs +++ b/build.rs @@ -3,8 +3,9 @@ use std::env; use std::io::Write; fn write_link_info_type(file: &mut std::fs::File) -> Result<(), std::io::Error> { - let cid = env::var("GOOGLE_CLIENT_ID").unwrap(); - let cls = env::var("GOOGLE_CLIENT_SECRET").unwrap(); + let cid = env::var("GOOGLE_CLIENT_ID").expect("env var GOOGLE_CLIENT_ID should be set but was"); + let cls = env::var("GOOGLE_CLIENT_SECRET") + .expect("env var GOOGLE_CLIENT_SECRET should be set but was"); let data = format!( "pub struct Secrets {{ pub client_id: String, @@ -25,7 +26,7 @@ impl Secrets {{ } fn generate_module() -> Result<(), std::io::Error> { - let mut module = std::fs::File::create(&format!("src/{}.rs", "secrets"))?; + let mut module = std::fs::File::create(format!("src/{}.rs", "secrets"))?; write_link_info_type(&mut module)?; Ok(()) } diff --git a/src/cli.rs b/src/cli.rs index bb32fbb..f6ac160 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -38,7 +38,7 @@ pub enum TaskAction { /// Set the tasks status to completed. #[structopt(short, long)] - completed: bool + completed: bool, }, /// Clear all completed tasks in a task-list. Clear, @@ -108,4 +108,6 @@ pub enum Commands { }, /// Helps you set-up battery for p10k Battery, + /// Opens a terminal user interface + Tui, } diff --git a/src/handlers/task_handler.rs b/src/handlers/task_handler.rs index 4344a0b..2ee384a 100644 --- a/src/handlers/task_handler.rs +++ b/src/handlers/task_handler.rs @@ -25,10 +25,15 @@ impl TaskManager { Ok(()) } - pub fn add_task(&self, title: Option, notes: Option, completed: bool) -> anyhow::Result<()> { + pub fn add_task( + &self, + title: Option, + notes: Option, + completed: bool, + ) -> anyhow::Result<()> { let task = match title { Some(t) => self.create_task_without_prompts(t, notes, completed), - None => self.create_task_with_prompts(notes, completed)? + None => self.create_task_with_prompts(notes, completed)?, }; let resp = &self.client.add_task(task); match resp { @@ -41,31 +46,44 @@ impl TaskManager { Ok(()) } - fn create_task_without_prompts(&self, title: String, notes: Option, completed: bool) -> Tasks { + fn create_task_without_prompts( + &self, + title: String, + notes: Option, + completed: bool, + ) -> Tasks { let status = if completed { String::from("completed") } else { String::from("needsAction") }; - Tasks::new(None, title, notes.unwrap_or_else(||String::from("")), status) + Tasks::new( + None, + title, + notes.unwrap_or_else(|| String::from("")), + status, + ) } - fn create_task_with_prompts (&self, notes: Option, done: bool) -> anyhow::Result { + fn create_task_with_prompts(&self, notes: Option, done: bool) -> anyhow::Result { let title: String = Input::with_theme(&ColorfulTheme::default()) .with_prompt("Title of the task") .with_initial_text("task") .allow_empty(false) .interact_text()?; - - let notes: String = notes.map(Result::Ok).unwrap_or_else(|| Input::with_theme(&ColorfulTheme::default()) + + let notes: String = notes.map(Result::Ok).unwrap_or_else(|| { + Input::with_theme(&ColorfulTheme::default()) .with_prompt("Note for task") .with_initial_text("note") .allow_empty(true) .interact_text() - )?; + })?; let items = vec!["No", "Yes"]; - let completed = if done { 1_usize } else { + let completed = if done { + 1_usize + } else { Select::with_theme(&ColorfulTheme::default()) .with_prompt("Is the task completed?") .items(&items) diff --git a/src/handlers/tasklist_handler.rs b/src/handlers/tasklist_handler.rs index ee3efe8..50221dd 100644 --- a/src/handlers/tasklist_handler.rs +++ b/src/handlers/tasklist_handler.rs @@ -104,7 +104,7 @@ impl TaskListManager { let resp = &self.client.fetch_tasklist(false); match resp { Ok(data) => Ok(data.items.clone()), - Err(_err) => Err(anyhow!("Cannot fetch tasklists!")), + Err(err) => Err(anyhow!("Cannot fetch tasklists! {}", err)), } } diff --git a/src/main.rs b/src/main.rs index 06993a0..121527d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ mod oauth; mod printer; mod secrets; mod service; +mod tui; #[macro_use] extern crate prettytable; @@ -30,7 +31,11 @@ fn main() -> anyhow::Result<()> { } Delete { position } => generate_task_manager(tasks_database).delete_task(position)?, Show { position } => generate_task_manager(tasks_database).show_task(position)?, - Add { title, notes, completed } => generate_task_manager(tasks_database).add_task(title, notes, completed)?, + Add { + title, + notes, + completed, + } => generate_task_manager(tasks_database).add_task(title, notes, completed)?, Clear => generate_task_manager(tasks_database).clear_tasks()?, Undo { position } => { generate_task_manager(tasks_database).complete_task(position, false)? @@ -60,6 +65,7 @@ fn main() -> anyhow::Result<()> { Logout => oauth::logout(&tasks_database)?, }, Battery => MiscManager.help_p10k_script_generation()?, + Tui => tui::open(tasks_database)?, } Ok(()) } diff --git a/src/models/tasks.rs b/src/models/tasks.rs index 5abf27c..6bdb50b 100644 --- a/src/models/tasks.rs +++ b/src/models/tasks.rs @@ -31,6 +31,8 @@ pub struct Tasks { pub status: String, #[serde(default)] pub due: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub parent: Option, } impl Tasks { @@ -46,6 +48,7 @@ impl Tasks { notes, status, due: String::from(""), + parent: None, } } @@ -61,10 +64,11 @@ impl Tasks { notes: String::from(&self.notes), status: String::from(&self.status), due: String::from(&self.due), + parent: self.parent.clone(), } } - pub fn get_sanitised_data(&self) -> (String, String, String, String) { + pub fn get_sanitised_data(&self, tasks: &[Tasks]) -> (String, String, String, String, String) { let status = if self.status == "needsAction" { String::from("Incomplete") } else { @@ -82,7 +86,22 @@ impl Tasks { } else { String::from(&self.notes) }; - (String::from(&self.title), status, notes, due) + let parent = self.parent.clone().unwrap_or("No parent".into()); + + println!("{self:?}"); + + let parent = tasks + .iter() + .find(|t| t.id == Some(parent.clone())) + .map(|t| t.title.clone()) + .unwrap_or("Parent not found!".to_string()); + ( + String::from(&self.title), + status, + notes, + due, + parent.to_string(), + ) } } @@ -103,13 +122,15 @@ impl fmt::Display for Tasks { } else { String::from(&self.notes) }; + let parent = self.parent.clone().unwrap_or("No parent".into()); write!( f, - "{0: <10} | {1: <10} | {2: <10} | {3: <10}", + "{0: <10} | {1: <10} | {2: <10} | {3: <10} | {4: <10}", style(&self.title).for_stdout().green(), notes, status, - due + due, + parent, ) } } diff --git a/src/tui.rs b/src/tui.rs new file mode 100644 index 0000000..b01879b --- /dev/null +++ b/src/tui.rs @@ -0,0 +1,360 @@ +use crate::{ + models::{tasklist::TaskList, tasks::Tasks}, + service::{ + database_api::TasksDatabase, google_api::GoogleApiClient, google_tasklist::ApiTaskList, + google_tasks::ApiTasks, + }, +}; +use crossterm::{ + event::{self, Event, KeyCode}, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, + ExecutableCommand, +}; +use ratatui::{prelude::*, widgets::*}; +use std::io::stdout; + +struct State { + google_api_client: GoogleApiClient, + should_quit: bool, + tasklists: Vec, + tasks: Vec, + selected_tasklist: usize, + selected_task: usize, + show_error: Option, + is_hidden_shown: bool, + create_task: Option, // TODO https://github.com/sayanarijit/tui-input/blob/main/examples/ratatui-input/src/main.rs +} + +pub fn open(tasks_database: TasksDatabase) -> anyhow::Result<()> { + let google_api_client = GoogleApiClient::new(tasks_database); + + enable_raw_mode()?; + stdout().execute(EnterAlternateScreen)?; + let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; + + let mut state = State { + google_api_client, + should_quit: false, + tasklists: Vec::new(), + tasks: Vec::new(), + selected_tasklist: 0, + selected_task: 0, + show_error: None, + is_hidden_shown: false, + create_task: None, + }; + + fetch_tasklists(&mut state); + fetch_tasks(&mut state); + + while !state.should_quit { + update(&mut state)?; + terminal.draw(|frame| { + ui(frame, &state); + })?; + } + + disable_raw_mode()?; + stdout().execute(LeaveAlternateScreen)?; + Ok(()) +} + +fn update(state: &mut State) -> anyhow::Result<()> { + if event::poll(std::time::Duration::from_millis(50))? { + if let Event::Key(key) = event::read()? { + if key.kind == event::KeyEventKind::Press { + if key.code == KeyCode::Char('q') { + state.should_quit = true; + } + let value_ro = state.create_task.clone().unwrap_or("".to_string()); + if let Some(value) = &mut state.create_task { + match key.code { + KeyCode::Backspace => { + value.pop(); + } + KeyCode::Delete => todo!(), + KeyCode::Enter => { + create_task(state, value_ro); + state.create_task = None; + } + KeyCode::Left => todo!(), + KeyCode::Right => todo!(), + KeyCode::Tab => todo!(), + KeyCode::Char(c) => { + value.push(c); + } + KeyCode::Esc => { + state.create_task = None; + } + _ => (), + } + } else { + if key.code == KeyCode::Char('s') { + state.is_hidden_shown = !state.is_hidden_shown; + fetch_tasks(state); + } + + if key.code == KeyCode::Char('c') { + state.create_task = Some("".to_string()); + } + + if key.code == KeyCode::Char('l') { + state.selected_tasklist = + if state.selected_tasklist == state.tasklists.len() - 1 { + 0 + } else { + state.selected_tasklist + 1 + }; + state.selected_task = 0; + state.google_api_client.tasklist = + state.tasklists[state.selected_tasklist].id.clone(); + fetch_tasks(state); + } + + if key.code == KeyCode::Char('h') { + state.selected_tasklist = if state.selected_tasklist == 0 { + state.tasklists.len() - 1 + } else { + state.selected_tasklist - 1 + }; + state.selected_task = 0; + state.google_api_client.tasklist = + state.tasklists[state.selected_tasklist].id.clone(); + fetch_tasks(state); + } + + if key.code == KeyCode::Char('j') { + state.selected_task = if state.selected_task == state.tasks.len() - 1 { + 0 + } else { + state.selected_task + 1 + }; + } + + if key.code == KeyCode::Char('k') { + state.selected_task = if state.selected_task == 0 { + state.tasks.len() - 1 + } else { + state.selected_task - 1 + }; + } + + if key.code == KeyCode::Char(' ') { + toggle_taks_completed(state); + } + } + } + } + } + + Ok(()) +} + +fn fetch_tasklists(state: &mut State) { + let resp = state.google_api_client.fetch_tasklist(false); + match resp { + Ok(data) => state.tasklists = data.items.clone(), + Err(_err) => state.show_error = Some("Can not fetch taskslists".to_string()), + }; +} + +fn fetch_tasks(state: &mut State) { + let resp = state + .google_api_client + .fetch_all_tasks(state.is_hidden_shown); + match resp { + Ok(data) => state.tasks = data.items.clone(), + Err(_err) => state.show_error = Some("Can not fetch tasks".to_string()), + }; +} + +fn toggle_taks_completed(state: &mut State) { + if let Some(task) = state.tasks.get_mut(state.selected_task) { + task.status = if task.status == "completed" { + "needsAction" + } else { + "completed" + } + .to_string(); + + let resp = state.google_api_client.update_task(task.clone()); + match resp { + Ok(data) => *task = data.clone(), + Err(_err) => state.show_error = Some("Can not update tasks".to_string()), + } + } +} + +fn create_task(state: &mut State, title: String) { + let task = Tasks::new(None, title, String::from(""), String::from("needsAction")); + + let resp = state.google_api_client.add_task(task); + match resp { + Ok(data) => state.tasks.push(data), + Err(_err) => state.show_error = Some("Can not fetch tasks".to_string()), + }; +} + +fn ui(frame: &mut Frame, state: &State) { + let main_layout = Layout::new( + Direction::Vertical, + [Constraint::Min(0), Constraint::Length(1)], + ) + .split(frame.size()); + + { + let area = Layout::new( + Direction::Vertical, + [ + Constraint::Length(1), + Constraint::Min(0), + Constraint::Length(8), + ], + ) + .split(main_layout[0]); + + { + let tasklist_titles = state + .tasklists + .iter() + .map(|task_list| format!(" {} ", task_list.title.clone())) + .collect::>(); + + if tasklist_titles.is_empty() { + frame.render_widget(Text::raw("You got no tasklists"), area[0]); + } else { + let tabs = Tabs::new(tasklist_titles) + .style(Style::default().white()) + .highlight_style(Style::default().white().bg(Color::Blue)) + .divider("⣿") + .padding("", "") + .select(state.selected_tasklist); + + frame.render_widget(tabs, area[0]); + } + + if state.tasks.is_empty() { + frame.render_widget( + Paragraph::new("There are no Tasks yet") + .block(Block::new().padding(Padding::uniform(1))), + area[1], + ); + } else { + let items = state.tasks.iter().map(|task| view_task(task.clone())); + + let mut list_state = ListState::default().with_selected(Some(state.selected_task)); + + let list = List::new(items) + .block(Block::default().title("List").borders(Borders::ALL)) + .style(Style::default().fg(Color::White)) + .highlight_style(Style::default().bg(Color::Blue).white()) + .block( + Block::default() + .title("Tasks") + .borders(Borders::ALL) + .border_type(BorderType::Rounded), + ); + frame.render_stateful_widget(list, area[1], &mut list_state); + + if let Some(task) = state.tasks.get(state.selected_task) { + frame.render_widget( + Paragraph::new(task.notes.to_owned()).block( + Block::new() + .title("Notes") + .borders(Borders::ALL) + .border_type(BorderType::Rounded), + ), + area[2], + ); + } else { + frame.render_widget( + Paragraph::new("No task selected".to_string()).block( + Block::new() + .title("Notes") + .borders(Borders::ALL) + .border_type(BorderType::Rounded), + ), + area[2], + ); + } + } + } + + // TODO replace with better string concat + // let actions = possible_actions() + // .iter() + // .filter(|a| { + // let f = &*a.func; + // f(state.clone()).is_some() + // }) + // .map( + // |Action { + // key_code, + // name, + // func: _, + // }| { + // let key = key_code_to_string(key_code); + // format!("{key}: {name}") + // }, + // ) + // .collect::>() + // .join(", "); + + let actions = state + .google_api_client + .tasklist + .clone() + .unwrap_or(String::from("no tasklist")); + + frame.render_widget(Paragraph::new(actions), main_layout[1]); + + if let Some(value) = state.create_task.clone() { + let layout = Layout::new( + Direction::Vertical, + [ + Constraint::Fill(1), + Constraint::Length(3), + Constraint::Fill(1), + ], + ) + .margin(4) + .split(frame.size()); + + frame.render_widget(Clear, layout[1]); + frame.render_widget( + Paragraph::new(Line::from(vec![Span::from(value), " ".slow_blink()])).block( + Block::new() + .title("create task") + .borders(Borders::all()) + .border_type(BorderType::Rounded), + ), + layout[1], + ) + } + } +} + +fn view_task<'a>(task: Tasks) -> ListItem<'a> { + let is_completed = task.status == "completed"; + + let style = Style::default(); + let style = if is_completed { + style.crossed_out() + } else { + style + }; + // let style = if task.deleted { style.dim() } else { style }; // TODO + + ListItem::new(Line::from(vec![ + Span::raw(if is_completed { "" } else { "" }), + Span::raw(" "), + Span::styled(task.title.clone(), style), + ])) + // let mut text = Text::from(line); + // text.extend( + // task.children + // .iter() + // .flat_map(|t| task_to_list_item(t, depth + 1)), + // ); + // text +}