summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock772
-rw-r--r--Cargo.toml26
-rw-r--r--requirements/kanban.md1
-rw-r--r--requirements/tasks/epic-000.md2
-rw-r--r--schist_backend/src/main.rs2
-rw-r--r--schist_core/schist_fakes/src/bucket.rs24
-rw-r--r--schist_core/schist_fakes/src/category.rs19
-rw-r--r--schist_core/schist_fakes/src/category_transfer.rs8
-rw-r--r--schist_core/schist_fakes/src/lib.rs2
-rw-r--r--schist_core/schist_models/src/bucket.rs (renamed from schist_core/schist_models/src/category.rs)16
-rw-r--r--schist_core/schist_models/src/bucket_transfer.rs (renamed from schist_core/schist_models/src/category_transfer.rs)2
-rw-r--r--schist_core/schist_models/src/lib.rs6
-rw-r--r--schist_core/schist_models/src/schema.rs1
-rw-r--r--schist_desktop_gui/Cargo.toml5
-rw-r--r--schist_desktop_gui/src/config.rs17
-rw-r--r--schist_desktop_gui/src/config/keys.rs45
-rw-r--r--schist_desktop_gui/src/dummy_data.rs70
-rw-r--r--schist_desktop_gui/src/gui.rs132
-rw-r--r--schist_desktop_gui/src/gui/components.rs15
-rw-r--r--schist_desktop_gui/src/gui/components/balances_view.rs63
-rw-r--r--schist_desktop_gui/src/gui/components/balances_view/make_balances_view_greeting.rs9
-rw-r--r--schist_desktop_gui/src/gui/components/balances_view/update_balances_view.rs121
-rw-r--r--schist_desktop_gui/src/gui/components/balances_view/view_balances_view.rs22
-rw-r--r--schist_desktop_gui/src/gui/components/balances_view/view_group_names.rs143
-rw-r--r--schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs24
-rw-r--r--schist_desktop_gui/src/gui/components/buckets_view.rs105
-rw-r--r--schist_desktop_gui/src/gui/components/button.rs24
-rw-r--r--schist_desktop_gui/src/gui/components/navigation.rs68
-rw-r--r--schist_desktop_gui/src/gui/components/navigation/new_navigation.rs72
-rw-r--r--schist_desktop_gui/src/gui/components/navigation/update_navigation.rs128
-rw-r--r--schist_desktop_gui/src/gui/components/navigation/view_navigation.rs26
-rw-r--r--schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs27
-rw-r--r--schist_desktop_gui/src/gui/components/text.rs22
-rw-r--r--schist_desktop_gui/src/gui/components/transactions_view.rs118
-rw-r--r--schist_desktop_gui/src/gui/screens.rs9
-rw-r--r--schist_desktop_gui/src/gui/screens/main_screen.rs7
-rw-r--r--schist_desktop_gui/src/gui/screens/main_screen/main_screen.rs160
-rw-r--r--schist_desktop_gui/src/gui/screens/main_screen/view.rs48
-rw-r--r--schist_desktop_gui/src/main.rs22
-rw-r--r--schist_desktop_gui/src/message.rs3
-rw-r--r--schist_desktop_gui/src/shortcut.rs339
-rw-r--r--schist_desktop_gui/src/state.rs18
-rw-r--r--schist_desktop_gui/src/style.rs1
-rw-r--r--schist_desktop_gui/src/theme.rs6
-rw-r--r--schist_desktop_gui/src/traits.rs5
-rw-r--r--schist_desktop_gui/src/traits/component.rs5
-rw-r--r--schist_desktop_gui/src/traits/viewable.rs3
-rw-r--r--schist_desktop_gui/src/view.rs7
-rw-r--r--schist_desktop_gui/src/window_settings.rs2
49 files changed, 2342 insertions, 430 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 21bf6a4..2537d9d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
]
diff --git a/Cargo.toml b/Cargo.toml
index 52df1c3..0afc5c6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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
+}