diff options
49 files changed, 2342 insertions, 430 deletions
@@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -90,7 +90,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", ] @@ -105,7 +105,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.8.26", + "zerocopy", ] [[package]] @@ -130,7 +130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.6.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" dependencies = [ "backtrace", ] @@ -314,7 +314,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -354,7 +354,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -365,13 +365,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -382,9 +382,9 @@ checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" [[package]] name = "atomic" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" dependencies = [ "bytemuck", ] @@ -397,15 +397,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -445,9 +445,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "block" @@ -488,9 +488,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "by_address" @@ -500,9 +500,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -515,20 +515,14 @@ checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] name = "bytes" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "calloop" @@ -536,7 +530,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "log", "polling", "rustix 0.38.44", @@ -558,9 +552,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "jobserver", "libc", @@ -575,9 +569,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -593,9 +587,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -603,7 +597,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -761,7 +755,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "core-foundation 0.10.1", "core-graphics-types 0.2.0", "foreign-types", @@ -785,7 +779,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "core-foundation 0.10.1", "libc", ] @@ -796,7 +790,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "fontdb", "log", "rangemap", @@ -890,7 +884,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "libloading 0.8.8", "winapi", ] @@ -913,9 +907,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -923,27 +917,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -954,9 +948,9 @@ checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -979,7 +973,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -989,7 +983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -1024,18 +1018,18 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "diesel" -version = "2.2.4" +version = "2.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" +checksum = "229850a212cd9b84d4f0290ad9d294afc0ae70fccaa8949dbe8b43ffafa1e20c" dependencies = [ "diesel_derives", "libsqlite3-sys", @@ -1045,15 +1039,15 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.2.3" +version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" +checksum = "1b96984c469425cb577bf6f17121ecb3e4fe1e81de5d8f780dd372802858d756" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -1073,7 +1067,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" dependencies = [ - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -1145,7 +1139,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "bytemuck", "drm-ffi", "drm-fourcc", @@ -1180,23 +1174,23 @@ dependencies = [ [[package]] name = "dsl_auto_type" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b" dependencies = [ "darling", "either", "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encoding_rs" @@ -1231,14 +1225,14 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -1247,7 +1241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1304,9 +1298,9 @@ checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" @@ -1323,19 +1317,19 @@ version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" dependencies = [ - "atomic 0.6.0", + "atomic 0.6.1", "pear", "serde", - "toml", + "toml 0.8.23", "uncased", "version_check", ] [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -1397,7 +1391,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -1476,7 +1470,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -1544,13 +1538,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -1590,9 +1584,9 @@ checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "glow" @@ -1621,7 +1615,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "gpu-alloc-types", ] @@ -1631,7 +1625,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -1653,7 +1647,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "gpu-descriptor-types", "hashbrown 0.14.5", ] @@ -1664,7 +1658,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -1679,9 +1673,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1727,9 +1721,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "hassle-rs" @@ -1737,7 +1731,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "com", "libc", "libloading 0.8.8", @@ -1754,18 +1748,6 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" @@ -1795,9 +1777,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -1817,9 +1799,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -1829,9 +1811,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -1844,7 +1826,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -1853,16 +1835,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -1894,7 +1877,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0013a238275494641bf8f1732a23a808196540dc67b22ff97099c044ae4c8a1c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "bytes", "dark-light", "glam", @@ -1941,7 +1924,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba25a18cfa6d5cc160aca7e1b34f73ccdff21680fa8702168c09739767b6c66f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "bytemuck", "cosmic-text", "half", @@ -2003,7 +1986,7 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15708887133671d2bcc6c1d01d1f176f43a64d6cdc3b2bf893396c3ee498295f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "bytemuck", "futures", "glam", @@ -2060,12 +2043,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.4", "serde", ] @@ -2085,14 +2068,25 @@ dependencies = [ ] [[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "libc", +] + +[[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2106,9 +2100,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jni" @@ -2208,7 +2202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.3", ] [[package]] @@ -2219,13 +2213,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0" +checksum = "360e552c93fa0e8152ab463bc4c4837fce76a225df11dfaeea66c313de5e61f7" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.17", ] [[package]] @@ -2241,9 +2235,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" @@ -2259,9 +2253,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2269,9 +2263,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loom" @@ -2314,9 +2308,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -2342,7 +2336,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block", "core-graphics-types 0.1.3", "foreign-types", @@ -2353,12 +2347,12 @@ dependencies = [ [[package]] name = "migrations_internals" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff" +checksum = "3bda1634d70d5bd53553cf15dca9842a396e8c799982a3ad22998dc44d961f24" dependencies = [ "serde", - "toml", + "toml 0.9.2", ] [[package]] @@ -2380,9 +2374,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -2390,14 +2384,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ - "hermit-abi 0.3.9", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -2409,7 +2402,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.1.0", + "http 1.3.1", "httparse", "memchr", "mime", @@ -2426,7 +2419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" dependencies = [ "bit-set", - "bitflags 2.6.0", + "bitflags 2.9.1", "codespan-reporting", "hexf-parse", "indexmap", @@ -2445,7 +2438,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.6.0+11769913", @@ -2484,7 +2477,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -2518,11 +2511,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -2545,7 +2538,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -2580,7 +2573,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "libc", "objc2", @@ -2596,7 +2589,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-core-location", @@ -2620,7 +2613,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2662,7 +2655,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "dispatch", "libc", @@ -2687,7 +2680,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2699,7 +2692,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2722,7 +2715,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-cloud-kit", @@ -2754,7 +2747,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-core-location", @@ -2772,18 +2765,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "orbclient" @@ -2850,7 +2843,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -2872,12 +2865,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.11", ] [[package]] @@ -2896,13 +2889,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.17", "smallvec", "windows-targets 0.52.6", ] @@ -2933,7 +2926,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -2972,7 +2965,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -3001,14 +2994,14 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3029,9 +3022,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "png" @@ -3054,7 +3047,7 @@ checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.5.2", + "hermit-abi", "pin-project-lite", "rustix 1.0.8", "windows-sys 0.60.2", @@ -3068,11 +3061,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -3092,9 +3085,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -3107,7 +3100,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", "version_check", "yansi", ] @@ -3129,9 +3122,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -3149,7 +3142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "scheduled-thread-pool", ] @@ -3180,7 +3173,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -3251,11 +3244,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -3264,29 +3257,29 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror", ] [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -3358,7 +3351,7 @@ dependencies = [ "memchr", "multer", "num_cpus", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "pin-project-lite", "rand", "ref-cast", @@ -3389,7 +3382,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.87", + "syn 2.0.104", "unicode-xid", "version_check", ] @@ -3464,9 +3457,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -3486,10 +3479,10 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] @@ -3499,18 +3492,18 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rustybuzz" @@ -3518,7 +3511,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "bytemuck", "libm", "smallvec", @@ -3531,9 +3524,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -3550,7 +3543,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot 0.12.3", + "parking_lot 0.12.4", ] [[package]] @@ -3571,9 +3564,13 @@ dependencies = [ [[package]] name = "schist_desktop_gui" -version = "0.0.0" +version = "0.1.0" dependencies = [ + "anyhow", "iced", + "itertools", + "schist_fakes", + "schist_models", ] [[package]] @@ -3658,29 +3655,29 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", @@ -3696,7 +3693,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -3709,6 +3706,15 @@ dependencies = [ ] [[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + +[[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3736,9 +3742,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -3767,12 +3773,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "slotmap" @@ -3785,9 +3788,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -3795,7 +3798,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -3836,15 +3839,25 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] name = "softbuffer" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3864,7 +3877,7 @@ dependencies = [ "objc2-foundation", "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.7", + "redox_syscall 0.5.17", "rustix 0.38.44", "tiny-xlib", "wasm-bindgen", @@ -3888,7 +3901,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -3957,9 +3970,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -3977,14 +3990,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.3", "once_cell", - "rustix 0.38.44", + "rustix 1.0.8", "windows-sys 0.59.0", ] @@ -4014,24 +4027,23 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -4044,15 +4056,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -4114,37 +4126,39 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -4153,9 +4167,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -4166,17 +4180,32 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] [[package]] +name = "toml" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4186,6 +4215,15 @@ dependencies = [ ] [[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + +[[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4193,19 +4231,34 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", "winnow", ] [[package]] +name = "toml_parser" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +dependencies = [ + "winnow", +] + +[[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + +[[package]] name = "tower-service" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4213,9 +4266,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -4224,20 +4277,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -4256,9 +4309,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -4352,9 +4405,9 @@ checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-linebreak" @@ -4394,9 +4447,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -4431,9 +4484,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -4466,7 +4519,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -4501,7 +4554,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4550,7 +4603,7 @@ version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "rustix 0.38.44", "wayland-backend", "wayland-scanner", @@ -4562,7 +4615,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] @@ -4584,7 +4637,7 @@ version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -4596,7 +4649,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4609,7 +4662,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4671,7 +4724,7 @@ dependencies = [ "js-sys", "log", "naga", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "profiling", "raw-window-handle", "smallvec", @@ -4692,14 +4745,14 @@ checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.9.1", "cfg_aliases 0.1.1", "codespan-reporting", "indexmap", "log", "naga", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "profiling", "raw-window-handle", "rustc-hash 1.1.0", @@ -4720,7 +4773,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.6.0", + "bitflags 2.9.1", "block", "cfg_aliases 0.1.1", "core-graphics-types 0.1.3", @@ -4741,7 +4794,7 @@ dependencies = [ "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", - "parking_lot 0.12.3", + "parking_lot 0.12.4", "profiling", "range-alloc", "raw-window-handle", @@ -4761,7 +4814,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "js-sys", "web-sys", ] @@ -4832,7 +4885,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", "windows-targets 0.52.6", ] @@ -4846,6 +4899,65 @@ dependencies = [ ] [[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4878,7 +4990,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -4929,10 +5041,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -5132,7 +5245,7 @@ dependencies = [ "ahash 0.8.12", "android-activity", "atomic-waker", - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "bytemuck", "calloop", @@ -5199,7 +5312,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -5256,7 +5369,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -5337,7 +5450,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", "zvariant_utils", ] @@ -5360,32 +5473,11 @@ checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" [[package]] name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "zerocopy-derive 0.8.26", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", + "zerocopy-derive", ] [[package]] @@ -5396,7 +5488,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] [[package]] @@ -5421,7 +5513,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", "zvariant_utils", ] @@ -5433,5 +5525,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.104", ] @@ -1,17 +1,17 @@ [workspace] members = [ - "schist_backend", - "schist_core/schist_fakes", - "schist_core/schist_models", - "schist_core/schist_queries", - "schist_core/schist_schema", - "schist_core/schist_traits", - "schist_desktop_gui", - "transformers/actualbudget_transformer/actualbudget_fakes", - "transformers/actualbudget_transformer/actualbudget_models", - "transformers/actualbudget_transformer/actualbudget_queries", - "transformers/actualbudget_transformer/actualbudget_schema", - "transformers/actualbudget_transformer/actualbudget_to_schist_transformer", + "schist_backend", + "schist_core/schist_fakes", + "schist_core/schist_models", + "schist_core/schist_queries", + "schist_core/schist_schema", + "schist_core/schist_traits", + "schist_desktop_gui", + "transformers/actualbudget_transformer/actualbudget_fakes", + "transformers/actualbudget_transformer/actualbudget_models", + "transformers/actualbudget_transformer/actualbudget_queries", + "transformers/actualbudget_transformer/actualbudget_schema", + "transformers/actualbudget_transformer/actualbudget_to_schist_transformer", ] resolver = "2" @@ -25,7 +25,7 @@ diesel_migrations = "2.2.0" dotenvy = "0.15.7" iced = "0.13.1" itertools = "0.13.0" -libsqlite3-sys = { version = "0.30.1" } +libsqlite3-sys = { version = "0.30.1", features = ["bundled"] } rocket = { version = "0.5.1" } rocket_sync_db_pools = { version = "0.1.0" } schist_fakes = { path = "schist_core/schist_fakes" } diff --git a/requirements/kanban.md b/requirements/kanban.md index ace6e96..4f0ebde 100644 --- a/requirements/kanban.md +++ b/requirements/kanban.md @@ -4,7 +4,6 @@ | -------- | -------- | -------- | | | | epic-000 | | ======== | ======== | ======== | -| | | task-073 | | | task-012 | | | | task-001 | | | | task-064 | | diff --git a/requirements/tasks/epic-000.md b/requirements/tasks/epic-000.md index ae10a92..7b6e21c 100644 --- a/requirements/tasks/epic-000.md +++ b/requirements/tasks/epic-000.md @@ -8,7 +8,7 @@ Status: not ready ## Ordered backlog - [x] task-010 (hello, world) -- [ ] task-073 (UI layout & nav) +- [x] task-073 (UI layout & nav) - [ ] task-012 (SQLite) - [ ] task-001 (inserting transactions) - [ ] task-064 (deleting transactions) diff --git a/schist_backend/src/main.rs b/schist_backend/src/main.rs index 8395681..83da9b6 100644 --- a/schist_backend/src/main.rs +++ b/schist_backend/src/main.rs @@ -1,9 +1,9 @@ -use schist_schema::migrations::MIGRATIONS; use diesel::SqliteConnection; use diesel_migrations::MigrationHarness; use rocket::fairing::AdHoc; use rocket::http::ContentType; use rocket::{launch, routes, Build, Rocket}; +use schist_schema::migrations::MIGRATIONS; use crate::databases::UserDataDb; diff --git a/schist_core/schist_fakes/src/bucket.rs b/schist_core/schist_fakes/src/bucket.rs new file mode 100644 index 0000000..1b447b2 --- /dev/null +++ b/schist_core/schist_fakes/src/bucket.rs @@ -0,0 +1,24 @@ +use schist_models::{ + bucket::{Bucket, BucketBuilder}, + budget_period_unit::BudgetPeriodUnit, + date_utc::DateUtc, +}; +use schist_traits::nowlike::Nowlike; + +pub fn make_fake_bucket(id: i32) -> Bucket { + make_fake_bucket_builder(id).build().unwrap() +} + +pub fn make_fake_bucket_builder(id: i32) -> BucketBuilder { + let mut builder = BucketBuilder::default(); + builder + .id(id) + .name(String::from("Fake bucket")) + .balance(0) + .balance_date(DateUtc::now()) + .budget_period(0) + .budget_period_unit(BudgetPeriodUnit::Day) + .budget_quantity(0) + .group(String::from("Fake group")); + builder +} diff --git a/schist_core/schist_fakes/src/category.rs b/schist_core/schist_fakes/src/category.rs deleted file mode 100644 index c64818d..0000000 --- a/schist_core/schist_fakes/src/category.rs +++ /dev/null @@ -1,19 +0,0 @@ -use schist_models::{budget_period_unit::BudgetPeriodUnit, category::{Category, CategoryBuilder}, date_utc::DateUtc}; -use schist_traits::nowlike::Nowlike; - -pub fn make_fake_category(id: i32) -> Category { - make_fake_category_builder(id).build().unwrap() -} - -pub fn make_fake_category_builder(id: i32) -> CategoryBuilder { - let mut builder = CategoryBuilder::default(); - builder - .id(id) - .name(String::from("Fake category")) - .balance(0) - .balance_date(DateUtc::now()) - .budget_period(0) - .budget_period_unit(BudgetPeriodUnit::Day) - .budget_quantity(0); - builder -} diff --git a/schist_core/schist_fakes/src/category_transfer.rs b/schist_core/schist_fakes/src/category_transfer.rs index c28dffb..a16d238 100644 --- a/schist_core/schist_fakes/src/category_transfer.rs +++ b/schist_core/schist_fakes/src/category_transfer.rs @@ -1,11 +1,11 @@ -use schist_models::category_transfer::{CategoryTransfer, CategoryTransferBuilder}; +use schist_models::bucket_transfer::{BucketTransfer, BucketTransferBuilder}; -pub fn make_fake_category_transfer(id: i32) -> CategoryTransfer { +pub fn make_fake_category_transfer(id: i32) -> BucketTransfer { make_fake_category_transfer_builder(id).build().unwrap() } -pub fn make_fake_category_transfer_builder(id: i32) -> CategoryTransferBuilder { - let mut builder = CategoryTransferBuilder::default(); +pub fn make_fake_category_transfer_builder(id: i32) -> BucketTransferBuilder { + let mut builder = BucketTransferBuilder::default(); builder .id(id) .description(String::from("Fake category transfer")) diff --git a/schist_core/schist_fakes/src/lib.rs b/schist_core/schist_fakes/src/lib.rs index 6e20c31..4a22169 100644 --- a/schist_core/schist_fakes/src/lib.rs +++ b/schist_core/schist_fakes/src/lib.rs @@ -1,7 +1,7 @@ pub mod account; pub mod account_transfer; +pub mod bucket; pub mod budget_drip; -pub mod category; pub mod category_transfer; pub mod transaction; pub mod transaction_categorisation; diff --git a/schist_core/schist_models/src/category.rs b/schist_core/schist_models/src/bucket.rs index e3c9938..f162405 100644 --- a/schist_core/schist_models/src/category.rs +++ b/schist_core/schist_models/src/bucket.rs @@ -4,9 +4,20 @@ use serde::{Deserialize, Serialize}; use crate::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc}; -#[derive(Builder, Clone, Queryable, Identifiable, Selectable, Debug, PartialEq, Serialize, Deserialize, Insertable)] +#[derive( + Builder, + Clone, + Queryable, + Identifiable, + Selectable, + Debug, + PartialEq, + Serialize, + Deserialize, + Insertable, +)] #[diesel(table_name = crate::schema::categories)] -pub struct Category { +pub struct Bucket { pub id: i32, pub name: String, pub balance: i32, @@ -14,4 +25,5 @@ pub struct Category { pub budget_period: i32, pub budget_period_unit: BudgetPeriodUnit, pub budget_quantity: i32, + pub group: String, } diff --git a/schist_core/schist_models/src/category_transfer.rs b/schist_core/schist_models/src/bucket_transfer.rs index 7b36054..5d2e268 100644 --- a/schist_core/schist_models/src/category_transfer.rs +++ b/schist_core/schist_models/src/bucket_transfer.rs @@ -3,7 +3,7 @@ use diesel::prelude::*; #[derive(Builder, Queryable, Identifiable, Selectable, Debug, PartialEq, Insertable)] #[diesel(table_name = crate::schema::category_transfers)] -pub struct CategoryTransfer { +pub struct BucketTransfer { pub id: i32, pub description: String, pub quantity: i32, diff --git a/schist_core/schist_models/src/lib.rs b/schist_core/schist_models/src/lib.rs index d9e93c4..db5c593 100644 --- a/schist_core/schist_models/src/lib.rs +++ b/schist_core/schist_models/src/lib.rs @@ -1,12 +1,12 @@ pub mod account; pub mod account_transfer; +pub mod bucket; +pub mod bucket_transfer; pub mod budget_drip; pub mod budget_period_unit; -pub mod category; -pub mod category_transfer; pub mod date_utc; pub mod datetime_utc; pub mod migrations; +pub mod schema; pub mod transaction; pub mod transaction_categorisation; -pub mod schema; diff --git a/schist_core/schist_models/src/schema.rs b/schist_core/schist_models/src/schema.rs index 1dd1391..40af56f 100644 --- a/schist_core/schist_models/src/schema.rs +++ b/schist_core/schist_models/src/schema.rs @@ -38,6 +38,7 @@ diesel::table! { budget_period -> Integer, budget_period_unit -> Text, budget_quantity -> Integer, + group -> Text, } } diff --git a/schist_desktop_gui/Cargo.toml b/schist_desktop_gui/Cargo.toml index 75072e7..b7b80da 100644 --- a/schist_desktop_gui/Cargo.toml +++ b/schist_desktop_gui/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "schist_desktop_gui" +version = "0.1.0" edition = "2021" [dependencies] +anyhow = { workspace = true } iced = { workspace = true } +itertools = { workspace = true } +schist_fakes = { workspace = true } +schist_models = { workspace = true } diff --git a/schist_desktop_gui/src/config.rs b/schist_desktop_gui/src/config.rs index cab9eba..d45c460 100644 --- a/schist_desktop_gui/src/config.rs +++ b/schist_desktop_gui/src/config.rs @@ -1,8 +1,17 @@ +mod keys; + +use crate::config::keys::Keyboard; + #[derive(Clone)] -pub struct Config {} +pub struct Config { + pub keyboard: Keyboard, +} impl Default for Config { - fn default() -> Self { - Self {} - } + fn default() -> Self { + let keyboard = Keyboard::default(); + Self { + keyboard: keyboard, + } + } } diff --git a/schist_desktop_gui/src/config/keys.rs b/schist_desktop_gui/src/config/keys.rs new file mode 100644 index 0000000..ff28757 --- /dev/null +++ b/schist_desktop_gui/src/config/keys.rs @@ -0,0 +1,45 @@ +// Borrowed from https://github.com/squidowl/halloy/tree/main/data/src/config/keys.rs + +use crate::{ + gui::screens::main_screen::View, + shortcut::{shortcut, Command, KeyBind, Shortcut}, +}; + +#[derive(Debug, Clone)] +pub struct Keyboard { + pub goto_next_item: KeyBind, + pub goto_prev_item: KeyBind, + pub goto_next_view: KeyBind, + pub goto_prev_view: KeyBind, + pub goto_view_1: KeyBind, + pub goto_view_2: KeyBind, + pub goto_view_3: KeyBind, +} + +impl Default for Keyboard { + fn default() -> Self { + Self { + goto_next_item: KeyBind::goto_next_item(), + goto_prev_item: KeyBind::goto_prev_item(), + goto_next_view: KeyBind::goto_next_view(), + goto_prev_view: KeyBind::goto_prev_view(), + goto_view_1: KeyBind::goto_view_1(), + goto_view_2: KeyBind::goto_view_2(), + goto_view_3: KeyBind::goto_view_3(), + } + } +} + +impl Keyboard { + pub fn shortcuts(&self) -> Vec<Shortcut> { + vec![ + shortcut(self.goto_next_item.clone(), Command::GotoNextItem), + shortcut(self.goto_prev_item.clone(), Command::GotoPrevItem), + shortcut(self.goto_next_view.clone(), Command::GotoNextView), + shortcut(self.goto_prev_view.clone(), Command::GotoPrevView), + shortcut(self.goto_view_1.clone(), Command::GotoView(View::VIEW_1)), + shortcut(self.goto_view_2.clone(), Command::GotoView(View::VIEW_2)), + shortcut(self.goto_view_3.clone(), Command::GotoView(View::VIEW_3)), + ] + } +} diff --git a/schist_desktop_gui/src/dummy_data.rs b/schist_desktop_gui/src/dummy_data.rs new file mode 100644 index 0000000..079b687 --- /dev/null +++ b/schist_desktop_gui/src/dummy_data.rs @@ -0,0 +1,70 @@ +use schist_models::{ + account::Account, bucket::Bucket, budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc, +}; + +#[derive(Clone, Debug)] +pub struct Error {} + +impl From<anyhow::Error> for Error { + fn from(_value: anyhow::Error) -> Self { + Error {} + } +} + +pub async fn fetch_accounts() -> Result<Vec<Account>, Error> { + Ok(vec![ + Account { + id: 0, + name: String::from("Nationwide current account"), + opening_balance: 0, + opening_date: DateUtc::from_ymd(2024, 06, 12)?, + }, + Account { + id: 1, + name: String::from("cash account"), + opening_balance: 0, + opening_date: DateUtc::from_ymd(2024, 06, 12)?, + }, + Account { + id: 2, + name: String::from("YBS savings account"), + opening_balance: 0, + opening_date: DateUtc::from_ymd(2024, 06, 12)?, + }, + ]) +} + +pub async fn fetch_buckets() -> Result<Vec<Bucket>, Error> { + Ok(vec![ + Bucket { + id: 0, + name: String::from("groceries"), + balance: 123, + balance_date: DateUtc::from_ymd(2025, 8, 10)?, + budget_period: 1, + budget_period_unit: BudgetPeriodUnit::Month, + budget_quantity: 300, + group: String::from("normal expenses"), + }, + Bucket { + id: 1, + name: String::from("outdoor trips"), + balance: -11, + balance_date: DateUtc::from_ymd(2025, 8, 10)?, + budget_period: 1, + budget_period_unit: BudgetPeriodUnit::Month, + budget_quantity: 110, + group: String::from("outdoors"), + }, + Bucket { + id: 2, + name: String::from("salary"), + balance: 1018, + balance_date: DateUtc::from_ymd(2025, 8, 10)?, + budget_period: 1, + budget_period_unit: BudgetPeriodUnit::Month, + budget_quantity: -2196, + group: String::from("income"), + }, + ]) +} diff --git a/schist_desktop_gui/src/gui.rs b/schist_desktop_gui/src/gui.rs new file mode 100644 index 0000000..0f84f41 --- /dev/null +++ b/schist_desktop_gui/src/gui.rs @@ -0,0 +1,132 @@ +pub mod components; +pub mod screens; + +use iced::Element; +use schist_models::{account::Account, bucket::Bucket}; + +use crate::{ + config::Config, + dummy_data::{self, fetch_accounts, fetch_buckets}, + gui::screens::{main_screen, MainScreen, Screen}, + shortcut::KeyBind, + traits::{Component, Viewable}, +}; + +#[derive(Clone, Debug)] +pub enum Message { + Event(iced::Event), + MainScreenMessage(main_screen::Message), + RefetchedAccounts(Result<Vec<Account>, dummy_data::Error>), + RefetchedBuckets(Result<Vec<Bucket>, dummy_data::Error>), +} + +pub struct Gui { + active_screen: Screen, + buckets: Vec<Bucket>, + main_screen: MainScreen, + config: Config, +} + +impl Gui { + pub fn new() -> (Self, iced::Task<Message>) { + let tasks = vec![ + iced::Task::perform(fetch_buckets(), Message::RefetchedBuckets), + iced::Task::perform(fetch_accounts(), Message::RefetchedAccounts), + ]; + let buckets = Vec::new(); + let accounts = Vec::new(); + let gui = Self { + active_screen: Screen::Main, + buckets: buckets.clone(), + main_screen: MainScreen::new(buckets, accounts), + config: Config::default(), + }; + (gui, iced::Task::batch(tasks)) + } +} + +impl Gui { + pub fn view(&self) -> Element<Message> { + match self.active_screen { + Screen::Main => self.main_screen.view().map(Message::MainScreenMessage), + } + } + + pub fn update(&mut self, message: Message) -> iced::Task<Message> { + match message { + Message::Event(iced::Event::Keyboard(iced::keyboard::Event::KeyPressed { + key, + modifiers, + .. + })) => { + let key_bind = KeyBind::from((key.clone(), modifiers)); + if let Some(command) = self + .config + .keyboard + .shortcuts() + .iter() + .find_map(|shortcut| shortcut.execute(&key_bind)) + { + match command { + crate::shortcut::Command::GotoNextView => { + self.main_screen.update(main_screen::Message::SelectView( + self.main_screen.active_view.next(), + )); + iced::Task::none() + } + crate::shortcut::Command::GotoPrevView => { + self.main_screen.update(main_screen::Message::SelectView( + self.main_screen.active_view.prev(), + )); + iced::Task::none() + } + crate::shortcut::Command::GotoView(view) => { + self.main_screen + .update(main_screen::Message::SelectView(view)); + iced::Task::none() + } + crate::shortcut::Command::GotoNextItem => { + self.main_screen.update(main_screen::Message::NextItem); + iced::Task::none() + } + crate::shortcut::Command::GotoPrevItem => { + self.main_screen.update(main_screen::Message::PrevItem); + iced::Task::none() + } + } + } else { + iced::Task::none() + } + } + Message::Event(_) => iced::Task::none(), + Message::MainScreenMessage(message) => match self.main_screen.update(message) { + main_screen::Action::None => iced::Task::none(), + }, + Message::RefetchedBuckets(buckets) => { + match buckets { + Ok(buckets) => { + self.buckets = buckets.clone(); + self.main_screen + .update(main_screen::Message::SetBuckets(buckets)); + } + Err(err) => println!("Failed to get buckets: {:?}", err), + }; + iced::Task::none() + } + Message::RefetchedAccounts(accounts) => { + match accounts { + Ok(accounts) => { + self.main_screen + .update(main_screen::Message::SetAccounts(accounts)); + } + Err(err) => println!("Failed to get accounts: {:?}", err), + } + iced::Task::none() + } + } + } +} + +pub fn subscription(_state: &Gui) -> iced::Subscription<Message> { + iced::event::listen().map(Message::Event) +} diff --git a/schist_desktop_gui/src/gui/components.rs b/schist_desktop_gui/src/gui/components.rs new file mode 100644 index 0000000..fc3c838 --- /dev/null +++ b/schist_desktop_gui/src/gui/components.rs @@ -0,0 +1,15 @@ +pub mod balances_view; +pub mod bucket_name_and_balance; +pub mod buckets_view; +pub mod button; +pub mod navigation; +pub mod text; +pub mod transactions_view; + +pub use balances_view::BalancesView; +pub use bucket_name_and_balance::BucketNameAndBalance; +pub use buckets_view::BucketsView; +pub use button::{active_button, inactive_button}; +pub use navigation::Navigation; +pub use text::Text; +pub use transactions_view::TransactionsView; diff --git a/schist_desktop_gui/src/gui/components/balances_view.rs b/schist_desktop_gui/src/gui/components/balances_view.rs new file mode 100644 index 0000000..2b72cd3 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/balances_view.rs @@ -0,0 +1,63 @@ +mod make_balances_view_greeting; +mod update_balances_view; +mod view_balances_view; +mod view_group_names; + +use self::{ + update_balances_view::update_balances_view, view_balances_view::view_balances_view, + view_group_names::view_group_names, +}; + +use schist_models::bucket::Bucket; + +use crate::{ + gui::components::{ + balances_view::make_balances_view_greeting::make_balances_view_greeting, navigation, + Navigation, Text, + }, + traits::{Component, Viewable}, +}; + +#[derive(Clone, Debug)] +pub struct BalancesView { + buckets: Vec<Bucket>, + greeting: String, + navigation: Navigation<Text>, +} + +#[derive(Clone, Debug)] +pub enum Message { + NavigationMessage(navigation::Message<Text>), + SelectNextBucket, + SelectPrevBucket, + SetBuckets(Vec<Bucket>), +} + +pub enum Action { + None, +} + +impl BalancesView { + pub fn new(buckets: Vec<Bucket>) -> Self { + let groups = view_group_names(buckets.clone()); + let active_group = groups.clone().first().cloned(); + let navigation = Navigation::new(active_group.clone(), groups); + Self { + buckets: buckets.clone(), + greeting: make_balances_view_greeting(active_group), + navigation: navigation, + } + } +} + +impl<'a> Viewable<'a, Message> for BalancesView { + fn view(&'a self) -> iced::Element<'a, Message> { + view_balances_view(self) + } +} + +impl<'a> Component<'a, Message, Action> for BalancesView { + fn update(&mut self, message: Message) -> Action { + update_balances_view(self, message) + } +} diff --git a/schist_desktop_gui/src/gui/components/balances_view/make_balances_view_greeting.rs b/schist_desktop_gui/src/gui/components/balances_view/make_balances_view_greeting.rs new file mode 100644 index 0000000..4926046 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/balances_view/make_balances_view_greeting.rs @@ -0,0 +1,9 @@ +use crate::gui::components::text::Text; + +pub fn make_balances_view_greeting(group_name: Option<Text>) -> String { + if let Some(group_name) = group_name { + format!("Hello, {} balances!", group_name.content) + } else { + String::from("Hello, balances!") + } +} diff --git a/schist_desktop_gui/src/gui/components/balances_view/update_balances_view.rs b/schist_desktop_gui/src/gui/components/balances_view/update_balances_view.rs new file mode 100644 index 0000000..100cbc9 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/balances_view/update_balances_view.rs @@ -0,0 +1,121 @@ +use super::{ + make_balances_view_greeting::make_balances_view_greeting, view_group_names::view_group_names, + Action, BalancesView, Message, +}; +use crate::{ + gui::components::{navigation, Text}, + traits::Component, +}; + +pub fn update_balances_view(balances_view: &mut BalancesView, message: Message) -> Action { + match message { + Message::NavigationMessage(message) => update_navigation(balances_view, message), + Message::SetBuckets(buckets) => set_buckets(balances_view, buckets), + Message::SelectNextBucket => select_next_bucket(balances_view), + Message::SelectPrevBucket => select_prev_bucket(balances_view), + } +} + +fn select_prev_bucket(balances_view: &mut BalancesView) -> Action { + match balances_view + .navigation + .update(navigation::Message::SelectPrev) + { + navigation::Action::SelectOption(option) => { + balances_view.greeting = make_balances_view_greeting(Some(option)); + Action::None + } + navigation::Action::None => Action::None, + } +} + +fn select_next_bucket(balances_view: &mut BalancesView) -> Action { + match balances_view + .navigation + .update(navigation::Message::SelectNext) + { + navigation::Action::SelectOption(option) => { + balances_view.greeting = make_balances_view_greeting(Some(option)); + Action::None + } + navigation::Action::None => Action::None, + } +} + +fn set_buckets( + balances_view: &mut BalancesView, + buckets: Vec<schist_models::bucket::Bucket>, +) -> Action { + balances_view.buckets = buckets.clone(); + match balances_view + .navigation + .update(navigation::Message::SetOptions(view_group_names(buckets))) + { + navigation::Action::SelectOption(option) => { + balances_view.greeting = make_balances_view_greeting(Some(option)); + Action::None + } + navigation::Action::None => Action::None, + } +} + +fn update_navigation( + balances_view: &mut BalancesView, + message: navigation::Message<Text>, +) -> Action { + match balances_view.navigation.update(message) { + navigation::Action::SelectOption(group_name) => { + balances_view.greeting = make_balances_view_greeting(Some(group_name)); + Action::None + } + navigation::Action::None => Action::None, + } +} + +#[cfg(test)] +mod test { + use schist_fakes::bucket::make_fake_bucket_builder; + + use crate::{ + gui::components::{ + balances_view::{BalancesView, Message}, + navigation, + }, + traits::Component, + }; + + #[test] + fn update_navigation_updates_greeting() { + let groceries = make_fake_bucket_builder(0) + .group(String::from("normal expenses")) + .build() + .unwrap(); + let fragrance = make_fake_bucket_builder(1) + .group(String::from("luxuries")) + .build() + .unwrap(); + let maps = make_fake_bucket_builder(2) + .group(String::from("outdoors")) + .build() + .unwrap(); + let buckets = vec![groceries, fragrance.clone(), maps]; + + let mut balances_view = BalancesView::new(buckets); + assert_eq!("Hello, normal expenses balances!", balances_view.greeting); + + balances_view.update(Message::NavigationMessage(navigation::Message::SelectPrev)); + assert_eq!("Hello, normal expenses balances!", balances_view.greeting); + + balances_view.update(Message::NavigationMessage(navigation::Message::SelectPrev)); + assert_eq!("Hello, normal expenses balances!", balances_view.greeting); + + balances_view.update(Message::NavigationMessage(navigation::Message::SelectNext)); + assert_eq!("Hello, luxuries balances!", balances_view.greeting); + + balances_view.update(Message::NavigationMessage(navigation::Message::SelectNext)); + assert_eq!("Hello, outdoors balances!", balances_view.greeting); + + balances_view.update(Message::NavigationMessage(navigation::Message::SelectNext)); + assert_eq!("Hello, outdoors balances!", balances_view.greeting); + } +} diff --git a/schist_desktop_gui/src/gui/components/balances_view/view_balances_view.rs b/schist_desktop_gui/src/gui/components/balances_view/view_balances_view.rs new file mode 100644 index 0000000..e8a1e46 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/balances_view/view_balances_view.rs @@ -0,0 +1,22 @@ +use iced::widget::{column, row, Container}; +use iced::{alignment, Element, Length}; + +use crate::gui::components::{balances_view::Message, BalancesView}; +use crate::style::SPACING_LG; +use crate::traits::Viewable; + +pub fn view_balances_view<'a>(balances_view: &'a BalancesView) -> Element<'a, Message> { + let navigation = balances_view + .navigation + .view() + .map(Message::NavigationMessage); + let main_content = column![iced::widget::text(balances_view.greeting.clone())]; + row![ + Container::new(navigation).width(Length::FillPortion(1)), + Container::new(main_content).width(Length::FillPortion(3)), + ] + .align_y(alignment::Vertical::Center) + .height(Length::Fill) + .spacing(SPACING_LG) + .into() +} diff --git a/schist_desktop_gui/src/gui/components/balances_view/view_group_names.rs b/schist_desktop_gui/src/gui/components/balances_view/view_group_names.rs new file mode 100644 index 0000000..02900e9 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/balances_view/view_group_names.rs @@ -0,0 +1,143 @@ +use itertools::Itertools; +use schist_models::bucket::Bucket; + +use crate::gui::components::Text; + +pub fn view_group_names(buckets: Vec<Bucket>) -> Vec<Text> { + buckets + .iter() + .map(|b| b.group.clone()) + .unique() + .map(Text::new) + .collect() +} + +#[cfg(test)] +mod test { + use schist_fakes::bucket::make_fake_bucket_builder; + + use crate::gui::components::{balances_view::view_group_names::view_group_names, text::Text}; + + #[test] + fn preserves_order() { + let buckets = vec![ + make_fake_bucket_builder(0) + .group(String::from("hydrogen")) + .build() + .unwrap(), + make_fake_bucket_builder(1) + .group(String::from("helium")) + .build() + .unwrap(), + make_fake_bucket_builder(2) + .group(String::from("lithium")) + .build() + .unwrap(), + make_fake_bucket_builder(3) + .group(String::from("beryllium")) + .build() + .unwrap(), + make_fake_bucket_builder(4) + .group(String::from("boron")) + .build() + .unwrap(), + make_fake_bucket_builder(5) + .group(String::from("carbon")) + .build() + .unwrap(), + make_fake_bucket_builder(6) + .group(String::from("nitrogen")) + .build() + .unwrap(), + make_fake_bucket_builder(7) + .group(String::from("oxygen")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("flourine")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("flourine")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("neon")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("magnesium")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("aluminium")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("silicon")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("phosphorus")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("sulphur")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("chlorine")) + .build() + .unwrap(), + make_fake_bucket_builder(8) + .group(String::from("argon")) + .build() + .unwrap(), + ]; + let group_names = view_group_names(buckets); + assert_eq!(17, group_names.len()); + assert_eq!(group_names[0], Text::new(String::from("hydrogen"))); + assert_eq!(group_names[1], Text::new(String::from("helium"))); + assert_eq!(group_names[2], Text::new(String::from("lithium"))); + assert_eq!(group_names[3], Text::new(String::from("beryllium"))); + assert_eq!(group_names[4], Text::new(String::from("boron"))); + assert_eq!(group_names[5], Text::new(String::from("carbon"))); + assert_eq!(group_names[6], Text::new(String::from("nitrogen"))); + assert_eq!(group_names[7], Text::new(String::from("oxygen"))); + assert_eq!(group_names[8], Text::new(String::from("flourine"))); + assert_eq!(group_names[9], Text::new(String::from("neon"))); + assert_eq!(group_names[10], Text::new(String::from("magnesium"))); + assert_eq!(group_names[11], Text::new(String::from("aluminium"))); + assert_eq!(group_names[12], Text::new(String::from("silicon"))); + assert_eq!(group_names[13], Text::new(String::from("phosphorus"))); + assert_eq!(group_names[14], Text::new(String::from("sulphur"))); + assert_eq!(group_names[15], Text::new(String::from("chlorine"))); + assert_eq!(group_names[16], Text::new(String::from("argon"))); + } + + #[test] + fn removes_duplicates() { + let buckets = vec![ + make_fake_bucket_builder(0) + .group(String::from("hydrogen")) + .build() + .unwrap(), + make_fake_bucket_builder(1) + .group(String::from("helium")) + .build() + .unwrap(), + make_fake_bucket_builder(2) + .group(String::from("hydrogen")) + .build() + .unwrap(), + ]; + let group_names = view_group_names(buckets); + assert_eq!( + vec![ + Text::new(String::from("hydrogen")), + Text::new(String::from("helium")), + ], + group_names + ); + } +} diff --git a/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs b/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs new file mode 100644 index 0000000..fa2dcac --- /dev/null +++ b/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs @@ -0,0 +1,24 @@ +use iced::{ + widget::{row, text}, + Element, +}; +use schist_models::bucket::Bucket; + +use crate::gui::components::navigation; + +#[derive(Clone, Debug, PartialEq)] +pub struct BucketNameAndBalance { + pub bucket: Bucket, +} + +impl BucketNameAndBalance { + pub fn new(bucket: Bucket) -> Self { + Self { bucket } + } +} + +impl<'a> Into<Element<'a, navigation::Message<BucketNameAndBalance>>> for BucketNameAndBalance { + fn into(self) -> Element<'a, navigation::Message<BucketNameAndBalance>> { + row![text(self.bucket.name.clone()), text(self.bucket.balance)].into() + } +} diff --git a/schist_desktop_gui/src/gui/components/buckets_view.rs b/schist_desktop_gui/src/gui/components/buckets_view.rs new file mode 100644 index 0000000..d27b7ff --- /dev/null +++ b/schist_desktop_gui/src/gui/components/buckets_view.rs @@ -0,0 +1,105 @@ +use iced::{ + alignment, + widget::{column, row, Container}, + Length, +}; +use schist_models::bucket::Bucket; + +use crate::{ + gui::components::{navigation, BucketNameAndBalance, Navigation}, + style::SPACING_LG, + traits::{Component, Viewable}, +}; + +#[derive(Clone, Debug)] +pub struct BucketsView { + buckets: Vec<Bucket>, + greeting: String, + navigation: Navigation<BucketNameAndBalance>, +} + +#[derive(Clone, Debug)] +pub enum Message { + NavigationMessage(navigation::Message<BucketNameAndBalance>), + SelectNextBucket, + SelectPrevBucket, + SetBuckets(Vec<Bucket>), +} + +pub enum Action { + None, +} + +impl BucketsView { + pub fn new(buckets: Vec<Bucket>, greeting: &str) -> Self { + Self { + buckets: buckets.clone(), + greeting: greeting.to_owned(), + navigation: Navigation::new( + buckets.first().cloned().map(BucketNameAndBalance::new), + buckets.into_iter().map(BucketNameAndBalance::new).collect(), + ), + } + } + + fn update_greeting(&mut self, active_bucket: &Bucket) { + self.greeting = format!("Hello, {} bucket!", active_bucket.name); + } +} + +impl<'a> Viewable<'a, Message> for BucketsView { + fn view(&'a self) -> iced::Element<'a, Message> + where + Message: 'a, + { + let navigation = self.navigation.view().map(Message::NavigationMessage); + let main_content = column![iced::widget::text(self.greeting.clone())]; + row![ + Container::new(navigation).width(Length::FillPortion(1)), + Container::new(main_content).width(Length::FillPortion(3)), + ] + .align_y(alignment::Vertical::Center) + .height(Length::Fill) + .spacing(SPACING_LG) + .into() + } +} + +impl<'a> Component<'a, Message, Action> for BucketsView { + fn update(&mut self, message: Message) -> Action { + match message { + Message::SetBuckets(buckets) => { + self.buckets = buckets.clone(); + self.navigation.update(navigation::Message::SetOptions( + buckets.into_iter().map(BucketNameAndBalance::new).collect(), + )); + Action::None + } + Message::NavigationMessage(message) => match self.navigation.update(message) { + navigation::Action::SelectOption(bucket) => { + self.update_greeting(&bucket.bucket); + Action::None + } + navigation::Action::None => Action::None, + }, + Message::SelectNextBucket => { + match self.navigation.update(navigation::Message::SelectNext) { + navigation::Action::SelectOption(bucket) => { + self.update_greeting(&bucket.bucket); + Action::None + } + navigation::Action::None => Action::None, + } + } + Message::SelectPrevBucket => { + match self.navigation.update(navigation::Message::SelectPrev) { + navigation::Action::SelectOption(bucket) => { + self.update_greeting(&bucket.bucket); + Action::None + } + navigation::Action::None => Action::None, + } + } + } + } +} diff --git a/schist_desktop_gui/src/gui/components/button.rs b/schist_desktop_gui/src/gui/components/button.rs new file mode 100644 index 0000000..bc9e5f9 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/button.rs @@ -0,0 +1,24 @@ +use iced::{widget::Button, Element}; + +pub fn active_button<'a, Content: Into<Element<'a, Message>>, Message>( + content: Content, +) -> Button<'a, Message> { + iced::widget::button(content) + .style(|theme: &iced::Theme, _status| iced::widget::button::Style { + background: Some(iced::Background::Color( + theme.extended_palette().primary.base.text, + )), + text_color: theme.extended_palette().primary.base.color, + ..Default::default() + }) + .width(iced::Length::Fill) +} + +pub fn inactive_button<'a, Content: Into<Element<'a, Message>>, Message>( + content: Content, + on_press: Message, +) -> Button<'a, Message> { + iced::widget::button(content) + .on_press(on_press) + .width(iced::Length::Fill) +} diff --git a/schist_desktop_gui/src/gui/components/navigation.rs b/schist_desktop_gui/src/gui/components/navigation.rs new file mode 100644 index 0000000..bed3221 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/navigation.rs @@ -0,0 +1,68 @@ +mod new_navigation; +mod update_navigation; +mod view_navigation; +mod view_navigation_button; + +use new_navigation::new_navigation; +use update_navigation::update_navigation; +use view_navigation::view_navigation; +use view_navigation_button::view_navigation_button; + +use std::fmt::Debug; + +use iced::Element; + +use crate::traits::{Component, Viewable}; + +#[derive(Clone, Debug)] +pub struct Navigation<TOption> { + options_before_active: Vec<TOption>, + active_option: Option<TOption>, + options_after_active: Vec<TOption>, +} + +#[derive(Clone, Debug)] +pub enum Message<TOption> { + SelectNext, + SelectOption(TOption), + SelectPrev, + SetOptions(Vec<TOption>), +} + +pub enum Action<TOption> { + SelectOption(TOption), + None, +} + +impl<TOption: Clone + Debug + PartialEq> Navigation<TOption> { + pub fn new(active_option: Option<TOption>, options: Vec<TOption>) -> Self { + new_navigation(active_option, options) + } +} + +impl<'a, TOption> Navigation<TOption> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + pub fn button(&'a self, option: &'a TOption) -> Element<'a, Message<TOption>> { + view_navigation_button(self, option) + } +} + +impl<'a, TOption> Viewable<'a, Message<TOption>> for Navigation<TOption> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + fn view(&'a self) -> iced::Element<'a, Message<TOption>> { + view_navigation(self) + } +} + +impl<'a, TOption> Component<'a, Message<TOption>, Action<TOption>> for Navigation<TOption> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + fn update(&mut self, message: Message<TOption>) -> Action<TOption> { + update_navigation(self, message) + } +} diff --git a/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs new file mode 100644 index 0000000..b5c0c19 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs @@ -0,0 +1,72 @@ +use super::Navigation; + +pub fn new_navigation<TOption>( + active_option: Option<TOption>, + options: Vec<TOption>, +) -> Navigation<TOption> +where + TOption: Clone + PartialEq, +{ + let active_option_index = active_option.clone().map_or(Option::None, |active_option| { + options.iter().position(|option| option.eq(&active_option)) + }); + if let Some(active_option_index) = active_option_index { + let split = options.split_at(active_option_index); + Navigation { + options_before_active: split.0.to_vec(), + active_option, + options_after_active: split.1.split_at(1).1.to_vec(), + } + } else { + Navigation { + options_before_active: options, + active_option, + options_after_active: vec![], + } + } +} + +#[cfg(test)] +mod test { + use super::Navigation; + + #[test] + fn when_active_option_at_start_of_options_then_finds_active_option() { + let navigation = Navigation::new(Some(1), vec![1, 2, 3, 4, 5]); + assert_eq!(Vec::<i32>::new(), navigation.options_before_active); + assert_eq!(Some(1), navigation.active_option); + assert_eq!(vec![2, 3, 4, 5], navigation.options_after_active); + } + + #[test] + fn when_active_option_in_middle_of_options_then_finds_active_option() { + let navigation = Navigation::new(Some(3), vec![1, 2, 3, 4, 5]); + assert_eq!(vec![1, 2], navigation.options_before_active); + assert_eq!(Some(3), navigation.active_option); + assert_eq!(vec![4, 5], navigation.options_after_active); + } + + #[test] + fn when_active_option_at_end_of_options_then_finds_active_option() { + let navigation = Navigation::new(Some(5), vec![1, 2, 3, 4, 5]); + assert_eq!(vec![1, 2, 3, 4], navigation.options_before_active); + assert_eq!(Some(5), navigation.active_option); + assert_eq!(Vec::<i32>::new(), navigation.options_after_active); + } + + #[test] + fn when_active_option_not_in_options_then_appends_active_option() { + let navigation = Navigation::new(Some(6), vec![1, 2, 3, 4, 5]); + assert_eq!(vec![1, 2, 3, 4, 5], navigation.options_before_active); + assert_eq!(Some(6), navigation.active_option); + assert_eq!(Vec::<i32>::new(), navigation.options_after_active); + } + + #[test] + fn when_no_active_option_then_all_options_are_before_active_option() { + let navigation = Navigation::new(None, vec![1, 2, 3, 4, 5]); + assert_eq!(vec![1, 2, 3, 4, 5], navigation.options_before_active); + assert_eq!(None, navigation.active_option); + assert_eq!(Vec::<i32>::new(), navigation.options_after_active); + } +} diff --git a/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs new file mode 100644 index 0000000..f86867f --- /dev/null +++ b/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs @@ -0,0 +1,128 @@ +use iced::Element; + +use super::{Action, Message, Navigation}; + +pub fn update_navigation<'a, TOption>( + navigation: &mut Navigation<TOption>, + message: Message<TOption>, +) -> Action<TOption> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + match message { + Message::SelectOption(option) => { + if navigation + .active_option + .as_ref() + .is_some_and(|active_option| active_option.clone() == option) + { + Action::None + } else if let Some(index) = navigation + .options_before_active + .iter() + .position(|o| o.clone() == option) + { + let split = navigation.options_before_active.split_at(index); + navigation.options_after_active = vec![ + navigation + .active_option + .clone() + .map_or(vec![], |active_option| vec![active_option]), + split.1.split_at(1).1.to_vec(), + navigation.options_after_active.clone(), + ] + .concat(); + navigation.options_before_active = split.0.to_vec(); + navigation.active_option = Some(option.clone()); + Action::SelectOption(option) + } else if let Some(index) = navigation + .options_after_active + .iter() + .position(|o| o.clone() == option) + { + let split = navigation.options_after_active.split_at(index); + navigation.options_before_active = vec![ + navigation.options_before_active.clone(), + split.0.to_vec(), + navigation + .active_option + .clone() + .map_or(vec![], |active_option| vec![active_option]), + ] + .concat(); + navigation.active_option = Some(option.clone()); + navigation.options_after_active = split.1.split_at(1).1.to_vec(); + Action::SelectOption(option) + } else { + if let Some(active_option) = &navigation.active_option { + navigation.options_before_active.push(active_option.clone()); + } + navigation + .options_before_active + .append(&mut navigation.options_after_active); + navigation.active_option = Some(option.clone()); + navigation.options_after_active = vec![]; + Action::SelectOption(option) + } + } + Message::SetOptions(options) => { + let active_option_index = + navigation + .active_option + .clone() + .map_or(Option::None, |active_option| { + options + .iter() + .position(|option| active_option == option.clone()) + }); + if let Some(active_option_index) = active_option_index { + let split = options.split_at(active_option_index); + navigation.options_before_active = split.0.to_vec(); + navigation.options_after_active = split.1.split_at(1).1.to_vec(); + Action::None + } else { + navigation.options_before_active = options + .split_last() + .map_or_else(Vec::new, |(_last, rest)| rest.to_vec()); + navigation.active_option = options.last().cloned(); + options + .last() + .cloned() + .map_or(Action::None, Action::SelectOption) + } + } + Message::SelectNext => { + if let Some(next) = navigation.options_after_active.clone().first() { + navigation.options_before_active = vec![ + navigation.options_before_active.clone(), + navigation.active_option.clone().map_or(vec![], |o| vec![o]), + ] + .concat(); + navigation.active_option = Some(next.clone()); + navigation.options_after_active = + navigation.options_after_active.split_at(1).1.to_vec(); + Action::SelectOption(next.clone()) + } else { + Action::None + } + } + Message::SelectPrev => { + if let Some(prev) = navigation.options_before_active.clone().last() { + navigation.options_after_active = vec![ + navigation.active_option.clone().map_or(vec![], |o| vec![o]), + navigation.options_after_active.clone(), + ] + .concat(); + navigation.active_option = Some(prev.clone()); + navigation.options_before_active = navigation + .options_before_active + .split_last() + .map(|split| split.1.to_vec()) + .unwrap_or_else(Vec::new); + Action::SelectOption(prev.clone()) + } else { + Action::None + } + } + } +} diff --git a/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs new file mode 100644 index 0000000..beec818 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs @@ -0,0 +1,26 @@ +use iced::{widget::column, Element}; + +use super::{Message, Navigation}; + +pub fn view_navigation<'a, TOption>( + navigation: &'a Navigation<TOption>, +) -> Element<'a, Message<TOption>> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + let mut options = Vec::new(); + navigation + .options_before_active + .iter() + .map(|option| navigation.button(&option)) + .for_each(|option| options.push(option)); + if let Some(active_option) = navigation.active_option.as_ref() { + options.push(navigation.button(&active_option)); + } + navigation + .options_after_active + .iter() + .map(|option| navigation.button(&option)) + .for_each(|option| options.push(option)); + column(options).into() +} diff --git a/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs b/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs new file mode 100644 index 0000000..3132bf1 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs @@ -0,0 +1,27 @@ +use iced::Element; + +use crate::gui::components::{active_button, inactive_button}; + +use super::{Message, Navigation}; + +pub fn view_navigation_button<'a, TOption>( + navigation: &'a Navigation<TOption>, + option: &'a TOption, +) -> Element<'a, Message<TOption>> +where + TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, +{ + if navigation + .active_option + .as_ref() + .is_some_and(|o| *o == *option) + { + active_button(Into::<Element<'a, Message<TOption>>>::into(option.clone())).into() + } else { + inactive_button( + Into::<Element<'a, Message<TOption>>>::into(option.clone()), + Message::SelectOption(option.clone()), + ) + .into() + } +} diff --git a/schist_desktop_gui/src/gui/components/text.rs b/schist_desktop_gui/src/gui/components/text.rs new file mode 100644 index 0000000..d334de3 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/text.rs @@ -0,0 +1,22 @@ +use iced::Element; + +use crate::gui::components::navigation; + +#[derive(Clone, Debug, PartialEq)] +pub struct Text { + pub content: String, +} + +impl Text { + pub fn new(group_name: String) -> Self { + Self { + content: group_name.clone(), + } + } +} + +impl<'a> Into<Element<'a, navigation::Message<Text>>> for Text { + fn into(self) -> Element<'a, navigation::Message<Text>> { + iced::widget::text(self.content.clone()).into() + } +} diff --git a/schist_desktop_gui/src/gui/components/transactions_view.rs b/schist_desktop_gui/src/gui/components/transactions_view.rs new file mode 100644 index 0000000..6181a14 --- /dev/null +++ b/schist_desktop_gui/src/gui/components/transactions_view.rs @@ -0,0 +1,118 @@ +use iced::{ + alignment, + widget::{column, row, Container}, + Element, Length, +}; +use schist_models::account::Account; + +use crate::{ + gui::components::{navigation, Navigation, Text}, + style::SPACING_LG, + traits::{Component, Viewable}, +}; + +#[derive(Clone, Debug)] +pub struct TransactionsView { + accounts: Vec<Account>, + greeting: String, + navigation: Navigation<Text>, +} + +#[derive(Clone, Debug)] +pub enum Message { + NavigationMessage(navigation::Message<Text>), + SelectNextTransaction, + SelectPrevTransaction, + SetAccounts(Vec<Account>), +} + +pub enum Action { + None, +} + +impl TransactionsView { + pub fn new(accounts: Vec<Account>, greeting: &str) -> Self { + let account_names = view_account_names(accounts.clone()); + let navigation = Navigation::new(account_names.clone().first().cloned(), account_names); + Self { + accounts: accounts, + greeting: greeting.to_owned(), + navigation: navigation, + } + } +} + +impl<'a> Viewable<'a, Message> for TransactionsView { + fn view(&self) -> Element<Message> { + let navigation = self.navigation.view().map(Message::NavigationMessage); + let main_content = column![iced::widget::text(self.greeting.clone())]; + row![ + Container::new(navigation).width(Length::FillPortion(1)), + Container::new(main_content).width(Length::FillPortion(3)), + ] + .align_y(alignment::Vertical::Center) + .height(Length::Fill) + .spacing(SPACING_LG) + .into() + } +} + +impl<'a> Component<'a, Message, Action> for TransactionsView { + fn update(&mut self, message: Message) -> Action { + match message { + Message::NavigationMessage(message) => { + match self.navigation.update(message) { + navigation::Action::SelectOption(group_name) => { + self.greeting = make_greeting(group_name); + Action::None + } + navigation::Action::None => Action::None, + }; + Action::None + } + Message::SetAccounts(accounts) => { + self.accounts = accounts.clone(); + match self + .navigation + .update(navigation::Message::SetOptions(view_account_names( + accounts, + ))) { + navigation::Action::SelectOption(option) => { + self.greeting = make_greeting(option); + Action::None + } + navigation::Action::None => Action::None, + } + } + Message::SelectNextTransaction => { + match self.navigation.update(navigation::Message::SelectNext) { + navigation::Action::SelectOption(option) => { + self.greeting = make_greeting(option); + Action::None + } + navigation::Action::None => Action::None, + } + } + Message::SelectPrevTransaction => { + match self.navigation.update(navigation::Message::SelectPrev) { + navigation::Action::SelectOption(option) => { + self.greeting = make_greeting(option); + Action::None + } + navigation::Action::None => Action::None, + } + } + } + } +} + +fn make_greeting(account_name: Text) -> String { + format!("Hello, {} account!", account_name.content) +} + +fn view_account_names(accounts: Vec<Account>) -> Vec<Text> { + accounts + .iter() + .map(|acc| Text::new(acc.name.clone())) + .collect() +} diff --git a/schist_desktop_gui/src/gui/screens.rs b/schist_desktop_gui/src/gui/screens.rs new file mode 100644 index 0000000..3ae97dd --- /dev/null +++ b/schist_desktop_gui/src/gui/screens.rs @@ -0,0 +1,9 @@ +pub mod main_screen; + +pub use main_screen::MainScreen; + +#[derive(Default)] +pub enum Screen { + #[default] + Main, +} diff --git a/schist_desktop_gui/src/gui/screens/main_screen.rs b/schist_desktop_gui/src/gui/screens/main_screen.rs new file mode 100644 index 0000000..21ef44a --- /dev/null +++ b/schist_desktop_gui/src/gui/screens/main_screen.rs @@ -0,0 +1,7 @@ +mod main_screen; +mod view; + +pub use main_screen::Action; +pub use main_screen::MainScreen; +pub use main_screen::Message; +pub use view::View; diff --git a/schist_desktop_gui/src/gui/screens/main_screen/main_screen.rs b/schist_desktop_gui/src/gui/screens/main_screen/main_screen.rs new file mode 100644 index 0000000..bad3dee --- /dev/null +++ b/schist_desktop_gui/src/gui/screens/main_screen/main_screen.rs @@ -0,0 +1,160 @@ +use super::View; +use iced::{ + alignment, + widget::{row, Container}, + Element, Length, +}; +use schist_models::{account::Account, bucket::Bucket}; + +use crate::{ + gui::components::{ + balances_view, buckets_view, navigation, transactions_view, BalancesView, BucketsView, + Navigation, TransactionsView, + }, + style::SPACING_LG, + traits::{Component, Viewable}, +}; + +pub struct MainScreen { + pub active_view: View, + pub buckets: Vec<Bucket>, + pub balances_view: BalancesView, + pub buckets_view: BucketsView, + pub transactions_view: TransactionsView, + pub view_navigation: Navigation<View>, +} + +#[derive(Clone, Debug)] +pub enum Message { + BalancesViewMessage(balances_view::Message), + BucketsViewMessage(buckets_view::Message), + NextItem, + PrevItem, + TransactionsViewMessage(transactions_view::Message), + SelectView(View), + SetAccounts(Vec<Account>), + SetBuckets(Vec<Bucket>), + ViewNavigationMessage(navigation::Message<View>), +} + +pub enum Action { + None, +} + +impl<'a> Viewable<'a, Message> for MainScreen { + fn view(&'a self) -> Element<'a, Message> { + let view_navigation = self + .view_navigation + .view() + .map(Message::ViewNavigationMessage); + let view = match &self.active_view { + View::Balances => self.balances_view.view().map(Message::BalancesViewMessage), + View::Buckets => self.buckets_view.view().map(Message::BucketsViewMessage), + View::Transactions => self + .transactions_view + .view() + .map(Message::TransactionsViewMessage), + }; + + row![ + Container::new(view_navigation).width(Length::FillPortion(1)), + Container::new(view).width(Length::FillPortion(4)), + ] + .align_y(alignment::Vertical::Center) + .height(Length::Fill) + .spacing(SPACING_LG) + .into() + } +} + +impl<'a> Component<'a, Message, Action> for MainScreen { + fn update(&mut self, message: Message) -> Action { + match message { + Message::SelectView(view) => { + self.active_view = view; + self.view_navigation + .update(navigation::Message::SelectOption(view)); + Action::None + } + Message::BalancesViewMessage(message) => match self.balances_view.update(message) { + balances_view::Action::None => Action::None, + }, + Message::BucketsViewMessage(message) => { + self.buckets_view.update(message); + Action::None + } + Message::TransactionsViewMessage(message) => { + match self.transactions_view.update(message) { + transactions_view::Action::None => Action::None, + } + } + Message::ViewNavigationMessage(message) => match self.view_navigation.update(message) { + navigation::Action::SelectOption(view) => { + self.active_view = view; + Action::None + } + navigation::Action::None => Action::None, + }, + Message::SetBuckets(buckets) => { + self.buckets = buckets.clone(); + self.balances_view + .update(balances_view::Message::SetBuckets(buckets.clone())); + self.buckets_view + .update(buckets_view::Message::SetBuckets(buckets)); + Action::None + } + Message::SetAccounts(accounts) => { + self.transactions_view + .update(transactions_view::Message::SetAccounts(accounts)); + Action::None + } + Message::NextItem => match self.active_view { + View::Balances => { + self.balances_view + .update(balances_view::Message::SelectNextBucket); + Action::None + } + View::Buckets => { + self.buckets_view + .update(buckets_view::Message::SelectNextBucket); + Action::None + } + View::Transactions => { + self.transactions_view + .update(transactions_view::Message::SelectNextTransaction); + Action::None + } + }, + Message::PrevItem => match self.active_view { + View::Balances => { + self.balances_view + .update(balances_view::Message::SelectPrevBucket); + Action::None + } + View::Buckets => { + self.buckets_view + .update(buckets_view::Message::SelectPrevBucket); + Action::None + } + View::Transactions => { + self.transactions_view + .update(transactions_view::Message::SelectPrevTransaction); + Action::None + } + }, + } + } +} + +impl MainScreen { + pub fn new(buckets: Vec<Bucket>, accounts: Vec<Account>) -> Self { + Self { + balances_view: BalancesView::new(buckets.clone()), + buckets: buckets.clone(), + buckets_view: BucketsView::new(buckets, "Hello, buckets!"), + transactions_view: TransactionsView::new(accounts, "Hello, transactions!"), + active_view: View::Balances, + view_navigation: Navigation::new(Some(View::Balances), View::views()), + } + } +} diff --git a/schist_desktop_gui/src/gui/screens/main_screen/view.rs b/schist_desktop_gui/src/gui/screens/main_screen/view.rs new file mode 100644 index 0000000..eb9c88e --- /dev/null +++ b/schist_desktop_gui/src/gui/screens/main_screen/view.rs @@ -0,0 +1,48 @@ +use iced::Element; + +use crate::gui::components::navigation; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum View { + Balances, + Buckets, + Transactions, +} + +impl View { + pub const VIEW_1: View = View::Buckets; + pub const VIEW_2: View = View::Balances; + pub const VIEW_3: View = View::Transactions; + + pub fn views() -> Vec<View> { + vec![Self::VIEW_1, Self::VIEW_2, Self::VIEW_3] + } + + pub const fn name(self) -> &'static str { + match self { + View::Balances => "balances", + View::Buckets => "buckets", + View::Transactions => "transactions", + } + } + + pub fn next(&self) -> View { + match *self { + Self::VIEW_1 => Self::VIEW_2, + Self::VIEW_2 | Self::VIEW_3 => Self::VIEW_3, + } + } + + pub fn prev(&self) -> View { + match *self { + Self::VIEW_1 | Self::VIEW_2 => Self::VIEW_1, + Self::VIEW_3 => Self::VIEW_2, + } + } +} + +impl<'a> Into<Element<'a, navigation::Message<View>>> for View { + fn into(self) -> Element<'a, navigation::Message<View>> { + iced::widget::text(self.name()).into() + } +} diff --git a/schist_desktop_gui/src/main.rs b/schist_desktop_gui/src/main.rs index b836453..7e54ddb 100644 --- a/schist_desktop_gui/src/main.rs +++ b/schist_desktop_gui/src/main.rs @@ -1,18 +1,24 @@ mod config; -mod message; +mod dummy_data; +mod gui; mod settings; -mod state; +mod shortcut; +mod style; mod theme; +mod traits; mod window_settings; -mod view; -use crate::{config::Config, settings::make_settings, state::State, theme::make_theme, window_settings::make_window_settings, view::view}; +use crate::{ + config::Config, gui::Gui, settings::make_settings, theme::make_theme, + window_settings::make_window_settings, +}; fn main() -> iced::Result { let config = Config::default(); - iced::application("Schist", State::update, view) + iced::application("Schist", Gui::update, Gui::view) .settings(make_settings(&config.clone())) - .theme(|state: &State| make_theme(state)) + .subscription(gui::subscription) + .theme(make_theme) .window(make_window_settings(&config.clone())) - .run() -}
\ No newline at end of file + .run_with(Gui::new) +} diff --git a/schist_desktop_gui/src/message.rs b/schist_desktop_gui/src/message.rs deleted file mode 100644 index 10f734b..0000000 --- a/schist_desktop_gui/src/message.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[derive(Debug)] -pub enum Message { -} diff --git a/schist_desktop_gui/src/shortcut.rs b/schist_desktop_gui/src/shortcut.rs new file mode 100644 index 0000000..f979f4e --- /dev/null +++ b/schist_desktop_gui/src/shortcut.rs @@ -0,0 +1,339 @@ +// borrowed from https://github.com/squidowl/halloy/tree/main/src/shortcut.rs#L230 + +use iced::keyboard::{self, key}; +use std::hash::Hash; +use std::str::FromStr; +use std::{fmt, ops}; + +use crate::gui::screens::main_screen::View; + +pub fn shortcut(key_bind: KeyBind, command: Command) -> Shortcut { + Shortcut { key_bind, command } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Shortcut { + key_bind: KeyBind, + command: Command, +} + +impl Shortcut { + pub fn execute(&self, key_bind: &KeyBind) -> Option<Command> { + (self.key_bind == *key_bind).then_some(self.command) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Command { + GotoNextItem, + GotoPrevItem, + GotoNextView, + GotoPrevView, + GotoView(View), +} + +macro_rules! default { + ($name:ident, $k:tt) => { + pub fn $name() -> KeyBind { + KeyBind { + key_code: KeyCode(iced::keyboard::Key::Named(iced::keyboard::key::Named::$k)), + modifiers: Modifiers::default(), + } + } + }; + ($name:ident, $k:literal, $m:expr) => { + pub fn $name() -> KeyBind { + KeyBind { + key_code: KeyCode(iced::keyboard::Key::Character($k.into())), + modifiers: $m, + } + } + }; + ($name:ident, $k:tt, $m:expr) => { + pub fn $name() -> KeyBind { + KeyBind { + key_code: KeyCode(iced::keyboard::Key::Named(iced::keyboard::key::Named::$k)), + modifiers: $m, + } + } + }; +} + +#[derive(Debug, Clone, Eq, Ord, PartialOrd)] +pub struct KeyBind { + key_code: KeyCode, + modifiers: Modifiers, +} + +impl fmt::Display for KeyBind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} {}", self.modifiers, self.key_code) + } +} + +impl PartialEq for KeyBind { + fn eq(&self, other: &Self) -> bool { + if self.modifiers != other.modifiers { + return false; + } + + match (&self.key_code.0, &other.key_code.0) { + // SHIFT modifier effects if this comes across as `a` or `A`, but + // we explicitly define / check modifiers so it doesn't matter if + // user defined it as `a` or `A` in their keymap + (keyboard::Key::Character(a), keyboard::Key::Character(b)) => { + a.to_lowercase() == b.to_lowercase() + } + (a, b) => a == b, + } + } +} + +impl Hash for KeyBind { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.key_code.hash(state); + self.modifiers.hash(state); + } +} + +// For defaults check the platform specific defaults: +// macOS: https://support.apple.com/en-us/102650 +// Windows: https://support.microsoft.com/en-us/windows/keyboard-shortcuts-in-windows-dcc61a57-8ff0-cffe-9796-cb9706c75eec +// Linux FreeDesktop (not ready yet): https://wiki.freedesktop.org/www/Specifications/default-keys-spec/ +// Linux - KDE: https://docs.kde.org/stable5/en/khelpcenter/fundamentals/kbd.html +// Linux - Gnome: https://help.gnome.org/users/gnome-help/stable/keyboard-nav.html.en + +impl KeyBind { + default!(goto_next_item, "j", Modifiers::EMPTY); + default!(goto_prev_item, "k", Modifiers::EMPTY); + default!(goto_next_view, "j", Modifiers::CTRL); + default!(goto_prev_view, "k", Modifiers::CTRL); + default!(goto_view_1, "1", Modifiers::CTRL); + default!(goto_view_2, "2", Modifiers::CTRL); + default!(goto_view_3, "3", Modifiers::CTRL); +} + +impl From<(keyboard::Key, keyboard::Modifiers)> for KeyBind { + fn from((key_code, modifiers): (keyboard::Key, keyboard::Modifiers)) -> Self { + Self { + key_code: KeyCode(key_code), + modifiers: Modifiers(modifiers), + } + } +} + +#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone)] +pub struct KeyCode(keyboard::Key); + +#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Default)] +pub struct Modifiers(keyboard::Modifiers); + +impl Modifiers { + const CTRL: Modifiers = Modifiers(keyboard::Modifiers::CTRL); + const EMPTY: Modifiers = Modifiers(keyboard::Modifiers::empty()); +} + +impl From<keyboard::Modifiers> for Modifiers { + fn from(modifiers: keyboard::Modifiers) -> Self { + Self(modifiers) + } +} + +impl ops::BitOr for Modifiers { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +impl fmt::Display for Modifiers { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut mods = vec![]; + let inner = self.0; + + if inner.contains(keyboard::Modifiers::SHIFT) { + mods.push("Shift"); + } + if inner.contains(keyboard::Modifiers::CTRL) { + if cfg!(target_os = "macos") { + // macOS: ⌃ + mods.push("\u{2303}"); + } else { + mods.push("Ctrl"); + } + } + if inner.contains(keyboard::Modifiers::ALT) { + if cfg!(target_os = "macos") { + // macOS: ⌥ + mods.push("\u{2325}"); + } else { + mods.push("Alt"); + } + } + if inner.contains(keyboard::Modifiers::LOGO) { + // macOS: ⌘ + mods.push("\u{2318}"); + } + + if mods.is_empty() { + write!(f, "") + } else { + write!(f, "{}", mods.join(" ")) + } + } +} + +impl fmt::Display for KeyCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let key = match self.0.clone() { + key::Key::Named(name) => { + let named = match name { + key::Named::F1 => "F1", + key::Named::F2 => "F2", + key::Named::F3 => "F3", + key::Named::F4 => "F4", + key::Named::F5 => "F5", + key::Named::F6 => "F6", + key::Named::F7 => "F7", + key::Named::F8 => "F8", + key::Named::F9 => "F9", + key::Named::F10 => "F10", + key::Named::F11 => "F11", + key::Named::F12 => "F12", + key::Named::F13 => "F13", + key::Named::F14 => "F14", + key::Named::F15 => "F15", + key::Named::F16 => "F16", + key::Named::F17 => "F17", + key::Named::F18 => "F18", + key::Named::F19 => "F19", + key::Named::F20 => "F20", + key::Named::F21 => "F21", + key::Named::F22 => "F22", + key::Named::F23 => "F23", + key::Named::F24 => "F24", + key::Named::Home => "Home", + key::Named::Delete => "Delete", + key::Named::End => "End", + key::Named::PageDown => "PageDown", + key::Named::PageUp => "PageUp", + key::Named::ArrowLeft => "←", + key::Named::ArrowUp => "↑", + key::Named::ArrowRight => "→", + key::Named::ArrowDown => "↓", + key::Named::Backspace => "Backspace", + key::Named::Enter => "Enter", + key::Named::Space => "Space", + key::Named::NumLock => "NumLock", + key::Named::Alt => "Alt", + key::Named::Tab => "Tab", + key::Named::Pause => "Pause", + key::Named::Insert => "Insert", + key::Named::Cut => "Cut", + key::Named::Paste => "Paste", + key::Named::Copy => "Copy", + key::Named::AudioVolumeDown => "VolumeDown", + key::Named::AudioVolumeUp => "VolumeUp", + key::Named::Shift => "Shift", + key::Named::Control => "Control", + key::Named::AudioVolumeMute => "Mute", + key::Named::MediaStop => "MediaStop", + key::Named::MediaPause => "MediaPause", + key::Named::MediaTrackNext => "MediaTrackNext", + key::Named::MediaTrackPrevious => "MediaTrackPrev", + _ => "", + }; + + named.to_string() + } + key::Key::Character(c) => c.to_uppercase(), + key::Key::Unidentified => String::new(), + }; + + write!(f, "{key}") + } +} + +impl FromStr for KeyCode { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Self(match s.to_ascii_lowercase().as_str() { + "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" | "a" | "b" | "c" | "d" + | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" + | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "`" | "-" | "=" | "[" | "]" + | "\\" | ";" | "'" | "," | "." | "/" => keyboard::Key::Character(s.into()), + "escape" | "esc" => keyboard::Key::Named(key::Named::Escape), + "f1" => keyboard::Key::Named(key::Named::F1), + "f2" => keyboard::Key::Named(key::Named::F2), + "f3" => keyboard::Key::Named(key::Named::F3), + "f4" => keyboard::Key::Named(key::Named::F4), + "f5" => keyboard::Key::Named(key::Named::F5), + "f6" => keyboard::Key::Named(key::Named::F6), + "f7" => keyboard::Key::Named(key::Named::F7), + "f8" => keyboard::Key::Named(key::Named::F8), + "f9" => keyboard::Key::Named(key::Named::F9), + "f10" => keyboard::Key::Named(key::Named::F10), + "f11" => keyboard::Key::Named(key::Named::F11), + "f12" => keyboard::Key::Named(key::Named::F12), + "f13" => keyboard::Key::Named(key::Named::F13), + "f14" => keyboard::Key::Named(key::Named::F14), + "f15" => keyboard::Key::Named(key::Named::F15), + "f16" => keyboard::Key::Named(key::Named::F16), + "f17" => keyboard::Key::Named(key::Named::F17), + "f18" => keyboard::Key::Named(key::Named::F18), + "f19" => keyboard::Key::Named(key::Named::F19), + "f20" => keyboard::Key::Named(key::Named::F20), + "f21" => keyboard::Key::Named(key::Named::F21), + "f22" => keyboard::Key::Named(key::Named::F22), + "f23" => keyboard::Key::Named(key::Named::F23), + "f24" => keyboard::Key::Named(key::Named::F24), + "home" => keyboard::Key::Named(key::Named::Home), + "delete" => keyboard::Key::Named(key::Named::Delete), + "end" => keyboard::Key::Named(key::Named::End), + "pagedown" => keyboard::Key::Named(key::Named::PageDown), + "pageup" => keyboard::Key::Named(key::Named::PageUp), + "left" => keyboard::Key::Named(key::Named::ArrowLeft), + "up" => keyboard::Key::Named(key::Named::ArrowUp), + "right" => keyboard::Key::Named(key::Named::ArrowRight), + "down" => keyboard::Key::Named(key::Named::ArrowDown), + "backspace" => keyboard::Key::Named(key::Named::Backspace), + "enter" => keyboard::Key::Named(key::Named::Enter), + "space" => keyboard::Key::Named(key::Named::Space), + "numlock" => keyboard::Key::Named(key::Named::NumLock), + "alt" => keyboard::Key::Named(key::Named::Alt), + "tab" => keyboard::Key::Named(key::Named::Tab), + "pause" => keyboard::Key::Named(key::Named::Pause), + "insert" => keyboard::Key::Named(key::Named::Insert), + "cut" => keyboard::Key::Named(key::Named::Cut), + "paste" => keyboard::Key::Named(key::Named::Paste), + "copy" => keyboard::Key::Named(key::Named::Copy), + "volumedown" => keyboard::Key::Named(key::Named::AudioVolumeDown), + "volumeup" => keyboard::Key::Named(key::Named::AudioVolumeUp), + "shift" => keyboard::Key::Named(key::Named::Shift), + "control" => keyboard::Key::Named(key::Named::Control), + "mute" => keyboard::Key::Named(key::Named::AudioVolumeMute), + "mediastop" => keyboard::Key::Named(key::Named::MediaStop), + "mediapause" => keyboard::Key::Named(key::Named::MediaPause), + "mediatracknext" => keyboard::Key::Named(key::Named::MediaTrackNext), + "mediatrackprev" => keyboard::Key::Named(key::Named::MediaTrackPrevious), + _ => return Err(anyhow::format_err!("Invalid key code: {}", s)), + })) + } +} + +impl FromStr for Modifiers { + type Err = anyhow::Error; + + fn from_str(s: &str) -> anyhow::Result<Self> { + Ok(Self(match s.to_lowercase().as_str() { + "shift" => keyboard::Modifiers::SHIFT, + "ctrl" => keyboard::Modifiers::CTRL, + "alt" | "option" | "opt" => keyboard::Modifiers::ALT, + "cmd" | "command" => keyboard::Modifiers::COMMAND, + "logo" | "super" | "windows" => keyboard::Modifiers::LOGO, + _ => return Err(anyhow::format_err!("Invalid error: {}", s)), + })) + } +} diff --git a/schist_desktop_gui/src/state.rs b/schist_desktop_gui/src/state.rs deleted file mode 100644 index 0183104..0000000 --- a/schist_desktop_gui/src/state.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::message::Message; - -pub struct State { - pub greeting: String, -} - -impl State { - pub fn update(&mut self, _message: Message) { - } -} - -impl Default for State { - fn default() -> Self { - Self { - greeting: String::from("Hello, world!"), - } - } -} diff --git a/schist_desktop_gui/src/style.rs b/schist_desktop_gui/src/style.rs new file mode 100644 index 0000000..01ec2ad --- /dev/null +++ b/schist_desktop_gui/src/style.rs @@ -0,0 +1 @@ +pub const SPACING_LG: u16 = 32; diff --git a/schist_desktop_gui/src/theme.rs b/schist_desktop_gui/src/theme.rs index 695ff8a..61d736b 100644 --- a/schist_desktop_gui/src/theme.rs +++ b/schist_desktop_gui/src/theme.rs @@ -1,7 +1,7 @@ use iced::Theme; -use crate::state::State; +use crate::gui::Gui; -pub fn make_theme(_state: &State) -> Theme { +pub fn make_theme(_state: &Gui) -> Theme { Theme::GruvboxDark -}
\ No newline at end of file +} diff --git a/schist_desktop_gui/src/traits.rs b/schist_desktop_gui/src/traits.rs new file mode 100644 index 0000000..a36ef19 --- /dev/null +++ b/schist_desktop_gui/src/traits.rs @@ -0,0 +1,5 @@ +mod component; +mod viewable; + +pub use component::Component; +pub use viewable::Viewable; diff --git a/schist_desktop_gui/src/traits/component.rs b/schist_desktop_gui/src/traits/component.rs new file mode 100644 index 0000000..cece636 --- /dev/null +++ b/schist_desktop_gui/src/traits/component.rs @@ -0,0 +1,5 @@ +use crate::traits::Viewable; + +pub trait Component<'a, Message, Action>: Viewable<'a, Message> { + fn update(&mut self, message: Message) -> Action; +} diff --git a/schist_desktop_gui/src/traits/viewable.rs b/schist_desktop_gui/src/traits/viewable.rs new file mode 100644 index 0000000..e0f0eb7 --- /dev/null +++ b/schist_desktop_gui/src/traits/viewable.rs @@ -0,0 +1,3 @@ +pub trait Viewable<'a, Message> { + fn view(&'a self) -> iced::Element<'a, Message>; +} diff --git a/schist_desktop_gui/src/view.rs b/schist_desktop_gui/src/view.rs deleted file mode 100644 index 7d169b5..0000000 --- a/schist_desktop_gui/src/view.rs +++ /dev/null @@ -1,7 +0,0 @@ -use iced::widget::{column, Column}; - -use crate::{message::Message, state::State}; - -pub fn view(state: &State) -> Column<Message> { - column![iced::widget::text(state.greeting.clone())] -} diff --git a/schist_desktop_gui/src/window_settings.rs b/schist_desktop_gui/src/window_settings.rs index cd71d09..8533f97 100644 --- a/schist_desktop_gui/src/window_settings.rs +++ b/schist_desktop_gui/src/window_settings.rs @@ -4,4 +4,4 @@ use crate::config::Config; pub fn make_window_settings(_config: &Config) -> Settings { Settings::default() -}
\ No newline at end of file +} |
