From e4ddc86caf127c299a01e36f57980d6a8b6479f3 Mon Sep 17 00:00:00 2001 From: electria Date: Tue, 25 Aug 2026 19:43:14 -0700 Subject: [PATCH] feat: starting page --- Cargo.lock | 492 ++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 5 +- flake.nix | 2 + src/app/mod.rs | 162 +++++++++++++++- src/db.rs | 26 +++ src/main.rs | 1 + 6 files changed, 674 insertions(+), 14 deletions(-) create mode 100644 src/db.rs diff --git a/Cargo.lock b/Cargo.lock index 0b01319..0e96f9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,23 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.12" @@ -244,6 +261,18 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bit-set" version = "0.8.0" @@ -271,12 +300,46 @@ version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +[[package]] +name = "blake2b_simd" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3560a7b1951efe814fcd721938313adc56753ca39f4b23847d7e9a2402f5dbff" +dependencies = [ + "arrayvec", + "constant_time_eq", +] + [[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block-modes" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2211b0817f061502a8dd9f11a37e879e79763e3c698d2418cf824d8cb2f21e" + +[[package]] +name = "block-padding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -334,6 +397,12 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.12.1" @@ -391,6 +460,15 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cbc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.4.0" @@ -415,6 +493,40 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer", + "crypto-common", + "inout", +] + [[package]] name = "clipboard-win" version = "5.4.1" @@ -454,6 +566,12 @@ dependencies = [ "x11rb", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "codespan-reporting" version = "0.12.0" @@ -484,6 +602,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "core-foundation" version = "0.9.4" @@ -578,6 +708,30 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.22" @@ -603,6 +757,15 @@ dependencies = [ "wgpu", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctor" version = "0.10.1" @@ -612,12 +775,54 @@ dependencies = [ "dtor", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "cursor-icon" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "ctutils", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -631,6 +836,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.13.1", + "block2 0.6.2", + "libc", "objc2 0.6.4", ] @@ -770,6 +977,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foldhash" version = "0.1.5" @@ -961,6 +1178,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -980,8 +1208,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "wasm-bindgen", ] [[package]] @@ -1144,12 +1374,60 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + [[package]] name = "hexf-parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest", +] + +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "iced" version = "0.14.0" @@ -1166,13 +1444,6 @@ dependencies = [ "thiserror 2.0.19", ] -[[package]] -name = "iced-template" -version = "0.1.0" -dependencies = [ - "iced", -] - [[package]] name = "iced_core" version = "0.14.0" @@ -1349,6 +1620,18 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "block-padding", + "hybrid-array", ] [[package]] @@ -1430,6 +1713,50 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keepass" +version = "0.13.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a845a36b656474a0e73e71bfb7dec34250244df364815b77abe1067f17e59e8e" +dependencies = [ + "aes", + "base64 0.23.1", + "block-modes", + "byteorder", + "cbc", + "chacha20", + "chrono", + "cipher", + "flate2", + "getrandom 0.4.3", + "hex", + "hex-literal", + "hmac", + "hybrid-array", + "indexmap", + "js-sys", + "quick-xml", + "rust-argon2", + "salsa20", + "secrecy", + "serde", + "sha2", + "thiserror 2.0.19", + "twofish", + "uuid", + "zeroize", +] + +[[package]] +name = "keepice" +version = "0.1.0" +dependencies = [ + "dirs", + "iced", + "keepass", + "rfd", +] + [[package]] name = "khronos-egl" version = "6.0.0" @@ -1593,6 +1920,16 @@ dependencies = [ "paste", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mundy" version = "0.2.3" @@ -2071,6 +2408,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orbclient" version = "0.3.55" @@ -2219,6 +2562,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "portable-atomic" version = "1.14.0" @@ -2271,6 +2620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", + "serde", ] [[package]] @@ -2361,18 +2711,68 @@ dependencies = [ "bitflags 2.13.1", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.19", +] + [[package]] name = "renderdoc-sys" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +[[package]] +name = "rfd" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20dafead71c16a34e1ff357ddefc8afc11e7d51d6d2b9fbd07eaa48e3e540220" +dependencies = [ + "block2 0.6.2", + "dispatch2", + "js-sys", + "libc", + "log", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "percent-encoding", + "pollster", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "web-sys", + "windows-sys 0.61.2", +] + [[package]] name = "roxmltree" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rust-argon2" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae76b7506744d254fd0eb2c0ff5c5d108201ccbb083111ac04a44eeda105680" +dependencies = [ + "base64 0.22.1", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2426,6 +2826,16 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "salsa20" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f874456e72520ff1375a06c588eaf074b0f01f9e9e1aada45bd9b7954a6e42c" +dependencies = [ + "cfg-if", + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -2460,6 +2870,15 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + [[package]] name = "self_cell" version = "1.3.0" @@ -2513,6 +2932,17 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "2.0.1" @@ -2529,6 +2959,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + [[package]] name = "simd_cesu8" version = "1.2.0" @@ -2944,6 +3380,21 @@ dependencies = [ "core_maths", ] +[[package]] +name = "twofish" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0218ef702a91e18ba84dd516edf8df33a9f9fb4431d6ada13e6f9502c3bcb6fc" +dependencies = [ + "cipher", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + [[package]] name = "uds_windows" version = "1.2.1" @@ -2997,6 +3448,7 @@ version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", @@ -3018,6 +3470,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasip2" version = "1.0.4+wasi-0.2.12" @@ -3913,6 +4371,26 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "zvariant" version = "5.13.1" diff --git a/Cargo.toml b/Cargo.toml index cdc8bd8..3c0551f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [package] -name = "iced-template" +name = "keepice" version = "0.1.0" edition = "2024" license = "AGPL-3.0-or-later" [dependencies] +dirs = "6.0.0" +keepass = "0.13.22" +rfd = "0.17.2" [dependencies.iced] version = "0.14.0" diff --git a/flake.nix b/flake.nix index e136cb7..2aa1a02 100644 --- a/flake.nix +++ b/flake.nix @@ -34,6 +34,8 @@ ++ lib.optionals stdenv.hostPlatform.isLinux [ vulkan-loader wayland + + dbus.lib ]; commonArgs = { diff --git a/src/app/mod.rs b/src/app/mod.rs index db11f02..602fff2 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,25 +1,175 @@ -use iced::{Color, Task, application, theme, widget}; +use std::fs; + +use iced::{ + Color, Length, Subscription, Task, application, event, + keyboard::{self, Key, key}, + theme, widget, +}; +use rfd::{AsyncFileDialog, FileHandle}; + +use crate::db; type Element<'a> = iced::Element<'a, Message, iced::Theme, iced::Renderer>; -enum Message {} +#[derive(Clone)] +enum Message { + ChangeDbPath(String), + PickDb, + PickedDb(Option), -struct State {} + ChangePassword(String), + ChangeSecurity(bool), + OpenDb, + + FocusNext, + FocusPrevious, + + Enter, + Pick, +} + +#[derive(Default)] +struct State { + db_path: String, + db_path_exists: bool, + + db_loaded: bool, + + password: String, + + is_secure: bool, +} impl State { - fn new() -> Self { - Self {} + fn new() -> (Self, Task) { + ( + Self { + is_secure: true, + ..Default::default() + }, + if let Ok(db_path) = db::get_last_opened() + .inspect_err(|e| eprintln!("failed to get last-opened db: {e}")) + { + Task::done(Message::ChangeDbPath(db_path)) + } else { + Task::none() + }, + ) } fn update(&mut self, message: Message) -> Task { + match message { + Message::ChangeDbPath(db_path) => { + self.db_path_exists = fs::exists(&db_path) + .inspect_err(|e| eprintln!("failed to check '{db_path}': {e}")) + .is_ok_and(|exists| exists); + self.db_path = db_path; + } + Message::PickDb => { + return Task::perform( + AsyncFileDialog::new() + .add_filter("kdbx", &["kdbx"]) + .pick_file(), + Message::PickedDb, + ); + } + Message::PickedDb(Some(file)) => { + return Task::done(Message::ChangeDbPath( + file.path().to_string_lossy().to_string(), + )); + } + Message::PickedDb(None) => eprintln!("no path received from picker"), + + Message::ChangePassword(password) => self.password = password, + Message::ChangeSecurity(bool) => self.is_secure = bool, + Message::OpenDb => todo!(), + + Message::FocusNext => return widget::operation::focus_next(), + Message::FocusPrevious => return widget::operation::focus_previous(), + + Message::Enter => { + if !self.db_loaded && self.db_path_exists { + return Task::done(Message::OpenDb); + } + } + Message::Pick => { + if !self.db_loaded { + return Task::done(Message::PickDb); + } + } + } + Task::none() } fn view(&self) -> Element<'_> { - widget::text("hiiiiiii").into() + if !self.db_loaded { + widget::container( + widget::column([ + widget::row([ + widget::text_input("database path", &self.db_path) + .on_input(Message::ChangeDbPath) + .into(), + widget::button("pick file").on_press(Message::PickDb).into(), + ]) + .into(), + widget::row([ + widget::text_input("password", &self.password) + .on_input(Message::ChangePassword) + .secure(self.is_secure) + .into(), + widget::checkbox(self.is_secure) + .label("security") + .on_toggle(Message::ChangeSecurity) + .into(), + ]) + .spacing(10) + .into(), + widget::container(widget::button("open database").on_press_maybe( + if self.db_path_exists { + Some(Message::OpenDb) + } else { + None + }, + )) + .center_x(Length::Fill) + .into(), + ]) + .spacing(20) + .padding(20), + ) + .center(Length::Fill) + .into() + } else { + widget::space().into() + } + } + + fn subscription(&self) -> Subscription { + event::listen().filter_map(|event| match event { + iced::Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) => { + match key.as_ref() { + Key::Named(key::Named::Tab) => Some(if modifiers.shift() { + Message::FocusPrevious + } else { + Message::FocusNext + }), + + Key::Named(key::Named::Enter) => Some(Message::Enter), + Key::Character("p" | "f" | "i") => Some(Message::Pick), + + // ignore unused keys + _ => None, + } + } + + // ignore unused events + _ => None, + }) } } pub fn run() -> Result<(), iced::Error> { application(State::new, State::update, State::view) + .subscription(State::subscription) .theme(theme::Theme::custom( "high-contrast-dark", theme::Palette { diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..982ab74 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,26 @@ +use std::{fs, io}; + +pub fn get_last_opened() -> io::Result { + Ok(fs::read_to_string( + dirs::data_dir() + .ok_or(io::Error::new( + io::ErrorKind::NotFound, + "unable to find data_dir", + ))? + .join("keepice.txt"), + )?) +} + +pub fn set_last_opened(path: impl AsRef) -> io::Result<()> { + fs::write( + dirs::data_dir() + .ok_or(io::Error::new( + io::ErrorKind::NotFound, + "unable to find data_dir", + ))? + .join("keepice.txt"), + path.as_ref(), + )?; + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 2e13470..4b0c8e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod app; +mod db; fn main() -> Result<(), impl std::error::Error> { app::run()