diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..1729fab
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,2024 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "base64"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "cairo-rs"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f33613627f0dea6a731b0605101fad59ba4f193a52c96c4687728d822605a8a1"
+dependencies = [
+ "bitflags 2.4.1",
+ "cairo-sys-rs",
+ "glib",
+ "libc",
+ "once_cell",
+ "thiserror",
+]
+
+[[package]]
+name = "cairo-sys-rs"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cfg-expr"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3"
+dependencies = [
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "deluxe"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed332aaf752b459088acf3dd4eca323e3ef4b83c70a84ca48fb0ec5305f1488"
+dependencies = [
+ "deluxe-core",
+ "deluxe-macros",
+ "once_cell",
+ "proc-macro2",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "deluxe-core"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eddada51c8576df9d6a8450c351ff63042b092c9458b8ac7d20f89cbd0ffd313"
+dependencies = [
+ "arrayvec",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "deluxe-macros"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f87546d9c837f0b7557e47b8bd6eae52c3c223141b76aa233c345c9ab41d9117"
+dependencies = [
+ "deluxe-core",
+ "heck",
+ "if_chain",
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
+name = "field-offset"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
+dependencies = [
+ "memoffset",
+ "rustc_version",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
+
+[[package]]
+name = "futures-task"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
+
+[[package]]
+name = "futures-util"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
+dependencies = [
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "gdk-pixbuf"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "446f32b74d22c33b7b258d4af4ffde53c2bf96ca2e29abdf1a785fe59bd6c82c"
+dependencies = [
+ "gdk-pixbuf-sys",
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "gdk-pixbuf-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
+dependencies = [
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gdk4"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edb019ad581f8ecf8ea8e4baa6df7c483a95b5a59be3140be6a9c3b0c632af6"
+dependencies = [
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk4-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk4-sys"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbab43f332a3cf1df9974da690b5bb0e26720ed09a228178ce52175372dcfef0"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gettext-rs"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364"
+dependencies = [
+ "gettext-sys",
+ "locale_config",
+]
+
+[[package]]
+name = "gettext-sys"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c63ce2e00f56a206778276704bbe38564c8695249fdc8f354b4ef71c57c3839d"
+dependencies = [
+ "cc",
+ "temp-dir",
+]
+
+[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "gio"
+version = "0.18.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "gio-sys",
+ "glib",
+ "libc",
+ "once_cell",
+ "pin-project-lite",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gio-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+ "winapi",
+]
+
+[[package]]
+name = "glib"
+version = "0.18.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e"
+dependencies = [
+ "bitflags 2.4.1",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys",
+ "glib-macros",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "memchr",
+ "once_cell",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72793962ceece3863c2965d7f10c8786323b17c7adea75a515809fa20ab799a5"
+dependencies = [
+ "heck",
+ "proc-macro-crate 2.0.1",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
+dependencies = [
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gobject-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "graphene-rs"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2228cda1505613a7a956cca69076892cfbda84fc2b7a62b94a41a272c0c401"
+dependencies = [
+ "glib",
+ "graphene-sys",
+ "libc",
+]
+
+[[package]]
+name = "graphene-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc4144cee8fc8788f2a9b73dc5f1d4e1189d1f95305c4cb7bd9c1af1cfa31f59"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gsettings-macro"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5582953d3e15ef858ec22b6e5312c540dbbf9e3a653f3d4cf51afc444bf0b5d"
+dependencies = [
+ "deluxe",
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+ "serde",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "gsk4"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d958e351d2f210309b32d081c832d7de0aca0b077aa10d88336c6379bd01f7e"
+dependencies = [
+ "cairo-rs",
+ "gdk4",
+ "glib",
+ "graphene-rs",
+ "gsk4-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gsk4-sys"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12bd9e3effea989f020e8f1ff3fa3b8c63ba93d43b899c11a118868853a56d55"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk4-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "gtk4"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aeb51aa3e9728575a053e1f43543cd9992ac2477e1b186ad824fd4adfb70842"
+dependencies = [
+ "cairo-rs",
+ "field-offset",
+ "futures-channel",
+ "gdk-pixbuf",
+ "gdk4",
+ "gio",
+ "glib",
+ "graphene-rs",
+ "gsk4",
+ "gtk4-macros",
+ "gtk4-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gtk4-macros"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d57ec49cf9b657f69a05bca8027cff0a8dfd0c49e812be026fc7311f2163832f"
+dependencies = [
+ "anyhow",
+ "proc-macro-crate 1.3.1",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "gtk4-sys"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54d8c4aa23638ce9faa2caf7e2a27d4a1295af2155c8e8d28c4d4eeca7a65eb8"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "gsk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "h2"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+
+[[package]]
+name = "http"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "0.14.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "if_chain"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
+
+[[package]]
+name = "indexmap"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
+
+[[package]]
+name = "itoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libadwaita"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fe7e70c06507ed10a16cda707f358fbe60fe0dc237498f78c686ade92fd979c"
+dependencies = [
+ "gdk-pixbuf",
+ "gdk4",
+ "gio",
+ "glib",
+ "gtk4",
+ "libadwaita-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "libadwaita-sys"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e10aaa38de1d53374f90deeb4535209adc40cc5dba37f9704724169bceec69a"
+dependencies = [
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "gtk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.151"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
+
+[[package]]
+name = "locale_config"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
+dependencies = [
+ "lazy_static",
+ "objc",
+ "objc-foundation",
+ "regex",
+ "winapi",
+]
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+
+[[package]]
+name = "memoffset"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mod-manager"
+version = "0.1.0"
+dependencies = [
+ "gettext-rs",
+ "gsettings-macro",
+ "gtk4",
+ "libadwaita",
+ "reqwest",
+ "serde",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
+[[package]]
+name = "object"
+version = "0.32.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "openssl"
+version = "0.10.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45"
+dependencies = [
+ "bitflags 2.4.1",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.97"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "pango"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
+dependencies = [
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+ "pango-sys",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
+dependencies = [
+ "toml_datetime",
+ "toml_edit 0.20.2",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "reqwest"
+version = "0.11.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+dependencies = [
+ "bitflags 2.4.1",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+
+[[package]]
+name = "schannel"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
+
+[[package]]
+name = "serde"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
+
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "system-deps"
+version = "6.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
+dependencies = [
+ "cfg-expr",
+ "heck",
+ "pkg-config",
+ "toml",
+ "version-compare",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
+
+[[package]]
+name = "temp-dir"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab"
+
+[[package]]
+name = "tempfile"
+version = "3.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.35.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.20.2",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "nu-ansi-term",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "url"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version-compare"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
+
+[[package]]
+name = "web-sys"
+version = "0.3.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
+name = "winnow"
+version = "0.5.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 803dc9b..d953158 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,14 @@ lto = true
[dependencies]
gettext-rs = { version = "0.7", features = ["gettext-system"] }
-gtk = { version = "0.7", package = "gtk4", features = ["v4_8"] }
+gtk = { version = "0.7", package = "gtk4", features = ["v4_10"] }
tracing = "0.1.37"
tracing-subscriber = "0.3"
+reqwest = { version = "0.11", features = ["json", "blocking"] }
+serde = { version = "1.0", features = ["derive"] }
+gsettings-macro = "0.1.20"
+
+[dependencies.adw]
+package = "libadwaita"
+version = "0.5"
+features = ["v1_4"]
diff --git a/build-aux/dev.mnts.ModManager.Devel.json b/build-aux/dev.mnts.ModManager.Devel.json
index 3540f1b..9eceea0 100644
--- a/build-aux/dev.mnts.ModManager.Devel.json
+++ b/build-aux/dev.mnts.ModManager.Devel.json
@@ -1,7 +1,7 @@
{
"id": "dev.mnts.ModManager.Devel",
"runtime": "org.gnome.Platform",
- "runtime-version": "44",
+ "runtime-version": "45",
"sdk": "org.gnome.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.rust-stable",
@@ -19,9 +19,7 @@
],
"build-options": {
"append-path": "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm16/bin",
- "build-args": [
- "--share=network"
- ],
+ "build-args": ["--share=network"],
"env": {
"CARGO_REGISTRIES_CRATES_IO_PROTOCOL": "sparse",
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "clang",
@@ -29,19 +27,37 @@
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER": "clang",
"CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS": "-C link-arg=-fuse-ld=/usr/lib/sdk/rust-stable/bin/mold"
},
- "test-args": [
- "--socket=x11",
- "--share=network"
- ]
+ "test-args": ["--socket=x11", "--share=network"]
},
+ "cleanup": [
+ "/include",
+ "/lib/pkgconfig",
+ "/man",
+ "/share/doc",
+ "/share/gtk-doc",
+ "/share/man",
+ "/share/pkgconfig",
+ "*.la",
+ "*.a"
+ ],
"modules": [
+ {
+ "name": "blueprint-compiler",
+ "buildsystem": "meson",
+ "cleanup": ["*"],
+ "sources": [
+ {
+ "type": "git",
+ "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler",
+ "tag": "v0.10.0"
+ }
+ ]
+ },
{
"name": "mod-manager",
"buildsystem": "meson",
"run-tests": true,
- "config-opts": [
- "-Dprofile=development"
- ],
+ "config-opts": ["-Dprofile=development"],
"sources": [
{
"type": "dir",
@@ -51,4 +67,3 @@
}
]
}
-
diff --git a/data/dev.mnts.ModManager.gschema.xml.in b/data/dev.mnts.ModManager.gschema.xml.in
index 7c09a08..7a38785 100644
--- a/data/dev.mnts.ModManager.gschema.xml.in
+++ b/data/dev.mnts.ModManager.gschema.xml.in
@@ -13,5 +13,10 @@
false
Window maximized state
+
+ {}
+ Dictionary of games being managed. First string is game name second is path to mods
+ folder.
+
-
+
\ No newline at end of file
diff --git a/data/resources/meson.build b/data/resources/meson.build
index 604e1b2..7cef381 100644
--- a/data/resources/meson.build
+++ b/data/resources/meson.build
@@ -1,8 +1,20 @@
# Resources
+blueprints = custom_target('blueprints',
+ input: files(
+ 'ui/windows/main/main.blp',
+ 'ui/windows/main/pages/welcome.blp',
+ 'ui/windows/main/pages/games_and_mods.blp',
+ 'ui/windows/add_new_game/add_new_game.blp',
+ 'ui/components/mods_list.blp',
+ ),
+ output: '.',
+ command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
+)
resources = gnome.compile_resources(
'resources',
'resources.gresource.xml',
gresource_bundle: true,
+ dependencies: blueprints,
source_dir: meson.current_build_dir(),
install: true,
install_dir: pkgdatadir,
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 74c30a6..14b3811 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -2,8 +2,11 @@
- ui/shortcuts.ui
- ui/window.ui
+ ui/windows/main/main.ui
+ ui/windows/main/pages/welcome.ui
+ ui/windows/main/pages/games_and_mods.ui
+ ui/windows/add_new_game/add_new_game.ui
+ ui/components/mods_list.ui
style.css
diff --git a/data/resources/style.css b/data/resources/style.css
index 3c4bd47..e69de29 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -1,4 +0,0 @@
-.title-header{
- font-size: 36px;
- font-weight: bold;
-}
diff --git a/data/resources/ui/components/mods_list.blp b/data/resources/ui/components/mods_list.blp
new file mode 100644
index 0000000..01a2988
--- /dev/null
+++ b/data/resources/ui/components/mods_list.blp
@@ -0,0 +1,135 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $ModsList : Adw.NavigationPage {
+ title: _("Main");
+
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar header_bar {
+ show-back-button: true;
+ }
+
+ content: Box {
+ orientation: vertical;
+ valign: center;
+ halign: center;
+
+ Image {
+ name: "logo";
+ icon-name: "re.sonny.Workbench";
+ pixel-size: 196;
+ margin-bottom: 30;
+
+ styles [
+ "icon-dropshadow"
+ ]
+ }
+
+ Label {
+ label: _("Welcome to Mod Manager");
+ margin-bottom: 30;
+
+ styles [
+ "title-1"
+ ]
+ }
+
+ Box subtitle {
+ orientation: vertical;
+ halign: center;
+ margin-bottom: 30;
+
+ Label {
+ label: "Learn and prototype with\nGNOME technologies";
+ justify: center;
+ }
+ }
+
+ Box {
+ orientation: vertical;
+ homogeneous: true;
+ halign: center;
+
+ Box {
+ margin-bottom: 6;
+
+ Image {
+ icon-name: "update-symbolic";
+ margin-end: 12;
+ icon-size: normal;
+ }
+
+ Label {
+ label: _("Edit Style or UI to update the Preview");
+ }
+ }
+
+ Box {
+ margin-bottom: 6;
+
+ Image {
+ icon-name: "media-playback-start-symbolic";
+ margin-end: 12;
+ icon-size: normal;
+ }
+
+ Label {
+ label: _("Hit");
+ }
+
+ ShortcutsShortcut {
+ accelerator: "Return";
+ margin-start: 12;
+ }
+
+ Label {
+ label: _("to format and run Code");
+ }
+ }
+
+ Box {
+ margin-bottom: 6;
+
+ Image {
+ icon-name: "media-floppy-symbolic";
+ margin-end: 12;
+ icon-size: normal;
+ }
+
+ Label {
+ label: _("Changes are automatically saved and restored");
+ }
+ }
+
+ Box {
+ margin-bottom: 6;
+
+ Image {
+ icon-name: "library-symbolic";
+ margin-end: 12;
+ icon-size: normal;
+ }
+
+ Label {
+ label: _("Browse the Library for demos and examples");
+ }
+ }
+
+ Box {
+ margin-bottom: 6;
+
+ Image {
+ icon-name: "user-bookmarks-symbolic";
+ margin-end: 12;
+ icon-size: normal;
+ }
+
+ Label {
+ label: _("Checkout the Bookmarks menu to learn and get help");
+ }
+ }
+ }
+};
+}
+}
\ No newline at end of file
diff --git a/data/resources/ui/shortcuts.ui b/data/resources/ui/shortcuts.ui
deleted file mode 100644
index ef12f02..0000000
--- a/data/resources/ui/shortcuts.ui
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
diff --git a/data/resources/ui/window.ui b/data/resources/ui/window.ui
deleted file mode 100644
index 0b1f360..0000000
--- a/data/resources/ui/window.ui
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
- Hello world!
-
-
-
-
-
diff --git a/data/resources/ui/windows/add_new_game/add_new_game.blp b/data/resources/ui/windows/add_new_game/add_new_game.blp
new file mode 100644
index 0000000..9a1172a
--- /dev/null
+++ b/data/resources/ui/windows/add_new_game/add_new_game.blp
@@ -0,0 +1,46 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $ModManagerWindowAddNewGame : Adw.ApplicationWindow {
+ default-width: 600;
+ default-height: 400;
+ title: _("Add a new game");
+
+ content: Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar header_bar {
+ show-back-button: true;
+ }
+
+ content: Box {
+ orientation: vertical;
+ halign: center;
+ valign: center;
+
+ Label {
+ label: _("Chose a game to manage mods for");
+ margin-bottom: 30;
+ justify: center;
+ wrap: true;
+ styles ["title-1"]
+ }
+
+ DropDown games_dropdown {
+ margin-bottom: 30;
+ }
+
+ FileDialog mods_folder {
+ title: _("Chose a location where to install the mods");
+ }
+
+ Button chose_button {
+ label: _("Chose the location");
+ margin-bottom: 30;
+ }
+
+ Button complete_button {
+ label: _("Add game");
+ }
+ };
+ };
+}
\ No newline at end of file
diff --git a/data/resources/ui/windows/main/main.blp b/data/resources/ui/windows/main/main.blp
new file mode 100644
index 0000000..0a677b9
--- /dev/null
+++ b/data/resources/ui/windows/main/main.blp
@@ -0,0 +1,25 @@
+/*
+ Copyright (c) 2023 Tine Jozelj
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+
+using Gtk 4.0;
+using Adw 1;
+
+template $ModManagerWindowMain : Adw.ApplicationWindow {
+ default-width: 1000;
+ default-height: 800;
+ title: _("Mod Manager");
+}
\ No newline at end of file
diff --git a/data/resources/ui/windows/main/pages/games_and_mods.blp b/data/resources/ui/windows/main/pages/games_and_mods.blp
new file mode 100644
index 0000000..496fe8a
--- /dev/null
+++ b/data/resources/ui/windows/main/pages/games_and_mods.blp
@@ -0,0 +1,45 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $GamesAndMods: Adw.Bin {
+ Adw.NavigationSplitView {
+ sidebar: Adw.NavigationPage {
+ title: "Games";
+ tag: "sidebar";
+
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ }
+
+ content: Box {
+ Label {
+ label: "The Sims 4";
+ }
+ Label {
+ label: "The Sims 3";
+ }
+ Label {
+ label: "The Sims 2";
+ }
+ };
+ }
+ };
+ content: Adw.NavigationPage{
+ title: "Mods";
+ tag: "content";
+
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ }
+
+ content: Box {
+ Label {
+ label: "Mods";
+ }
+ };
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/data/resources/ui/windows/main/pages/welcome.blp b/data/resources/ui/windows/main/pages/welcome.blp
new file mode 100644
index 0000000..77e9305
--- /dev/null
+++ b/data/resources/ui/windows/main/pages/welcome.blp
@@ -0,0 +1,28 @@
+using Gtk 4.0;
+using Adw 1;
+
+template $Welcome: Adw.Bin {
+ Adw.ToolbarView {
+ [top]
+ Adw.HeaderBar {
+ }
+
+ content: Box {
+ orientation: vertical;
+ halign: center;
+ valign: center;
+
+ Label {
+ label: "No games added yet!";
+ justify: center;
+ wrap: true;
+ styles ["title-1"]
+ margin-bottom: 30;
+ }
+ Button add_new_game {
+ label: "Add new game";
+ styles ["suggested-action", "pill"]
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/api/base.rs b/src/api/base.rs
new file mode 100644
index 0000000..31894a3
--- /dev/null
+++ b/src/api/base.rs
@@ -0,0 +1,15 @@
+pub const API_URL: &str = "https://api.curseforge.com";
+
+pub fn get_curse_forge_client() -> Result {
+ let mut api_key_header =
+ reqwest::header::HeaderValue::from_str(crate::config::API_KEY).unwrap();
+ api_key_header.set_sensitive(true);
+
+ let mut headers = reqwest::header::HeaderMap::new();
+ headers.insert("x-api-key", api_key_header);
+
+ reqwest::blocking::Client::builder()
+ .user_agent(format!("dev.mnts.ModManager/{}", crate::config::VERSION))
+ .default_headers(headers)
+ .build()
+}
diff --git a/src/api/games.rs b/src/api/games.rs
new file mode 100644
index 0000000..e614a93
--- /dev/null
+++ b/src/api/games.rs
@@ -0,0 +1,46 @@
+use serde::Deserialize;
+
+use crate::api::*;
+
+#[derive(Deserialize, Debug)]
+struct Response {
+ data: Vec,
+ pagination: Pagination,
+}
+
+#[derive(Deserialize, Debug)]
+struct Game {
+ id: u32,
+ name: String,
+ slug: String,
+ dateModified: String,
+ assets: Assets,
+ status: u32,
+ apiStatus: u32,
+}
+
+#[derive(Deserialize, Debug)]
+struct Assets {
+ iconUrl: Option,
+ tileUrl: String,
+ coverUrl: Option,
+}
+
+#[derive(Deserialize, Debug)]
+struct Pagination {
+ index: u32,
+ pageSize: u32,
+ resultCount: u32,
+ totalCount: u32,
+}
+
+pub fn get_games() -> Vec {
+ let client = base::get_curse_forge_client().unwrap();
+ let response = client
+ .get(&format!("{}/v1/games", base::API_URL))
+ .send()
+ .unwrap();
+ let json: Response = response.json().unwrap();
+
+ return json.data.iter().map(|game| game.name.clone()).collect();
+}
diff --git a/src/api/mod.rs b/src/api/mod.rs
new file mode 100644
index 0000000..22936d9
--- /dev/null
+++ b/src/api/mod.rs
@@ -0,0 +1,5 @@
+mod base;
+pub use base::*;
+
+pub mod games;
+pub use games::*;
diff --git a/src/application.rs b/src/application.rs
index a59bd35..c08395b 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -1,50 +1,80 @@
-use gettextrs::gettext;
+/* application.rs
+ *
+ * Copyright 2023 Tine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+use adw::subclass::prelude::*;
+use gtk::{gdk, prelude::*};
+use gtk::{gio, glib};
use tracing::{debug, info};
-use gtk::prelude::*;
-use gtk::subclass::prelude::*;
-use gtk::{gdk, gio, glib};
-
-use crate::config::{APP_ID, PKGDATADIR, PROFILE, VERSION};
-use crate::window::ExampleApplicationWindow;
+use crate::config::APP_ID;
+use crate::config::VERSION;
+use crate::settings::ModManagerSettings;
+use crate::windows::main::ModManagerWindowMain;
+use crate::windows::main::Welcome;
mod imp {
+
use super::*;
- use glib::WeakRef;
- use std::cell::OnceCell;
#[derive(Debug, Default)]
- pub struct ExampleApplication {
- pub window: OnceCell>,
- }
+ pub struct ModManagerApplication {}
#[glib::object_subclass]
- impl ObjectSubclass for ExampleApplication {
- const NAME: &'static str = "ExampleApplication";
- type Type = super::ExampleApplication;
- type ParentType = gtk::Application;
+ impl ObjectSubclass for ModManagerApplication {
+ const NAME: &'static str = "ModManagerApplication";
+ type Type = super::ModManagerApplication;
+ type ParentType = adw::Application;
}
- impl ObjectImpl for ExampleApplication {}
+ impl ObjectImpl for ModManagerApplication {
+ fn constructed(&self) {
+ self.parent_constructed();
+ let obj = self.obj();
+ obj.set_accels_for_action("app.quit", &["q"]);
+ }
+ }
- impl ApplicationImpl for ExampleApplication {
+ impl ApplicationImpl for ModManagerApplication {
+ // We connect to the activate callback to create a window when the application
+ // has been launched. Additionally, this callback notifies us when the user
+ // tries to launch a "second instance" of the application. When they try
+ // to do that, we'll just present any existing window.
fn activate(&self) {
- debug!("GtkApplication::activate");
- self.parent_activate();
- let app = self.obj();
+ let application = self.obj();
+ // Get the current window or create one if necessary
+ let window = if let Some(window) = application.active_window() {
+ window
+ } else {
+ let settings = ModManagerSettings::default();
- if let Some(window) = self.window.get() {
- let window = window.upgrade().unwrap();
- window.present();
- return;
- }
+ let games = settings.games();
+ println!("Games: {:?}", games);
- let window = ExampleApplicationWindow::new(&app);
- self.window
- .set(window.downgrade())
- .expect("Window already set.");
+ // TODO: Figure our if show welcome or games_and_mods.
+ let welcome = Welcome::new();
+ let window = ModManagerWindowMain::new(&*application, &welcome.upcast());
+ window.upcast()
+ };
- app.main_window().present();
+ // Ask the window manager/compositor to present the window
+ window.present();
}
fn startup(&self) {
@@ -57,47 +87,35 @@ mod imp {
app.setup_css();
app.setup_gactions();
- app.setup_accels();
}
}
- impl GtkApplicationImpl for ExampleApplication {}
+ impl GtkApplicationImpl for ModManagerApplication {}
+ impl AdwApplicationImpl for ModManagerApplication {}
}
glib::wrapper! {
- pub struct ExampleApplication(ObjectSubclass)
- @extends gio::Application, gtk::Application,
- @implements gio::ActionMap, gio::ActionGroup;
+ pub struct ModManagerApplication(ObjectSubclass)
+ @extends gio::Application, gtk::Application, adw::Application,
+ @implements gio::ActionGroup, gio::ActionMap;
}
-impl ExampleApplication {
- fn main_window(&self) -> ExampleApplicationWindow {
- self.imp().window.get().unwrap().upgrade().unwrap()
+impl ModManagerApplication {
+ pub fn new(flags: &gio::ApplicationFlags) -> Self {
+ glib::Object::builder()
+ .property("application-id", APP_ID)
+ .property("flags", flags)
+ .build()
}
fn setup_gactions(&self) {
- // Quit
- let action_quit = gio::ActionEntry::builder("quit")
- .activate(move |app: &Self, _, _| {
- // This is needed to trigger the delete event and saving the window state
- app.main_window().close();
- app.quit();
- })
+ let quit_action = gio::ActionEntry::builder("quit")
+ .activate(move |app: &Self, _, _| app.quit())
.build();
-
- // About
- let action_about = gio::ActionEntry::builder("about")
- .activate(|app: &Self, _, _| {
- app.show_about_dialog();
- })
+ let about_action = gio::ActionEntry::builder("about")
+ .activate(move |app: &Self, _, _| app.show_about())
.build();
- self.add_action_entries([action_quit, action_about]);
- }
-
- // Sets up keyboard shortcuts
- fn setup_accels(&self) {
- self.set_accels_for_action("app.quit", &["q"]);
- self.set_accels_for_action("window.close", &["w"]);
+ self.add_action_entries([quit_action, about_action]);
}
fn setup_css(&self) {
@@ -112,38 +130,18 @@ impl ExampleApplication {
}
}
- fn show_about_dialog(&self) {
- let dialog = gtk::AboutDialog::builder()
- .logo_icon_name(APP_ID)
- // Insert your license of choice here
- // .license_type(gtk::License::MitX11)
- // Insert your website here
- // .website("https://gitlab.gnome.org/bilelmoussaoui/mod-manager/")
+ fn show_about(&self) {
+ let window = self.active_window().unwrap();
+ let about = adw::AboutWindow::builder()
+ .transient_for(&window)
+ .application_name("mod-manager")
+ .application_icon(APP_ID)
+ .developer_name("Tine Jozelj")
.version(VERSION)
- .transient_for(&self.main_window())
- .translator_credits(gettext("translator-credits"))
- .modal(true)
- .authors(vec!["Tine Jozelj"])
- .artists(vec!["Tine Jozelj"])
+ .developers(vec!["Tine Jozelj "])
+ .copyright("© 2023 Tine Jozelj and other developers")
.build();
- dialog.present();
- }
-
- pub fn run(&self) -> glib::ExitCode {
- info!("Mod Manager ({})", APP_ID);
- info!("Version: {} ({})", VERSION, PROFILE);
- info!("Datadir: {}", PKGDATADIR);
-
- ApplicationExtManual::run(self)
- }
-}
-
-impl Default for ExampleApplication {
- fn default() -> Self {
- glib::Object::builder()
- .property("application-id", APP_ID)
- .property("resource-base-path", "/dev/mnts/ModManager/")
- .build()
+ about.present();
}
}
diff --git a/src/components/mod.rs b/src/components/mod.rs
new file mode 100644
index 0000000..1732d08
--- /dev/null
+++ b/src/components/mod.rs
@@ -0,0 +1,2 @@
+pub mod mods_list;
+pub use mods_list::*;
diff --git a/src/components/mods_list.rs b/src/components/mods_list.rs
new file mode 100644
index 0000000..005bf3b
--- /dev/null
+++ b/src/components/mods_list.rs
@@ -0,0 +1,64 @@
+/* welcome.rs
+ *
+ * Copyright 2023 Tine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+use adw::subclass::prelude::*;
+use gtk::{gio, glib};
+use gtk::{glib::clone, prelude::*};
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/ui/components/mods_list.ui")]
+ pub struct ModsList {}
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for ModsList {
+ const NAME: &'static str = "ModsList";
+ type Type = super::ModsList;
+ type ParentType = adw::NavigationPage;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for ModsList {
+ fn constructed(&self) {}
+ }
+ impl WidgetImpl for ModsList {}
+ impl NavigationPageImpl for ModsList {}
+}
+
+glib::wrapper! {
+ pub struct ModsList(ObjectSubclass)
+ @extends gtk::Widget, gtk::Buildable, adw::NavigationPage,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl ModsList {
+ pub fn new() -> Self {
+ glib::Object::builder().build()
+ }
+}
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..b69f07d
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,9 @@
+pub const APP_ID: &str = "dev.mnts.ModManager.Devel";
+pub const GETTEXT_PACKAGE: &str = "mod-manager";
+pub const LOCALEDIR: &str = "/app/share/locale";
+pub const PKGDATADIR: &str = "/app/share/mod-manager";
+pub const PROFILE: &str = "Devel";
+pub const RESOURCES_FILE: &str = concat!("/app/share/mod-manager", "/resources.gresource");
+pub const VERSION: &str = "0.1.0-be1d5b0";
+
+pub const API_KEY: &str = "$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2";
diff --git a/src/config.rs.in b/src/config.rs.in
index 699897f..f5207c3 100644
--- a/src/config.rs.in
+++ b/src/config.rs.in
@@ -5,3 +5,5 @@ pub const PKGDATADIR: &str = @PKGDATADIR@;
pub const PROFILE: &str = @PROFILE@;
pub const RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/resources.gresource");
pub const VERSION: &str = @VERSION@;
+
+pub const API_KEY: &str = @API_KEY@;
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 2281216..2c20699 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,32 +1,53 @@
-mod config {
- #![allow(dead_code)]
+/*
+Copyright (c) 2023 Tine Jozelj
- include!(concat!(env!("CODEGEN_BUILD_DIR"), "/config.rs"));
-}
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+mod api;
mod application;
-mod window;
+mod components;
+mod config;
+mod settings;
+mod windows;
-use gettextrs::{gettext, LocaleCategory};
+use self::application::ModManagerApplication;
+
+use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
+use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
+use gtk::prelude::*;
use gtk::{gio, glib};
-use self::application::ExampleApplication;
-use self::config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
-
fn main() -> glib::ExitCode {
- // Initialize logger
- tracing_subscriber::fmt::init();
+ // Set up gettext translations
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
+ .expect("Unable to set the text domain encoding");
+ textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
- // Prepare i18n
- gettextrs::setlocale(LocaleCategory::LcAll, "");
- gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
- gettextrs::textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
+ // Load resources
+ let resources = gio::Resource::load(RESOURCES_FILE).expect("Could not load resources");
+ gio::resources_register(&resources);
- glib::set_application_name(&gettext("Mod Manager"));
+ // Create a new GtkApplication. The application manages our main loop,
+ // application windows, integration with the window manager/compositor, and
+ // desktop features such as file opening and single-instance applications.
+ let app = ModManagerApplication::new(&gio::ApplicationFlags::empty());
- let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file");
- gio::resources_register(&res);
-
- let app = ExampleApplication::default();
+ // Run the application. This function will block until the application
+ // exits. Upon return, we have our exit code to return to the shell. (This
+ // is the code you see when you do `echo $?` after running a command in a
+ // terminal.
app.run()
}
diff --git a/src/meson.build b/src/meson.build
index 75c7a75..a3ec4d4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -5,12 +5,21 @@ global_conf.set_quoted('PROFILE', profile)
global_conf.set_quoted('VERSION', version + version_suffix)
global_conf.set_quoted('GETTEXT_PACKAGE', gettext_package)
global_conf.set_quoted('LOCALEDIR', localedir)
+global_conf.set_quoted('API_KEY', '$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2')
config = configure_file(
input: 'config.rs.in',
output: 'config.rs',
configuration: global_conf
)
+# Copy the config.rs output to the source directory.
+run_command(
+ 'cp',
+ meson.project_build_root() / 'src' / 'config.rs',
+ meson.project_source_root() / 'src' / 'config.rs',
+ check: true
+)
+
cargo_options = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ]
cargo_options += [ '--target-dir', meson.project_build_root() / 'src' ]
diff --git a/src/mod.rs b/src/mod.rs
new file mode 100644
index 0000000..b28922a
--- /dev/null
+++ b/src/mod.rs
@@ -0,0 +1,5 @@
+mod base;
+pub use base::*;
+
+pub mod games;
+pub use games::*;
\ No newline at end of file
diff --git a/src/mods_list.rs b/src/mods_list.rs
new file mode 100644
index 0000000..e8f6f08
--- /dev/null
+++ b/src/mods_list.rs
@@ -0,0 +1,66 @@
+/* welcome.rs
+ *
+ * Copyright 2023 Tine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+use adw::subclass::prelude::*;
+use gtk::{gio, glib};
+use gtk::{glib::clone, prelude::*};
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/components/mods_list.ui")]
+ pub struct ModsList {
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for ModsList {
+ const NAME: &'static str = "ModsList";
+ type Type = super::ModsList;
+ type ParentType = adw::NavigationPage;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for ModsList {
+ fn constructed(&self) {
+ }
+ }
+ impl WidgetImpl for ModsList {}
+ impl NavigationPageImpl for ModsList {}
+}
+
+glib::wrapper! {
+ pub struct ModsList(ObjectSubclass)
+ @extends gtk::Widget, gtk::Buildable, adw::NavigationPage,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl ModsList {
+ pub fn new() -> Self {
+ glib::Object::builder().build()
+ }
+}
diff --git a/src/settings.rs b/src/settings.rs
new file mode 100644
index 0000000..9a23c3c
--- /dev/null
+++ b/src/settings.rs
@@ -0,0 +1,20 @@
+use gio::glib;
+use gsettings_macro::gen_settings;
+use gtk::gio;
+use std::collections::HashMap;
+
+use crate::config::APP_ID;
+
+#[gen_settings(file = "./data/dev.mnts.ModManager.gschema.xml.in")]
+#[gen_settings_define(
+ key_name = "games",
+ arg_type = "HashMap",
+ ret_type = "HashMap"
+)]
+pub struct ModManagerSettings;
+
+impl Default for ModManagerSettings {
+ fn default() -> Self {
+ Self::new(APP_ID)
+ }
+}
diff --git a/src/window.rs b/src/window.rs
deleted file mode 100644
index 3fa99fa..0000000
--- a/src/window.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-use gtk::prelude::*;
-use gtk::subclass::prelude::*;
-use gtk::{gio, glib};
-
-use crate::application::ExampleApplication;
-use crate::config::{APP_ID, PROFILE};
-
-mod imp {
- use super::*;
-
- #[derive(Debug, gtk::CompositeTemplate)]
- #[template(resource = "/dev/mnts/ModManager/ui/window.ui")]
- pub struct ExampleApplicationWindow {
- #[template_child]
- pub headerbar: TemplateChild,
- pub settings: gio::Settings,
- }
-
- impl Default for ExampleApplicationWindow {
- fn default() -> Self {
- Self {
- headerbar: TemplateChild::default(),
- settings: gio::Settings::new(APP_ID),
- }
- }
- }
-
- #[glib::object_subclass]
- impl ObjectSubclass for ExampleApplicationWindow {
- const NAME: &'static str = "ExampleApplicationWindow";
- type Type = super::ExampleApplicationWindow;
- type ParentType = gtk::ApplicationWindow;
-
- fn class_init(klass: &mut Self::Class) {
- klass.bind_template();
- }
-
- // You must call `Widget`'s `init_template()` within `instance_init()`.
- fn instance_init(obj: &glib::subclass::InitializingObject) {
- obj.init_template();
- }
- }
-
- impl ObjectImpl for ExampleApplicationWindow {
- fn constructed(&self) {
- self.parent_constructed();
- let obj = self.obj();
-
- // Devel Profile
- if PROFILE == "Devel" {
- obj.add_css_class("devel");
- }
-
- // Load latest window state
- obj.load_window_size();
- }
-
- fn dispose(&self) {
- self.dispose_template();
- }
- }
-
- impl WidgetImpl for ExampleApplicationWindow {}
- impl WindowImpl for ExampleApplicationWindow {
- // Save window state on delete event
- fn close_request(&self) -> glib::Propagation {
- if let Err(err) = self.obj().save_window_size() {
- tracing::warn!("Failed to save window state, {}", &err);
- }
-
- // Pass close request on to the parent
- self.parent_close_request()
- }
- }
-
- impl ApplicationWindowImpl for ExampleApplicationWindow {}
-}
-
-glib::wrapper! {
- pub struct ExampleApplicationWindow(ObjectSubclass)
- @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow,
- @implements gio::ActionMap, gio::ActionGroup, gtk::Root;
-}
-
-impl ExampleApplicationWindow {
- pub fn new(app: &ExampleApplication) -> Self {
- glib::Object::builder().property("application", app).build()
- }
-
- fn save_window_size(&self) -> Result<(), glib::BoolError> {
- let imp = self.imp();
-
- let (width, height) = self.default_size();
-
- imp.settings.set_int("window-width", width)?;
- imp.settings.set_int("window-height", height)?;
-
- imp.settings
- .set_boolean("is-maximized", self.is_maximized())?;
-
- Ok(())
- }
-
- fn load_window_size(&self) {
- let imp = self.imp();
-
- let width = imp.settings.int("window-width");
- let height = imp.settings.int("window-height");
- let is_maximized = imp.settings.boolean("is-maximized");
-
- self.set_default_size(width, height);
-
- if is_maximized {
- self.maximize();
- }
- }
-}
diff --git a/src/windows/add_new_game/add_new_game.rs b/src/windows/add_new_game/add_new_game.rs
new file mode 100644
index 0000000..ab996c7
--- /dev/null
+++ b/src/windows/add_new_game/add_new_game.rs
@@ -0,0 +1,96 @@
+/* welcome.rs
+ *
+ * Copyright 2023 Tine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+use adw::subclass::prelude::*;
+use glib::clone;
+use gtk::prelude::*;
+use gtk::{gio, glib};
+
+use crate::api::*;
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/ui/windows/add_new_game/add_new_game.ui")]
+ pub struct ModManagerWindowAddNewGame {
+ #[template_child]
+ pub complete_button: TemplateChild,
+
+ #[template_child]
+ pub games_dropdown: TemplateChild,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for ModManagerWindowAddNewGame {
+ const NAME: &'static str = "ModManagerWindowAddNewGame";
+ type Type = super::ModManagerWindowAddNewGame;
+ type ParentType = adw::ApplicationWindow;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for ModManagerWindowAddNewGame {}
+ impl WidgetImpl for ModManagerWindowAddNewGame {}
+ impl WindowImpl for ModManagerWindowAddNewGame {}
+ impl ApplicationWindowImpl for ModManagerWindowAddNewGame {}
+ impl AdwApplicationWindowImpl for ModManagerWindowAddNewGame {}
+}
+
+glib::wrapper! {
+ pub struct ModManagerWindowAddNewGame(ObjectSubclass)
+ @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl ModManagerWindowAddNewGame {
+ pub fn new() -> Self {
+ glib::Object::builder().build()
+ }
+
+ pub fn setup(&self) {
+ let games = games::get_games();
+ let games_strs: Vec<&str> = games.iter().map(|s| s.as_str()).collect();
+ let games_list = >k::StringList::new(&games_strs);
+
+ let complete_button = &imp::ModManagerWindowAddNewGame::from_obj(self).complete_button;
+ let games_dropdown = &imp::ModManagerWindowAddNewGame::from_obj(self).games_dropdown;
+
+ games_dropdown.set_property("model", games_list);
+
+ let instance = self;
+
+ complete_button.connect_clicked(clone!(@strong instance => move |_| {
+ //let selected_game = games_dropdown.selected_item();
+
+ println!("complete button clicked");
+
+ //if let Some(selected_game) = selected_game {
+ instance.hide()
+ //}
+ }));
+ }
+}
diff --git a/src/windows/add_new_game/mod.rs b/src/windows/add_new_game/mod.rs
new file mode 100644
index 0000000..183070c
--- /dev/null
+++ b/src/windows/add_new_game/mod.rs
@@ -0,0 +1,2 @@
+pub mod add_new_game;
+pub use add_new_game::*;
diff --git a/src/windows/main/main.rs b/src/windows/main/main.rs
new file mode 100644
index 0000000..24890a0
--- /dev/null
+++ b/src/windows/main/main.rs
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2023 Tine Jozelj
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+use adw::subclass::prelude::*;
+use gtk::prelude::*;
+use gtk::{gio, glib};
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/ui/windows/main/main.ui")]
+ pub struct ModManagerWindowMain {}
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for ModManagerWindowMain {
+ const NAME: &'static str = "ModManagerWindowMain";
+ type Type = super::ModManagerWindowMain;
+ type ParentType = adw::ApplicationWindow;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for ModManagerWindowMain {
+ fn constructed(&self) {
+ self.parent_constructed();
+ }
+ }
+ impl WidgetImpl for ModManagerWindowMain {}
+ impl WindowImpl for ModManagerWindowMain {}
+ impl ApplicationWindowImpl for ModManagerWindowMain {}
+ impl AdwApplicationWindowImpl for ModManagerWindowMain {}
+}
+
+glib::wrapper! {
+ pub struct ModManagerWindowMain(ObjectSubclass)
+ @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl ModManagerWindowMain {
+ pub fn new>(application: &P, content: >k::Widget) -> Self {
+ glib::Object::builder()
+ .property("application", application)
+ .property("content", content)
+ .build()
+ }
+}
diff --git a/src/windows/main/mod.rs b/src/windows/main/mod.rs
new file mode 100644
index 0000000..3bda0e1
--- /dev/null
+++ b/src/windows/main/mod.rs
@@ -0,0 +1,5 @@
+pub mod main;
+pub use main::*;
+
+pub mod pages;
+pub use pages::*;
diff --git a/src/windows/main/pages/games_and_mods.rs b/src/windows/main/pages/games_and_mods.rs
new file mode 100644
index 0000000..33d747d
--- /dev/null
+++ b/src/windows/main/pages/games_and_mods.rs
@@ -0,0 +1,60 @@
+/*
+Copyright (c) 2023 Tine Jozelj
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+use adw::subclass::prelude::*;
+use gtk::prelude::*;
+use gtk::{gio, glib};
+
+mod imp {
+
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/ui/windows/main/pages/games_and_mods.ui")]
+ pub struct GamesAndMods {}
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for GamesAndMods {
+ const NAME: &'static str = "GamesAndMods";
+ type Type = super::GamesAndMods;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for GamesAndMods {}
+ impl WidgetImpl for GamesAndMods {}
+ impl BinImpl for GamesAndMods {}
+}
+
+glib::wrapper! {
+ pub struct GamesAndMods(ObjectSubclass)
+ @extends gtk::Widget, adw::NavigationSplitView,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl GamesAndMods {
+ pub fn new() -> Self {
+ glib::Object::builder().build()
+ }
+}
diff --git a/src/windows/main/pages/mod.rs b/src/windows/main/pages/mod.rs
new file mode 100644
index 0000000..a9a7d2a
--- /dev/null
+++ b/src/windows/main/pages/mod.rs
@@ -0,0 +1,5 @@
+pub mod games_and_mods;
+pub use games_and_mods::*;
+
+pub mod welcome;
+pub use welcome::*;
diff --git a/src/windows/main/pages/welcome.rs b/src/windows/main/pages/welcome.rs
new file mode 100644
index 0000000..2ed9f4a
--- /dev/null
+++ b/src/windows/main/pages/welcome.rs
@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2023 Tine Jozelj
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+use adw::subclass::prelude::*;
+use gtk::prelude::*;
+use gtk::{gio, glib};
+
+use crate::windows::ModManagerWindowAddNewGame;
+
+mod imp {
+
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/dev/mnts/ModManager/ui/windows/main/pages/welcome.ui")]
+ pub struct Welcome {
+ #[template_child]
+ pub add_new_game: gtk::TemplateChild,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for Welcome {
+ const NAME: &'static str = "Welcome";
+ type Type = super::Welcome;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for Welcome {
+ fn constructed(&self) {
+ self.parent_constructed();
+
+ self.add_new_game.connect_clicked(|_| {
+ let welcome = ModManagerWindowAddNewGame::new();
+ welcome.setup();
+ welcome.set_modal(true);
+ welcome.present();
+ });
+ }
+ }
+ impl WidgetImpl for Welcome {}
+ impl BinImpl for Welcome {}
+}
+
+glib::wrapper! {
+ pub struct Welcome(ObjectSubclass)
+ @extends gtk::Widget, adw::ToolbarView,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl Welcome {
+ pub fn new() -> Self {
+ glib::Object::builder().build()
+ }
+}
diff --git a/src/windows/mod.rs b/src/windows/mod.rs
new file mode 100644
index 0000000..be8c4ba
--- /dev/null
+++ b/src/windows/mod.rs
@@ -0,0 +1,5 @@
+pub mod main;
+pub use main::*;
+
+pub mod add_new_game;
+pub use add_new_game::*;