diff --git a/.gitignore b/.gitignore
index 69cb356..5acaefe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,8 @@
/captures
.externalNativeBuild
.idea/*
+
+
+# Added by cargo
+
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..a76249b
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,2068 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+
+[[package]]
+name = "cairo-rs"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b01fe135c0bd16afe262b6dea349bd5ea30e6de50708cec639aae7c5c14cc7e4"
+dependencies = [
+ "bitflags",
+ "cairo-sys-rs",
+ "glib",
+ "libc",
+]
+
+[[package]]
+name = "cairo-sys-rs"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06c28280c6b12055b5e39e4554271ae4e6630b27c0da9148c4cf6485fc6d245c"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-expr"
+version = "0.20.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368"
+dependencies = [
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[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 = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "gdk-pixbuf"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "debb0d39e3cdd84626edfd54d6e4a6ba2da9a0ef2e796e691c4e9f8646fda00c"
+dependencies = [
+ "gdk-pixbuf-sys",
+ "gio",
+ "glib",
+ "libc",
+]
+
+[[package]]
+name = "gdk-pixbuf-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd95ad50b9a3d2551e25dd4f6892aff0b772fe5372d84514e9d0583af60a0ce7"
+dependencies = [
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gdk4"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "756564212bbe4a4ce05d88ffbd2582581ac6003832d0d32822d0825cca84bfbf"
+dependencies = [
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk4-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk4-sys"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6d4e5b3ccf591826a4adcc83f5f57b4e59d1925cb4bf620b0d645f79498b034"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasip2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gio"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5ff48bf600c68b476e61dc6b7c762f2f4eb91deef66583ba8bb815c30b5811a"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "gio-sys",
+ "glib",
+ "libc",
+ "pin-project-lite",
+ "smallvec",
+]
+
+[[package]]
+name = "gio-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0071fe88dba8e40086c8ff9bbb62622999f49628344b1d1bf490a48a29d80f22"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "glib"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b"
+dependencies = [
+ "bitflags",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys",
+ "glib-macros",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "memchr",
+ "smallvec",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf59b675301228a696fe01c3073974643365080a76cc3ed5bc2cbc466ad87f17"
+dependencies = [
+ "heck",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d95e1a3a19ae464a7286e14af9a90683c64d70c02532d88d87ce95056af3e6c"
+dependencies = [
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gobject-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dca35da0d19a18f4575f3cb99fe1c9e029a2941af5662f326f738a21edaf294"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "graphene-rs"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2730030ac9db663fd8bfe1e7093742c1cafb92db9c315c9417c29032341fe2f9"
+dependencies = [
+ "glib",
+ "graphene-sys",
+ "libc",
+]
+
+[[package]]
+name = "graphene-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915e32091ea9ad241e4b044af62b7351c2d68aeb24f489a0d7f37a0fc484fd93"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gsk4"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e755de9d8c5896c5beaa028b89e1969d067f1b9bf1511384ede971f5983aa153"
+dependencies = [
+ "cairo-rs",
+ "gdk4",
+ "glib",
+ "graphene-rs",
+ "gsk4-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gsk4-sys"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ce91472391146f482065f1041876d8f869057b195b95399414caa163d72f4f7"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk4-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "gtk4"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acb21d53cfc6f7bfaf43549731c43b67ca47d87348d81c8cfc4dcdd44828e1a4"
+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.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ccfb5a14a3d941244815d5f8101fa12d4577b59cc47245778d8d907b0003e42"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "gtk4-sys"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "842577fe5a1ee15d166cd3afe804ce0cab6173bc789ca32e21308834f20088dd"
+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 = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "http"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hyper"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "pin-utils",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+ "webpki-roots",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
+
+[[package]]
+name = "icu_properties"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
+
+[[package]]
+name = "icu_provider"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "iri-string"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
+
+[[package]]
+name = "js-sys"
+version = "0.3.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libadwaita"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb09e12bf8f73342b3315c839d0a7668cc0ccebd78490c49fec48bab15d5484b"
+dependencies = [
+ "gdk4",
+ "gio",
+ "glib",
+ "gtk4",
+ "libadwaita-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "libadwaita-sys"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d7f94227ba87eb596fecada2491f04e357d507324142f77bf76d9e6be4a3e31"
+dependencies = [
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "gtk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.183"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+
+[[package]]
+name = "libredox"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "litemap"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "mio"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "next-companion"
+version = "0.1.0"
+dependencies = [
+ "dirs",
+ "gtk4",
+ "libadwaita",
+ "reqwest",
+ "serde_json",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "pango"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d1d85e2078077a065bb7fc072783d5bcd4e51b379f22d67107d0a16937eb69"
+dependencies = [
+ "gio",
+ "glib",
+ "libc",
+ "pango-sys",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4f06627d36ed5ff303d2df65211fc2e52ba5b17bf18dd80ff3d9628d6e06cfd"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[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.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.4",
+ "lru-slab",
+ "rand",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.18",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.17",
+ "libredox",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "webpki-roots",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
+dependencies = [
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
+dependencies = [
+ "serde_core",
+]
+
+[[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 = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "socket2"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "system-deps"
+version = "7.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f"
+dependencies = [
+ "cfg-expr",
+ "heck",
+ "pkg-config",
+ "toml",
+ "version-compare",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
+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.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.9.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime 0.7.5+spec-1.1.0",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.5+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "1.0.0+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.4+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2"
+dependencies = [
+ "indexmap",
+ "toml_datetime 1.0.0+spec-1.1.0",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.9+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.6+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "version-compare"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
+
+[[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.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[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.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.1",
+ "windows_aarch64_msvc 0.53.1",
+ "windows_i686_gnu 0.53.1",
+ "windows_i686_gnullvm 0.53.1",
+ "windows_i686_msvc 0.53.1",
+ "windows_x86_64_gnu 0.53.1",
+ "windows_x86_64_gnullvm 0.53.1",
+ "windows_x86_64_msvc 0.53.1",
+]
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+
+[[package]]
+name = "winnow"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+
+[[package]]
+name = "writeable"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
+
+[[package]]
+name = "yoke"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..dbc3fc0
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "next-companion"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+gtk = { package = "gtk4", version = "0.10" }
+adw = { package = "libadwaita", version = "0.8", features = ["v1_6"] }
+reqwest = { version = "0.12", features = ["blocking", "rustls-tls"], default-features = false }
+serde_json = "1"
+dirs = "5"
diff --git a/app/.gitignore b/app/.gitignore
deleted file mode 100644
index 796b96d..0000000
--- a/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index c8c10d8..0000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,29 +0,0 @@
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 28
- defaultConfig {
- applicationId "com.example.hochi.nextcompanion"
- minSdkVersion 15
- targetSdkVersion 28
- versionCode 8
- versionName "0.1.7.1"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:28.0.0'
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
- implementation 'com.android.support:design:28.0.0'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
-}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
deleted file mode 100644
index f1b4245..0000000
--- a/app/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/app/src/androidTest/java/com/example/hochi/nextcompanion/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/hochi/nextcompanion/ExampleInstrumentedTest.java
deleted file mode 100644
index 2759dd6..0000000
--- a/app/src/androidTest/java/com/example/hochi/nextcompanion/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.example.hochi.nextcompanion", appContext.getPackageName());
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 5637d70..0000000
--- a/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hochi/nextcompanion/AsyncTaskCallbacks.java b/app/src/main/java/com/example/hochi/nextcompanion/AsyncTaskCallbacks.java
deleted file mode 100644
index 2099b15..0000000
--- a/app/src/main/java/com/example/hochi/nextcompanion/AsyncTaskCallbacks.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-interface AsyncTaskCallbacks {
- void onTaskComplete(T response);
-}
diff --git a/app/src/main/java/com/example/hochi/nextcompanion/LoginActivity.java b/app/src/main/java/com/example/hochi/nextcompanion/LoginActivity.java
deleted file mode 100644
index 1ff8e6b..0000000
--- a/app/src/main/java/com/example/hochi/nextcompanion/LoginActivity.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.TargetApi;
-
-import android.content.SharedPreferences;
-import android.support.v7.app.AppCompatActivity;
-
-import android.os.Build;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import org.json.JSONObject;
-
-
-/**
- * A login screen that offers login via phone number/pin.
- */
-public class LoginActivity extends AppCompatActivity implements AsyncTaskCallbacks {
-
- /**
- * Keep track of the login task to ensure we can cancel it if requested.
- */
- private RequestHandler mAuthTask = null;
-
- // UI references.
- private TextView mPhoneView;
- private EditText mPinView;
- private View mProgressView;
- private View mLoginFormView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_login);
- // Set up the login form.
- mPhoneView = findViewById(R.id.phone);
-
- mPinView = findViewById(R.id.pin);
- mPinView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
- if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
- attemptLogin();
- return true;
- }
- return false;
- }
- });
-
- Button mPhoneSignInButton = findViewById(R.id.phone_sign_in_button);
- mPhoneSignInButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- attemptLogin();
- }
- });
-
- mLoginFormView = findViewById(R.id.login_form);
- mProgressView = findViewById(R.id.login_progress);
- }
-
- /**
- * Attempts to sign in or register the account specified by the login form.
- * If there are form errors (invalid phone number, missing fields, etc.), the
- * errors are presented and no actual login attempt is made.
- */
- private void attemptLogin() {
- if (mAuthTask != null) {
- return;
- }
-
- // Reset errors.
- mPhoneView.setError(null);
- mPinView.setError(null);
-
- // Store values at the time of the login attempt.
- String phone = mPhoneView.getText().toString();
- String pin = mPinView.getText().toString();
- String[] credentials = {
- "apikey=", getString(R.string.apikey),
- "mobile=", mPhoneView.getText().toString(),
- "pin=", mPinView.getText().toString()
- };
-
- boolean cancel = false;
- View focusView = null;
-
- // Check for a valid pin, if the user entered one.
- if (TextUtils.isEmpty(pin)) {
- mPinView.setError(getString(R.string.error_field_required));
- focusView = mPinView;
- cancel = true;
- }
-
- // Check for a valid phone address.
- if (TextUtils.isEmpty(phone)) {
- mPhoneView.setError(getString(R.string.error_field_required));
- focusView = mPhoneView;
- cancel = true;
- }
-
- if (cancel) {
- // There was an error; don't attempt login and focus the first
- // form field with an error.
- focusView.requestFocus();
- } else {
- // Show a progress spinner, and kick off a background task to
- // perform the user login attempt.
- showProgress(true);
- mAuthTask = new RequestHandler(this, "POST",
- "api/login.json", credentials);
- mAuthTask.execute((Void) null);
- }
- }
-
- /**
- * Shows the progress UI and hides the login form.
- */
- @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
- private void showProgress(final boolean show) {
- // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
- // for very easy animations. If available, use these APIs to fade-in
- // the progress spinner.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
- int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
-
- mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
- mLoginFormView.animate().setDuration(shortAnimTime).alpha(
- show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
- }
- });
-
- mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
- mProgressView.animate().setDuration(shortAnimTime).alpha(
- show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
- }
- });
- } else {
- // The ViewPropertyAnimator APIs are not available, so simply show
- // and hide the relevant UI components.
- mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
- mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
- }
- }
-
- @Override
- public void onTaskComplete(String response) {
- //Callback called when RequestHandler finished request
- if (!response.isEmpty()) {
- try {
- JSONObject jObject = new JSONObject(response);
- JSONObject userObject = jObject.getJSONObject("user");
- String loginkey = userObject.getString("loginkey");
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putString("loginKey", loginkey);
- editor.apply();
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- finish();
- } else {
- mPinView.setError(getString(R.string.error_incorrect_pin));
- mPinView.requestFocus();
- }
- }
-}
-
diff --git a/app/src/main/java/com/example/hochi/nextcompanion/MainActivity.java b/app/src/main/java/com/example/hochi/nextcompanion/MainActivity.java
deleted file mode 100644
index 5ec0d77..0000000
--- a/app/src/main/java/com/example/hochi/nextcompanion/MainActivity.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.design.widget.FloatingActionButton;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.View;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-
-public class MainActivity extends AppCompatActivity implements AsyncTaskCallbacks {
- private RequestHandler getBikesTask = null;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- //now this "every android activity" stuff
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- final Context context = this;
-
- //Floating Button
- FloatingActionButton fab = findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(context, RentActivity.class);
- startActivity(intent);
- }
- });
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- //pre-condition: Is there a login key?
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- String defaultValue = "nokey";
- String loginKey = sharedPref.getString("loginKey", defaultValue);
- //if not, go to LoginActivity
- if (loginKey.equals("nokey")) {
- Intent intent = new Intent(this, LoginActivity.class);
- startActivity(intent);
- }
- else {
- reloadBikeList();
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
-
-
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_logout) {
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.remove("loginkey");
- editor.apply();
- Intent intent = new Intent(this, LoginActivity.class);
- startActivity(intent);
- }
-
- if (id == R.id.action_map) {
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.map_url)));
- startActivity(browserIntent);
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- protected void reloadBikeList() {
- //get loginkey
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- String defaultValue = "nokey";
- String loginKey = sharedPref.getString("loginKey", defaultValue);
-
- String[] params = {
- "apikey=", getString(R.string.apikey),
- "loginkey=", loginKey
- };
-
- getBikesTask = new RequestHandler(this, "POST",
- "api/getOpenRentals.json", params);
- getBikesTask.execute((Void) null);
- }
-
- @Override
- public void onTaskComplete(String response) {
- //Callback called when RequestHandler finished request
- final Context context = this;
- if (!response.isEmpty()) {
- final ArrayList list = new ArrayList<>();
- try {
- JSONObject jObject = new JSONObject(response);
- JSONArray bikesArray = jObject.getJSONArray("rentalCollection");
- for (int i = 0; i < bikesArray.length(); i++) {
- String entry;
- JSONObject bike = bikesArray.getJSONObject(i);
- entry = "Bike " + bike.getString("bike")
- + " with lock code " + bike.getString("code");
- list.add(entry);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- //Create and fill list
- final ListView listview = findViewById(R.id.listview);
- final ArrayAdapter adapter = new ArrayAdapter<>(this,
- android.R.layout.simple_list_item_1, list);
- listview.setAdapter(adapter);
-
- //Print indicator if empty
- TextView tv = findViewById(R.id.noBikes);
- if(list.isEmpty()) tv.setVisibility(View.VISIBLE);
- else tv.setVisibility(View.INVISIBLE);
-
- try {
- final JSONObject jObject = new JSONObject(response);
- final JSONArray bikesArray = jObject.getJSONArray("rentalCollection");
- listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> parent, final View view, int position, long id) {
- Intent intent = new Intent(context, ReturnActivity.class);
- try {
- JSONObject bike = bikesArray.getJSONObject(position);
- String bID = bike.getString("bike");
- String stID = bike.getString("start_place");
- String lockE = bike.getString("electric_lock");
- String[] bikeArray = {bID, stID, lockE};
- intent.putExtra("bike", bikeArray);
- startActivity(intent);
- }
- catch (JSONException e) {
- e.printStackTrace();
- }
- }
-
- });
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- else {
- //TODO: implement error handling
- }
- }
-}
diff --git a/app/src/main/java/com/example/hochi/nextcompanion/RentActivity.java b/app/src/main/java/com/example/hochi/nextcompanion/RentActivity.java
deleted file mode 100644
index 79c7fb4..0000000
--- a/app/src/main/java/com/example/hochi/nextcompanion/RentActivity.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import android.content.SharedPreferences;
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class RentActivity extends AppCompatActivity implements AsyncTaskCallbacks {
- private RequestHandler rentRequestTask = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_rent);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- Button mRentSubmitButton = findViewById(R.id.rent_submit_button);
- mRentSubmitButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- rentRequest();
- }
- });
- }
-
- void rentRequest() {
- //Prepare request to rent bike
- TextView mBikeInput;
- mBikeInput = findViewById(R.id.bike_id);
- String bikeID = mBikeInput.getText().toString();
- //get loginkey
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- String defaultValue = "nokey";
- String loginKey = sharedPref.getString("loginKey", defaultValue);
-
- String[] params = {
- "apikey=", getString(R.string.apikey),
- "loginkey=", loginKey,
- "bike=", bikeID
- };
-
- rentRequestTask = new RequestHandler(this, "POST",
- "api/rent.json", params);
- rentRequestTask.execute((Void) null);
- }
-
- @Override
- public void onTaskComplete(String response) {
- //get back to main activity
- //TODO: *any* response handling
- finish();
- }
-}
diff --git a/app/src/main/java/com/example/hochi/nextcompanion/RequestHandler.java b/app/src/main/java/com/example/hochi/nextcompanion/RequestHandler.java
deleted file mode 100644
index 2476e63..0000000
--- a/app/src/main/java/com/example/hochi/nextcompanion/RequestHandler.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import android.os.AsyncTask;
-
-import java.io.BufferedReader;
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-
-public class RequestHandler extends AsyncTask {
-
- private String mHTTPmethod;
- private String mEndpoint;
- private AsyncTaskCallbacks callback;
- private String[] mCredentials;
-
- RequestHandler(AsyncTaskCallbacks act, String HTTPmethod,
- String endpoint, String[] credentials) {
- mHTTPmethod = HTTPmethod;
- mEndpoint = endpoint;
- mCredentials = credentials;
- callback = act;
- }
-
- @Override
- protected String doInBackground(Void... params) {
- StringBuilder response = new StringBuilder();
- StringBuilder urlParameters = new StringBuilder();
- int i=0;
- while (i {
- private String[] bikeArray;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_return);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
-
- Intent intent = getIntent();
- bikeArray = intent.getStringArrayExtra("bike");
-
- //if GPS and electric lock, show the instruction
- TextView tv = findViewById(R.id.gps_info);
- LinearLayout la = findViewById(R.id.return_form_container);
- if(bikeArray[2].equals("true")) {
- tv.setVisibility(View.VISIBLE);
- la.setVisibility(View.INVISIBLE);
- }
- else {
- la.setVisibility(View.VISIBLE);
- tv.setVisibility(View.INVISIBLE);
- Button mReturnSubmitButton = findViewById(R.id.return_submit_button);
- mReturnSubmitButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- returnRequest();
- }
- });
- }
- }
- void returnRequest() {
- TextView mStationInput;
- mStationInput = findViewById(R.id.return_station_id);
- String stationID = mStationInput.getText().toString();
- //get loginkey
- SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
- String defaultValue = "nokey";
- String loginKey = sharedPref.getString("loginKey", defaultValue);
-
- String[] params = {
- "apikey=", getString(R.string.apikey),
- "bike=", bikeArray[0],
- "loginkey=", loginKey,
- "station=", stationID,
- "comment=", ""
- };
- RequestHandler returnRequestTask = new RequestHandler(this, "POST",
- "api/return.json", params);
- returnRequestTask.execute((Void) null);
- }
-
- @Override
- public void onTaskComplete(String response) {
- //get back to main activity
- //TODO: *any* response handling
- finish();
- }
-}
diff --git a/app/src/main/res/drawable/ic_add_white_24dp.xml b/app/src/main/res/drawable/ic_add_white_24dp.xml
deleted file mode 100644
index b5b5ba4..0000000
--- a/app/src/main/res/drawable/ic_add_white_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
deleted file mode 100644
index de480af..0000000
--- a/app/src/main/res/layout/activity_login.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index d48b1b1..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_rent.xml b/app/src/main/res/layout/activity_rent.xml
deleted file mode 100644
index fb3084d..0000000
--- a/app/src/main/res/layout/activity_rent.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_return.xml b/app/src/main/res/layout/activity_return.xml
deleted file mode 100644
index 5728d58..0000000
--- a/app/src/main/res/layout/activity_return.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
deleted file mode 100644
index ef9edf3..0000000
--- a/app/src/main/res/layout/content_main.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index e2970cd..0000000
--- a/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index 036d09b..0000000
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index 036d09b..0000000
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 287a510..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
deleted file mode 100644
index 6c91c71..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 595b2c8..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index ded5dc9..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
deleted file mode 100644
index 03ca674..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index 92b9d0c..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 661eb62..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
deleted file mode 100644
index d0b1866..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 5c57a47..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index e83664a..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 11e7dfc..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index ac47ad8..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index d9dbdd8..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index a6563a5..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 120860f..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
deleted file mode 100644
index 541cfd5..0000000
--- a/app/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- #3F51B5
- #303F9F
- #9c274f
-
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
deleted file mode 100644
index 617af6a..0000000
--- a/app/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
- 16dp
-
- 16dp
- 16dp
-
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
deleted file mode 100644
index beab31f..0000000
--- a/app/src/main/res/values/ic_launcher_background.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- #000000
-
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index d4ea9ae..0000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/test/java/com/example/hochi/nextcompanion/ExampleUnitTest.java b/app/src/test/java/com/example/hochi/nextcompanion/ExampleUnitTest.java
deleted file mode 100644
index 8568a8c..0000000
--- a/app/src/test/java/com/example/hochi/nextcompanion/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.example.hochi.nextcompanion;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/build-aux/cargo-sources.json b/build-aux/cargo-sources.json
new file mode 100644
index 0000000..0cac0f1
--- /dev/null
+++ b/build-aux/cargo-sources.json
@@ -0,0 +1,1472 @@
+[
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/atomic-waker/1.1.2/download",
+ "sha256": "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0",
+ "dest": "cargo-vendor/atomic-waker-1.1.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/autocfg/1.5.0/download",
+ "sha256": "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8",
+ "dest": "cargo-vendor/autocfg-1.5.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/base64/0.22.1/download",
+ "sha256": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6",
+ "dest": "cargo-vendor/base64-0.22.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/bitflags/2.11.0/download",
+ "sha256": "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af",
+ "dest": "cargo-vendor/bitflags-2.11.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/bumpalo/3.20.2/download",
+ "sha256": "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb",
+ "dest": "cargo-vendor/bumpalo-3.20.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/bytes/1.11.1/download",
+ "sha256": "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33",
+ "dest": "cargo-vendor/bytes-1.11.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cairo-rs/0.21.5/download",
+ "sha256": "b01fe135c0bd16afe262b6dea349bd5ea30e6de50708cec639aae7c5c14cc7e4",
+ "dest": "cargo-vendor/cairo-rs-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cairo-sys-rs/0.21.5/download",
+ "sha256": "06c28280c6b12055b5e39e4554271ae4e6630b27c0da9148c4cf6485fc6d245c",
+ "dest": "cargo-vendor/cairo-sys-rs-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cc/1.2.56/download",
+ "sha256": "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2",
+ "dest": "cargo-vendor/cc-1.2.56"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cfg-expr/0.20.7/download",
+ "sha256": "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368",
+ "dest": "cargo-vendor/cfg-expr-0.20.7"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cfg-if/1.0.4/download",
+ "sha256": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801",
+ "dest": "cargo-vendor/cfg-if-1.0.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/cfg_aliases/0.2.1/download",
+ "sha256": "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724",
+ "dest": "cargo-vendor/cfg_aliases-0.2.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/dirs/5.0.1/download",
+ "sha256": "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225",
+ "dest": "cargo-vendor/dirs-5.0.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/dirs-sys/0.4.1/download",
+ "sha256": "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c",
+ "dest": "cargo-vendor/dirs-sys-0.4.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/displaydoc/0.2.5/download",
+ "sha256": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0",
+ "dest": "cargo-vendor/displaydoc-0.2.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/equivalent/1.0.2/download",
+ "sha256": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f",
+ "dest": "cargo-vendor/equivalent-1.0.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/field-offset/0.3.6/download",
+ "sha256": "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f",
+ "dest": "cargo-vendor/field-offset-0.3.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/find-msvc-tools/0.1.9/download",
+ "sha256": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582",
+ "dest": "cargo-vendor/find-msvc-tools-0.1.9"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/form_urlencoded/1.2.2/download",
+ "sha256": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf",
+ "dest": "cargo-vendor/form_urlencoded-1.2.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-channel/0.3.32/download",
+ "sha256": "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d",
+ "dest": "cargo-vendor/futures-channel-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-core/0.3.32/download",
+ "sha256": "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d",
+ "dest": "cargo-vendor/futures-core-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-executor/0.3.32/download",
+ "sha256": "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d",
+ "dest": "cargo-vendor/futures-executor-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-io/0.3.32/download",
+ "sha256": "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718",
+ "dest": "cargo-vendor/futures-io-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-macro/0.3.32/download",
+ "sha256": "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b",
+ "dest": "cargo-vendor/futures-macro-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-sink/0.3.32/download",
+ "sha256": "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893",
+ "dest": "cargo-vendor/futures-sink-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-task/0.3.32/download",
+ "sha256": "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393",
+ "dest": "cargo-vendor/futures-task-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/futures-util/0.3.32/download",
+ "sha256": "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6",
+ "dest": "cargo-vendor/futures-util-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gdk-pixbuf/0.21.5/download",
+ "sha256": "debb0d39e3cdd84626edfd54d6e4a6ba2da9a0ef2e796e691c4e9f8646fda00c",
+ "dest": "cargo-vendor/gdk-pixbuf-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gdk-pixbuf-sys/0.21.5/download",
+ "sha256": "bd95ad50b9a3d2551e25dd4f6892aff0b772fe5372d84514e9d0583af60a0ce7",
+ "dest": "cargo-vendor/gdk-pixbuf-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gdk4/0.10.3/download",
+ "sha256": "756564212bbe4a4ce05d88ffbd2582581ac6003832d0d32822d0825cca84bfbf",
+ "dest": "cargo-vendor/gdk4-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gdk4-sys/0.10.3/download",
+ "sha256": "a6d4e5b3ccf591826a4adcc83f5f57b4e59d1925cb4bf620b0d645f79498b034",
+ "dest": "cargo-vendor/gdk4-sys-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/getrandom/0.2.17/download",
+ "sha256": "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0",
+ "dest": "cargo-vendor/getrandom-0.2.17"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/getrandom/0.3.4/download",
+ "sha256": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd",
+ "dest": "cargo-vendor/getrandom-0.3.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gio/0.21.5/download",
+ "sha256": "c5ff48bf600c68b476e61dc6b7c762f2f4eb91deef66583ba8bb815c30b5811a",
+ "dest": "cargo-vendor/gio-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gio-sys/0.21.5/download",
+ "sha256": "0071fe88dba8e40086c8ff9bbb62622999f49628344b1d1bf490a48a29d80f22",
+ "dest": "cargo-vendor/gio-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/glib/0.21.5/download",
+ "sha256": "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b",
+ "dest": "cargo-vendor/glib-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/glib-macros/0.21.5/download",
+ "sha256": "cf59b675301228a696fe01c3073974643365080a76cc3ed5bc2cbc466ad87f17",
+ "dest": "cargo-vendor/glib-macros-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/glib-sys/0.21.5/download",
+ "sha256": "2d95e1a3a19ae464a7286e14af9a90683c64d70c02532d88d87ce95056af3e6c",
+ "dest": "cargo-vendor/glib-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gobject-sys/0.21.5/download",
+ "sha256": "2dca35da0d19a18f4575f3cb99fe1c9e029a2941af5662f326f738a21edaf294",
+ "dest": "cargo-vendor/gobject-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/graphene-rs/0.21.5/download",
+ "sha256": "2730030ac9db663fd8bfe1e7093742c1cafb92db9c315c9417c29032341fe2f9",
+ "dest": "cargo-vendor/graphene-rs-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/graphene-sys/0.21.5/download",
+ "sha256": "915e32091ea9ad241e4b044af62b7351c2d68aeb24f489a0d7f37a0fc484fd93",
+ "dest": "cargo-vendor/graphene-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gsk4/0.10.3/download",
+ "sha256": "e755de9d8c5896c5beaa028b89e1969d067f1b9bf1511384ede971f5983aa153",
+ "dest": "cargo-vendor/gsk4-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gsk4-sys/0.10.3/download",
+ "sha256": "7ce91472391146f482065f1041876d8f869057b195b95399414caa163d72f4f7",
+ "dest": "cargo-vendor/gsk4-sys-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gtk4/0.10.3/download",
+ "sha256": "acb21d53cfc6f7bfaf43549731c43b67ca47d87348d81c8cfc4dcdd44828e1a4",
+ "dest": "cargo-vendor/gtk4-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gtk4-macros/0.10.3/download",
+ "sha256": "3ccfb5a14a3d941244815d5f8101fa12d4577b59cc47245778d8d907b0003e42",
+ "dest": "cargo-vendor/gtk4-macros-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/gtk4-sys/0.10.3/download",
+ "sha256": "842577fe5a1ee15d166cd3afe804ce0cab6173bc789ca32e21308834f20088dd",
+ "dest": "cargo-vendor/gtk4-sys-0.10.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/hashbrown/0.16.1/download",
+ "sha256": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100",
+ "dest": "cargo-vendor/hashbrown-0.16.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/heck/0.5.0/download",
+ "sha256": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea",
+ "dest": "cargo-vendor/heck-0.5.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/http/1.4.0/download",
+ "sha256": "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a",
+ "dest": "cargo-vendor/http-1.4.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/http-body/1.0.1/download",
+ "sha256": "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184",
+ "dest": "cargo-vendor/http-body-1.0.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/http-body-util/0.1.3/download",
+ "sha256": "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a",
+ "dest": "cargo-vendor/http-body-util-0.1.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/httparse/1.10.1/download",
+ "sha256": "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87",
+ "dest": "cargo-vendor/httparse-1.10.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/hyper/1.8.1/download",
+ "sha256": "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11",
+ "dest": "cargo-vendor/hyper-1.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/hyper-rustls/0.27.7/download",
+ "sha256": "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58",
+ "dest": "cargo-vendor/hyper-rustls-0.27.7"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/hyper-util/0.1.20/download",
+ "sha256": "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0",
+ "dest": "cargo-vendor/hyper-util-0.1.20"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_collections/2.1.1/download",
+ "sha256": "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43",
+ "dest": "cargo-vendor/icu_collections-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_locale_core/2.1.1/download",
+ "sha256": "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6",
+ "dest": "cargo-vendor/icu_locale_core-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_normalizer/2.1.1/download",
+ "sha256": "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599",
+ "dest": "cargo-vendor/icu_normalizer-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_normalizer_data/2.1.1/download",
+ "sha256": "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a",
+ "dest": "cargo-vendor/icu_normalizer_data-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_properties/2.1.2/download",
+ "sha256": "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec",
+ "dest": "cargo-vendor/icu_properties-2.1.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_properties_data/2.1.2/download",
+ "sha256": "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af",
+ "dest": "cargo-vendor/icu_properties_data-2.1.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/icu_provider/2.1.1/download",
+ "sha256": "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614",
+ "dest": "cargo-vendor/icu_provider-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/idna/1.1.0/download",
+ "sha256": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de",
+ "dest": "cargo-vendor/idna-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/idna_adapter/1.2.1/download",
+ "sha256": "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344",
+ "dest": "cargo-vendor/idna_adapter-1.2.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/indexmap/2.13.0/download",
+ "sha256": "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017",
+ "dest": "cargo-vendor/indexmap-2.13.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/ipnet/2.12.0/download",
+ "sha256": "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2",
+ "dest": "cargo-vendor/ipnet-2.12.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/iri-string/0.7.10/download",
+ "sha256": "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a",
+ "dest": "cargo-vendor/iri-string-0.7.10"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/itoa/1.0.17/download",
+ "sha256": "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2",
+ "dest": "cargo-vendor/itoa-1.0.17"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/js-sys/0.3.91/download",
+ "sha256": "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c",
+ "dest": "cargo-vendor/js-sys-0.3.91"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/libadwaita/0.8.1/download",
+ "sha256": "fb09e12bf8f73342b3315c839d0a7668cc0ccebd78490c49fec48bab15d5484b",
+ "dest": "cargo-vendor/libadwaita-0.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/libadwaita-sys/0.8.1/download",
+ "sha256": "6d7f94227ba87eb596fecada2491f04e357d507324142f77bf76d9e6be4a3e31",
+ "dest": "cargo-vendor/libadwaita-sys-0.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/libc/0.2.183/download",
+ "sha256": "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d",
+ "dest": "cargo-vendor/libc-0.2.183"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/libredox/0.1.14/download",
+ "sha256": "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a",
+ "dest": "cargo-vendor/libredox-0.1.14"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/litemap/0.8.1/download",
+ "sha256": "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77",
+ "dest": "cargo-vendor/litemap-0.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/log/0.4.29/download",
+ "sha256": "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897",
+ "dest": "cargo-vendor/log-0.4.29"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/lru-slab/0.1.2/download",
+ "sha256": "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154",
+ "dest": "cargo-vendor/lru-slab-0.1.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/memchr/2.8.0/download",
+ "sha256": "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79",
+ "dest": "cargo-vendor/memchr-2.8.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/memoffset/0.9.1/download",
+ "sha256": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a",
+ "dest": "cargo-vendor/memoffset-0.9.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/mio/1.1.1/download",
+ "sha256": "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc",
+ "dest": "cargo-vendor/mio-1.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/once_cell/1.21.3/download",
+ "sha256": "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d",
+ "dest": "cargo-vendor/once_cell-1.21.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/option-ext/0.2.0/download",
+ "sha256": "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d",
+ "dest": "cargo-vendor/option-ext-0.2.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/pango/0.21.5/download",
+ "sha256": "52d1d85e2078077a065bb7fc072783d5bcd4e51b379f22d67107d0a16937eb69",
+ "dest": "cargo-vendor/pango-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/pango-sys/0.21.5/download",
+ "sha256": "b4f06627d36ed5ff303d2df65211fc2e52ba5b17bf18dd80ff3d9628d6e06cfd",
+ "dest": "cargo-vendor/pango-sys-0.21.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/percent-encoding/2.3.2/download",
+ "sha256": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220",
+ "dest": "cargo-vendor/percent-encoding-2.3.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/pin-project-lite/0.2.17/download",
+ "sha256": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd",
+ "dest": "cargo-vendor/pin-project-lite-0.2.17"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/pin-utils/0.1.0/download",
+ "sha256": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184",
+ "dest": "cargo-vendor/pin-utils-0.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/pkg-config/0.3.32/download",
+ "sha256": "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c",
+ "dest": "cargo-vendor/pkg-config-0.3.32"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/potential_utf/0.1.4/download",
+ "sha256": "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77",
+ "dest": "cargo-vendor/potential_utf-0.1.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/ppv-lite86/0.2.21/download",
+ "sha256": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9",
+ "dest": "cargo-vendor/ppv-lite86-0.2.21"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/proc-macro-crate/3.5.0/download",
+ "sha256": "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f",
+ "dest": "cargo-vendor/proc-macro-crate-3.5.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/proc-macro2/1.0.106/download",
+ "sha256": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934",
+ "dest": "cargo-vendor/proc-macro2-1.0.106"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/quinn/0.11.9/download",
+ "sha256": "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20",
+ "dest": "cargo-vendor/quinn-0.11.9"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/quinn-proto/0.11.14/download",
+ "sha256": "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098",
+ "dest": "cargo-vendor/quinn-proto-0.11.14"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/quinn-udp/0.5.14/download",
+ "sha256": "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd",
+ "dest": "cargo-vendor/quinn-udp-0.5.14"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/quote/1.0.45/download",
+ "sha256": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924",
+ "dest": "cargo-vendor/quote-1.0.45"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/r-efi/5.3.0/download",
+ "sha256": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f",
+ "dest": "cargo-vendor/r-efi-5.3.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rand/0.9.2/download",
+ "sha256": "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1",
+ "dest": "cargo-vendor/rand-0.9.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rand_chacha/0.9.0/download",
+ "sha256": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb",
+ "dest": "cargo-vendor/rand_chacha-0.9.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rand_core/0.9.5/download",
+ "sha256": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c",
+ "dest": "cargo-vendor/rand_core-0.9.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/redox_users/0.4.6/download",
+ "sha256": "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43",
+ "dest": "cargo-vendor/redox_users-0.4.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/reqwest/0.12.28/download",
+ "sha256": "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147",
+ "dest": "cargo-vendor/reqwest-0.12.28"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/ring/0.17.14/download",
+ "sha256": "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7",
+ "dest": "cargo-vendor/ring-0.17.14"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustc-hash/2.1.1/download",
+ "sha256": "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d",
+ "dest": "cargo-vendor/rustc-hash-2.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustc_version/0.4.1/download",
+ "sha256": "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92",
+ "dest": "cargo-vendor/rustc_version-0.4.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustls/0.23.37/download",
+ "sha256": "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4",
+ "dest": "cargo-vendor/rustls-0.23.37"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustls-pki-types/1.14.0/download",
+ "sha256": "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd",
+ "dest": "cargo-vendor/rustls-pki-types-1.14.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustls-webpki/0.103.9/download",
+ "sha256": "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53",
+ "dest": "cargo-vendor/rustls-webpki-0.103.9"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/rustversion/1.0.22/download",
+ "sha256": "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d",
+ "dest": "cargo-vendor/rustversion-1.0.22"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/ryu/1.0.23/download",
+ "sha256": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f",
+ "dest": "cargo-vendor/ryu-1.0.23"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/semver/1.0.27/download",
+ "sha256": "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2",
+ "dest": "cargo-vendor/semver-1.0.27"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde/1.0.228/download",
+ "sha256": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e",
+ "dest": "cargo-vendor/serde-1.0.228"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde_core/1.0.228/download",
+ "sha256": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad",
+ "dest": "cargo-vendor/serde_core-1.0.228"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde_derive/1.0.228/download",
+ "sha256": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79",
+ "dest": "cargo-vendor/serde_derive-1.0.228"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde_json/1.0.149/download",
+ "sha256": "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86",
+ "dest": "cargo-vendor/serde_json-1.0.149"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde_spanned/1.0.4/download",
+ "sha256": "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776",
+ "dest": "cargo-vendor/serde_spanned-1.0.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/serde_urlencoded/0.7.1/download",
+ "sha256": "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd",
+ "dest": "cargo-vendor/serde_urlencoded-0.7.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/shlex/1.3.0/download",
+ "sha256": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64",
+ "dest": "cargo-vendor/shlex-1.3.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/slab/0.4.12/download",
+ "sha256": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5",
+ "dest": "cargo-vendor/slab-0.4.12"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/smallvec/1.15.1/download",
+ "sha256": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03",
+ "dest": "cargo-vendor/smallvec-1.15.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/socket2/0.6.3/download",
+ "sha256": "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e",
+ "dest": "cargo-vendor/socket2-0.6.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/stable_deref_trait/1.2.1/download",
+ "sha256": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596",
+ "dest": "cargo-vendor/stable_deref_trait-1.2.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/subtle/2.6.1/download",
+ "sha256": "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292",
+ "dest": "cargo-vendor/subtle-2.6.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/syn/2.0.117/download",
+ "sha256": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99",
+ "dest": "cargo-vendor/syn-2.0.117"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/sync_wrapper/1.0.2/download",
+ "sha256": "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263",
+ "dest": "cargo-vendor/sync_wrapper-1.0.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/synstructure/0.13.2/download",
+ "sha256": "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2",
+ "dest": "cargo-vendor/synstructure-0.13.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/system-deps/7.0.7/download",
+ "sha256": "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f",
+ "dest": "cargo-vendor/system-deps-7.0.7"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/target-lexicon/0.13.3/download",
+ "sha256": "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c",
+ "dest": "cargo-vendor/target-lexicon-0.13.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/thiserror/1.0.69/download",
+ "sha256": "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52",
+ "dest": "cargo-vendor/thiserror-1.0.69"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/thiserror/2.0.18/download",
+ "sha256": "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4",
+ "dest": "cargo-vendor/thiserror-2.0.18"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/thiserror-impl/1.0.69/download",
+ "sha256": "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1",
+ "dest": "cargo-vendor/thiserror-impl-1.0.69"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/thiserror-impl/2.0.18/download",
+ "sha256": "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5",
+ "dest": "cargo-vendor/thiserror-impl-2.0.18"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tinystr/0.8.2/download",
+ "sha256": "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869",
+ "dest": "cargo-vendor/tinystr-0.8.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tinyvec/1.10.0/download",
+ "sha256": "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa",
+ "dest": "cargo-vendor/tinyvec-1.10.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tinyvec_macros/0.1.1/download",
+ "sha256": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20",
+ "dest": "cargo-vendor/tinyvec_macros-0.1.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tokio/1.50.0/download",
+ "sha256": "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d",
+ "dest": "cargo-vendor/tokio-1.50.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tokio-rustls/0.26.4/download",
+ "sha256": "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61",
+ "dest": "cargo-vendor/tokio-rustls-0.26.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml/0.9.12+spec-1.1.0/download",
+ "sha256": "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863",
+ "dest": "cargo-vendor/toml-0.9.12+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml_datetime/0.7.5+spec-1.1.0/download",
+ "sha256": "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347",
+ "dest": "cargo-vendor/toml_datetime-0.7.5+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml_datetime/1.0.0+spec-1.1.0/download",
+ "sha256": "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e",
+ "dest": "cargo-vendor/toml_datetime-1.0.0+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml_edit/0.25.4+spec-1.1.0/download",
+ "sha256": "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2",
+ "dest": "cargo-vendor/toml_edit-0.25.4+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml_parser/1.0.9+spec-1.1.0/download",
+ "sha256": "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4",
+ "dest": "cargo-vendor/toml_parser-1.0.9+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/toml_writer/1.0.6+spec-1.1.0/download",
+ "sha256": "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607",
+ "dest": "cargo-vendor/toml_writer-1.0.6+spec-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tower/0.5.3/download",
+ "sha256": "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4",
+ "dest": "cargo-vendor/tower-0.5.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tower-http/0.6.8/download",
+ "sha256": "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8",
+ "dest": "cargo-vendor/tower-http-0.6.8"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tower-layer/0.3.3/download",
+ "sha256": "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e",
+ "dest": "cargo-vendor/tower-layer-0.3.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tower-service/0.3.3/download",
+ "sha256": "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3",
+ "dest": "cargo-vendor/tower-service-0.3.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tracing/0.1.44/download",
+ "sha256": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100",
+ "dest": "cargo-vendor/tracing-0.1.44"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/tracing-core/0.1.36/download",
+ "sha256": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a",
+ "dest": "cargo-vendor/tracing-core-0.1.36"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/try-lock/0.2.5/download",
+ "sha256": "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b",
+ "dest": "cargo-vendor/try-lock-0.2.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/unicode-ident/1.0.24/download",
+ "sha256": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75",
+ "dest": "cargo-vendor/unicode-ident-1.0.24"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/untrusted/0.9.0/download",
+ "sha256": "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1",
+ "dest": "cargo-vendor/untrusted-0.9.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/url/2.5.8/download",
+ "sha256": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed",
+ "dest": "cargo-vendor/url-2.5.8"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/utf8_iter/1.0.4/download",
+ "sha256": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be",
+ "dest": "cargo-vendor/utf8_iter-1.0.4"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/version-compare/0.2.1/download",
+ "sha256": "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e",
+ "dest": "cargo-vendor/version-compare-0.2.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/want/0.3.1/download",
+ "sha256": "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e",
+ "dest": "cargo-vendor/want-0.3.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download",
+ "sha256": "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b",
+ "dest": "cargo-vendor/wasi-0.11.1+wasi-snapshot-preview1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasip2/1.0.2+wasi-0.2.9/download",
+ "sha256": "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5",
+ "dest": "cargo-vendor/wasip2-1.0.2+wasi-0.2.9"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasm-bindgen/0.2.114/download",
+ "sha256": "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e",
+ "dest": "cargo-vendor/wasm-bindgen-0.2.114"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasm-bindgen-futures/0.4.64/download",
+ "sha256": "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8",
+ "dest": "cargo-vendor/wasm-bindgen-futures-0.4.64"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasm-bindgen-macro/0.2.114/download",
+ "sha256": "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6",
+ "dest": "cargo-vendor/wasm-bindgen-macro-0.2.114"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.114/download",
+ "sha256": "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3",
+ "dest": "cargo-vendor/wasm-bindgen-macro-support-0.2.114"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wasm-bindgen-shared/0.2.114/download",
+ "sha256": "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16",
+ "dest": "cargo-vendor/wasm-bindgen-shared-0.2.114"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/web-sys/0.3.91/download",
+ "sha256": "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9",
+ "dest": "cargo-vendor/web-sys-0.3.91"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/web-time/1.1.0/download",
+ "sha256": "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb",
+ "dest": "cargo-vendor/web-time-1.1.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/webpki-roots/1.0.6/download",
+ "sha256": "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed",
+ "dest": "cargo-vendor/webpki-roots-1.0.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-link/0.2.1/download",
+ "sha256": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5",
+ "dest": "cargo-vendor/windows-link-0.2.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-sys/0.48.0/download",
+ "sha256": "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9",
+ "dest": "cargo-vendor/windows-sys-0.48.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-sys/0.52.0/download",
+ "sha256": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d",
+ "dest": "cargo-vendor/windows-sys-0.52.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-sys/0.60.2/download",
+ "sha256": "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb",
+ "dest": "cargo-vendor/windows-sys-0.60.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-sys/0.61.2/download",
+ "sha256": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc",
+ "dest": "cargo-vendor/windows-sys-0.61.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-targets/0.48.5/download",
+ "sha256": "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c",
+ "dest": "cargo-vendor/windows-targets-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-targets/0.52.6/download",
+ "sha256": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973",
+ "dest": "cargo-vendor/windows-targets-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows-targets/0.53.5/download",
+ "sha256": "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3",
+ "dest": "cargo-vendor/windows-targets-0.53.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_gnullvm/0.48.5/download",
+ "sha256": "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8",
+ "dest": "cargo-vendor/windows_aarch64_gnullvm-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download",
+ "sha256": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3",
+ "dest": "cargo-vendor/windows_aarch64_gnullvm-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_gnullvm/0.53.1/download",
+ "sha256": "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53",
+ "dest": "cargo-vendor/windows_aarch64_gnullvm-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_msvc/0.48.5/download",
+ "sha256": "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc",
+ "dest": "cargo-vendor/windows_aarch64_msvc-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download",
+ "sha256": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469",
+ "dest": "cargo-vendor/windows_aarch64_msvc-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_aarch64_msvc/0.53.1/download",
+ "sha256": "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006",
+ "dest": "cargo-vendor/windows_aarch64_msvc-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_gnu/0.48.5/download",
+ "sha256": "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e",
+ "dest": "cargo-vendor/windows_i686_gnu-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_gnu/0.52.6/download",
+ "sha256": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b",
+ "dest": "cargo-vendor/windows_i686_gnu-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_gnu/0.53.1/download",
+ "sha256": "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3",
+ "dest": "cargo-vendor/windows_i686_gnu-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download",
+ "sha256": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66",
+ "dest": "cargo-vendor/windows_i686_gnullvm-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_gnullvm/0.53.1/download",
+ "sha256": "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c",
+ "dest": "cargo-vendor/windows_i686_gnullvm-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_msvc/0.48.5/download",
+ "sha256": "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406",
+ "dest": "cargo-vendor/windows_i686_msvc-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_msvc/0.52.6/download",
+ "sha256": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66",
+ "dest": "cargo-vendor/windows_i686_msvc-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_i686_msvc/0.53.1/download",
+ "sha256": "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2",
+ "dest": "cargo-vendor/windows_i686_msvc-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnu/0.48.5/download",
+ "sha256": "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e",
+ "dest": "cargo-vendor/windows_x86_64_gnu-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download",
+ "sha256": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78",
+ "dest": "cargo-vendor/windows_x86_64_gnu-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnu/0.53.1/download",
+ "sha256": "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499",
+ "dest": "cargo-vendor/windows_x86_64_gnu-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnullvm/0.48.5/download",
+ "sha256": "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc",
+ "dest": "cargo-vendor/windows_x86_64_gnullvm-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download",
+ "sha256": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d",
+ "dest": "cargo-vendor/windows_x86_64_gnullvm-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_gnullvm/0.53.1/download",
+ "sha256": "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1",
+ "dest": "cargo-vendor/windows_x86_64_gnullvm-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_msvc/0.48.5/download",
+ "sha256": "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538",
+ "dest": "cargo-vendor/windows_x86_64_msvc-0.48.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download",
+ "sha256": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec",
+ "dest": "cargo-vendor/windows_x86_64_msvc-0.52.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/windows_x86_64_msvc/0.53.1/download",
+ "sha256": "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650",
+ "dest": "cargo-vendor/windows_x86_64_msvc-0.53.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/winnow/0.7.15/download",
+ "sha256": "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945",
+ "dest": "cargo-vendor/winnow-0.7.15"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/wit-bindgen/0.51.0/download",
+ "sha256": "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5",
+ "dest": "cargo-vendor/wit-bindgen-0.51.0"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/writeable/0.6.2/download",
+ "sha256": "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9",
+ "dest": "cargo-vendor/writeable-0.6.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/yoke/0.8.1/download",
+ "sha256": "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954",
+ "dest": "cargo-vendor/yoke-0.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/yoke-derive/0.8.1/download",
+ "sha256": "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d",
+ "dest": "cargo-vendor/yoke-derive-0.8.1"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerocopy/0.8.42/download",
+ "sha256": "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3",
+ "dest": "cargo-vendor/zerocopy-0.8.42"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerocopy-derive/0.8.42/download",
+ "sha256": "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f",
+ "dest": "cargo-vendor/zerocopy-derive-0.8.42"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerofrom/0.1.6/download",
+ "sha256": "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5",
+ "dest": "cargo-vendor/zerofrom-0.1.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerofrom-derive/0.1.6/download",
+ "sha256": "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502",
+ "dest": "cargo-vendor/zerofrom-derive-0.1.6"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zeroize/1.8.2/download",
+ "sha256": "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0",
+ "dest": "cargo-vendor/zeroize-1.8.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerotrie/0.2.3/download",
+ "sha256": "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851",
+ "dest": "cargo-vendor/zerotrie-0.2.3"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerovec/0.11.5/download",
+ "sha256": "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002",
+ "dest": "cargo-vendor/zerovec-0.11.5"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zerovec-derive/0.11.2/download",
+ "sha256": "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3",
+ "dest": "cargo-vendor/zerovec-derive-0.11.2"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": "https://static.crates.io/crates/zmij/1.0.21/download",
+ "sha256": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa",
+ "dest": "cargo-vendor/zmij-1.0.21"
+ }
+]
diff --git a/build-aux/cargo-vendor-config.toml b/build-aux/cargo-vendor-config.toml
new file mode 100644
index 0000000..3152530
--- /dev/null
+++ b/build-aux/cargo-vendor-config.toml
@@ -0,0 +1,5 @@
+[source.crates-io]
+replace-with = "vendored-sources"
+
+[source.vendored-sources]
+directory = "/run/build/next-companion/cargo-vendor"
diff --git a/build-aux/flatpak-cargo-generator.py b/build-aux/flatpak-cargo-generator.py
new file mode 100644
index 0000000..2c0079c
--- /dev/null
+++ b/build-aux/flatpak-cargo-generator.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+"""Generate Flatpak source entries for Cargo dependencies from Cargo.lock.
+
+Usage:
+ python3 build-aux/flatpak-cargo-generator.py [Cargo.lock] \
+ > build-aux/cargo-sources.json
+"""
+
+import json
+import sys
+
+try:
+ import tomllib
+except ImportError:
+ try:
+ import tomli as tomllib # pip install tomli
+ except ImportError:
+ print("Error: requires Python 3.11+ or the 'tomli' package", file=sys.stderr)
+ sys.exit(1)
+
+CRATES_IO_DL = "https://static.crates.io/crates"
+REGISTRY_SOURCE = "registry+https://github.com/rust-lang/crates.io-index"
+
+
+def main() -> None:
+ lockfile = sys.argv[1] if len(sys.argv) > 1 else "Cargo.lock"
+
+ with open(lockfile, "rb") as f:
+ lock = tomllib.load(f)
+
+ sources = []
+
+ for pkg in lock.get("package", []):
+ name = pkg["name"]
+ version = pkg["version"]
+ source = pkg.get("source", "")
+ checksum = pkg.get("checksum")
+
+ # Only vendor packages from crates.io (they have a checksum)
+ if source == REGISTRY_SOURCE and checksum:
+ sources.append(
+ {
+ "type": "archive",
+ "archive-type": "tar-gz",
+ "url": f"{CRATES_IO_DL}/{name}/{version}/download",
+ "sha256": checksum,
+ "dest": f"cargo-vendor/{name}-{version}",
+ }
+ )
+
+ print(json.dumps(sources, indent=2))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 4082391..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
-
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.3.1'
-
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- }
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/app/src/main/ic_launcher-web.png b/data/icons/org.nextbike.NextCompanion.png
similarity index 100%
rename from app/src/main/ic_launcher-web.png
rename to data/icons/org.nextbike.NextCompanion.png
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..09412e5
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,62 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1772963539,
+ "narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1744536153,
+ "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "nixpkgs": "nixpkgs_2"
+ },
+ "locked": {
+ "lastModified": 1773115373,
+ "narHash": "sha256-bfK9FJFcQth6f3ydYggS5m0z2NRGF/PY6Y2XgZDJ6pg=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "1924b4672a2b8e4aee6e6652ec2e59a8d3c5648e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..0fe5510
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,51 @@
+{
+ description = "NextCompanion — a minimal GTK4 Nextbike client for Linux";
+
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ rust-overlay.url = "github:oxalica/rust-overlay";
+ };
+
+ outputs = { self, nixpkgs, rust-overlay, ... }:
+ let
+ system = "x86_64-linux";
+ overlays = [ (import rust-overlay) ];
+ pkgs = import nixpkgs { inherit system overlays; };
+
+ runtimeDeps = with pkgs; [
+ gtk4
+ libadwaita
+ glib
+ ];
+ buildDeps = with pkgs; [
+ pkg-config
+ rust-bin.stable.latest.default
+ ];
+ in
+ {
+ devShells.${system}.default = pkgs.mkShell {
+ buildInputs = buildDeps ++ runtimeDeps;
+ shellHook = ''
+ export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath runtimeDeps}:$LD_LIBRARY_PATH"
+ '';
+ };
+
+ packages.${system}.default = pkgs.rustPlatform.buildRustPackage {
+ pname = "next-companion";
+ version = "0.1.0";
+ src = ./.;
+ cargoLock.lockFile = ./Cargo.lock;
+ nativeBuildInputs = buildDeps;
+ buildInputs = runtimeDeps;
+ postInstall = ''
+ install -Dm644 data/icons/org.nextbike.NextCompanion.png \
+ $out/share/icons/hicolor/512x512/apps/org.nextbike.NextCompanion.png
+ '';
+ };
+
+ apps.${system}.default = {
+ type = "app";
+ program = "${self.packages.${system}.default}/bin/next-companion";
+ };
+ };
+}
diff --git a/gradle.properties b/gradle.properties
deleted file mode 100644
index 743d692..0000000
--- a/gradle.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 7a3265e..0000000
Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 10ff630..0000000
--- a/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Fri May 03 12:47:19 GMT 2019
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew b/gradlew
deleted file mode 100755
index cccdd3d..0000000
--- a/gradlew
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env sh
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
deleted file mode 100644
index e95643d..0000000
--- a/gradlew.bat
+++ /dev/null
@@ -1,84 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/org.nextbike.NextCompanion.yml b/org.nextbike.NextCompanion.yml
new file mode 100644
index 0000000..38049f9
--- /dev/null
+++ b/org.nextbike.NextCompanion.yml
@@ -0,0 +1,47 @@
+app-id: org.nextbike.NextCompanion
+runtime: org.gnome.Platform
+runtime-version: '47'
+sdk: org.gnome.Sdk
+sdk-extensions:
+ - org.freedesktop.Sdk.Extension.rust-stable
+command: next-companion
+
+finish-args:
+ - --share=network # nextbike API calls
+ - --share=ipc
+ - --socket=wayland
+ - --socket=fallback-x11
+ - --device=dri # GPU acceleration
+
+build-options:
+ append-path: /usr/lib/sdk/rust-stable/bin
+ env:
+ CARGO_HOME: /run/build/next-companion/cargo-home
+ RUST_BACKTRACE: '1'
+ arch:
+ aarch64:
+ env:
+ CARGO_BUILD_TARGET: aarch64-unknown-linux-gnu
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-unknown-linux-gnu-gcc
+
+modules:
+ - name: next-companion
+ buildsystem: simple
+ build-commands:
+ - mkdir -p .cargo
+ - cp cargo-vendor-config/cargo-vendor-config.toml .cargo/config.toml
+ - cargo --offline build --release
+ - |
+ install -Dm755 \
+ "target/${CARGO_BUILD_TARGET:+${CARGO_BUILD_TARGET}/}release/next-companion" \
+ /app/bin/next-companion
+ - install -Dm644 data/icons/org.nextbike.NextCompanion.png
+ /app/share/icons/hicolor/512x512/apps/org.nextbike.NextCompanion.png
+ sources:
+ - type: dir
+ path: .
+ - type: file
+ path: build-aux/cargo-vendor-config.toml
+ dest: cargo-vendor-config
+ dest-filename: cargo-vendor-config.toml
+ - build-aux/cargo-sources.json
diff --git a/result b/result
new file mode 120000
index 0000000..91521cf
--- /dev/null
+++ b/result
@@ -0,0 +1 @@
+/nix/store/gan72x7dji7c6lwngwfx88my14azg9wn-next-companion-0.1.0
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index e7b4def..0000000
--- a/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':app'
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..b730196
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,608 @@
+use adw::prelude::*;
+use adw::{Application, ApplicationWindow, BottomSheet, Clamp, HeaderBar, NavigationPage, NavigationView};
+use gtk::{
+ Box, Button, Entry, Label, ListBox, ListBoxRow, Orientation, ScrolledWindow, Spinner, Stack,
+};
+use gtk::gio;
+use gtk::glib;
+use std::cell::RefCell;
+use std::fs;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+const API_KEY: &str = "3IaBlP9OZw14dvES";
+const BASE_URL: &str = "https://api.nextbike.net";
+
+// ── Bike model ────────────────────────────────────────────────────────────────
+
+#[derive(Clone)]
+struct Bike {
+ id: String,
+ code: String,
+ electric_lock: bool,
+}
+
+// ── Persistent login key ──────────────────────────────────────────────────────
+
+fn config_path() -> PathBuf {
+ let mut p = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
+ p.push("next-companion");
+ p.push("loginkey");
+ p
+}
+
+fn load_loginkey() -> Option {
+ fs::read_to_string(config_path())
+ .ok()
+ .map(|s| s.trim().to_string())
+ .filter(|s| !s.is_empty())
+}
+
+fn save_loginkey(key: &str) {
+ let path = config_path();
+ if let Some(parent) = path.parent() {
+ let _ = fs::create_dir_all(parent);
+ }
+ let _ = fs::write(&path, key);
+}
+
+fn clear_loginkey() {
+ let _ = fs::remove_file(config_path());
+}
+
+// ── API calls (blocking — run via gio::spawn_blocking) ────────────────────────
+
+fn api_login(phone: &str, pin: &str) -> Result {
+ let resp = reqwest::blocking::Client::new()
+ .post(format!("{BASE_URL}/api/login.json"))
+ .form(&[("apikey", API_KEY), ("mobile", phone), ("pin", pin)])
+ .send()
+ .map_err(|e| e.to_string())?;
+ let json: serde_json::Value =
+ serde_json::from_str(&resp.text().map_err(|e| e.to_string())?)
+ .map_err(|e| e.to_string())?;
+ json["user"]["loginkey"]
+ .as_str()
+ .map(|s| s.to_string())
+ .ok_or_else(|| "Invalid credentials".to_string())
+}
+
+fn api_get_rentals(loginkey: &str) -> Result, String> {
+ let resp = reqwest::blocking::Client::new()
+ .post(format!("{BASE_URL}/api/getOpenRentals.json"))
+ .form(&[("apikey", API_KEY), ("loginkey", loginkey)])
+ .send()
+ .map_err(|e| e.to_string())?;
+ let json: serde_json::Value =
+ serde_json::from_str(&resp.text().map_err(|e| e.to_string())?)
+ .map_err(|e| e.to_string())?;
+ let arr = json["rentalCollection"]
+ .as_array()
+ .ok_or_else(|| "No rental data".to_string())?;
+ Ok(arr
+ .iter()
+ .map(|b| Bike {
+ id: b["bike"].as_str().unwrap_or("").to_string(),
+ code: b["code"].as_str().unwrap_or("").to_string(),
+ electric_lock: b["electric_lock"].as_str().map_or(false, |s| s == "true"),
+ })
+ .collect())
+}
+
+fn api_rent(loginkey: &str, bike_id: &str) -> Result<(), String> {
+ reqwest::blocking::Client::new()
+ .post(format!("{BASE_URL}/api/rent.json"))
+ .form(&[("apikey", API_KEY), ("loginkey", loginkey), ("bike", bike_id)])
+ .send()
+ .map_err(|e| e.to_string())?;
+ Ok(())
+}
+
+fn api_return(loginkey: &str, bike_id: &str, station_id: &str) -> Result<(), String> {
+ reqwest::blocking::Client::new()
+ .post(format!("{BASE_URL}/api/return.json"))
+ .form(&[
+ ("apikey", API_KEY),
+ ("bike", bike_id),
+ ("loginkey", loginkey),
+ ("station", station_id),
+ ("comment", ""),
+ ])
+ .send()
+ .map_err(|e| e.to_string())?;
+ Ok(())
+}
+
+// ── Async helpers (run on GLib main context) ──────────────────────────────────
+
+async fn load_rentals(key: String, bikes: Rc>>, bikes_list: ListBox, list_stack: Stack) {
+ let result = match gio::spawn_blocking(move || api_get_rentals(&key)).await {
+ Ok(r) => r,
+ Err(_) => return,
+ };
+ if let Ok(new_bikes) = result {
+ while let Some(child) = bikes_list.first_child() {
+ bikes_list.remove(&child);
+ }
+ for bike in &new_bikes {
+ let text = format!(
+ "Bike {} · code: {}{}",
+ bike.id,
+ bike.code,
+ if bike.electric_lock { " ⚡" } else { "" }
+ );
+ let lbl = Label::builder()
+ .label(&text)
+ .xalign(0.0)
+ .margin_top(14)
+ .margin_bottom(14)
+ .margin_start(12)
+ .margin_end(12)
+ .build();
+ let row = ListBoxRow::new();
+ row.set_child(Some(&lbl));
+ bikes_list.append(&row);
+ }
+ list_stack.set_visible_child_name(if new_bikes.is_empty() { "empty" } else { "list" });
+ *bikes.borrow_mut() = new_bikes;
+ }
+}
+
+// ── Entry point ───────────────────────────────────────────────────────────────
+
+fn main() -> glib::ExitCode {
+ let app = Application::builder()
+ .application_id("org.nextbike.NextCompanion")
+ .build();
+ app.connect_activate(build_ui);
+ app.run()
+}
+
+// ── UI ────────────────────────────────────────────────────────────────────────
+
+fn build_ui(app: &Application) {
+ let loginkey: Rc>> = Rc::new(RefCell::new(load_loginkey()));
+ let bikes: Rc>> = Rc::new(RefCell::new(vec![]));
+ let return_bike: Rc>> = Rc::new(RefCell::new(None));
+
+ // ── Login page ────────────────────────────────────────────────────────────
+ let phone_entry = Entry::builder()
+ .placeholder_text("Phone number")
+ .build();
+ let pin_entry = Entry::builder()
+ .placeholder_text("PIN")
+ .visibility(false)
+ .build();
+ let login_err = Label::builder()
+ .css_classes(["error"])
+ .wrap(true)
+ .visible(false)
+ .build();
+ let login_btn = Button::builder()
+ .label("Sign In")
+ .css_classes(["suggested-action", "pill"])
+ .build();
+ let login_spinner = Spinner::new();
+
+ let login_form = Box::builder()
+ .orientation(Orientation::Vertical)
+ .spacing(12)
+ .margin_top(24).margin_bottom(24).margin_start(12).margin_end(12)
+ .build();
+ login_form.append(&phone_entry);
+ login_form.append(&pin_entry);
+ login_form.append(&login_err);
+ login_form.append(&login_btn);
+ login_form.append(&login_spinner);
+
+ let login_clamp = Clamp::builder().maximum_size(400).build();
+ login_clamp.set_child(Some(&login_form));
+
+ let login_body = Box::builder().orientation(Orientation::Vertical).build();
+ login_body.append(&HeaderBar::new());
+ login_body.append(&login_clamp);
+
+ let login_page = NavigationPage::builder()
+ .title("Sign In")
+ .child(&login_body)
+ .build();
+
+ // ── Main page ─────────────────────────────────────────────────────────────
+ let bikes_list = ListBox::builder()
+ .css_classes(["boxed-list"])
+ .selection_mode(gtk::SelectionMode::None)
+ .margin_top(8).margin_bottom(8).margin_start(12).margin_end(12)
+ .build();
+ let empty_label = Label::builder()
+ .label("No active rentals")
+ .margin_top(48)
+ .css_classes(["dim-label"])
+ .build();
+ let list_stack = Stack::new();
+ list_stack.add_named(&empty_label, Some("empty"));
+ list_stack.add_named(&bikes_list, Some("list"));
+ list_stack.set_visible_child_name("empty");
+
+ let scroll = ScrolledWindow::builder().vexpand(true).child(&list_stack).build();
+
+ let rent_btn = Button::builder()
+ .label("Rent a Bike")
+ .css_classes(["suggested-action", "pill"])
+ .margin_top(8).margin_bottom(12).margin_start(12).margin_end(12)
+ .build();
+
+ let main_hdr = HeaderBar::new();
+ let logout_btn = Button::builder()
+ .icon_name("system-log-out-symbolic")
+ .tooltip_text("Logout")
+ .build();
+ let refresh_btn = Button::builder()
+ .icon_name("view-refresh-symbolic")
+ .tooltip_text("Refresh")
+ .build();
+ main_hdr.pack_end(&logout_btn);
+ main_hdr.pack_start(&refresh_btn);
+
+ // ── Bottom sheet (rent + return) ──────────────────────────────────────────
+
+ // — Rent form —
+ let bike_entry = Entry::builder()
+ .placeholder_text("Bike number")
+ .input_purpose(gtk::InputPurpose::Digits)
+ .build();
+ let rent_err = Label::builder()
+ .css_classes(["error"])
+ .wrap(true)
+ .visible(false)
+ .build();
+ let rent_submit = Button::builder()
+ .label("Rent")
+ .css_classes(["suggested-action", "pill"])
+ .build();
+ let rent_spinner = Spinner::new();
+
+ let rent_sheet = Box::builder()
+ .orientation(Orientation::Vertical)
+ .spacing(12)
+ .build();
+ let rent_form = Box::builder()
+ .orientation(Orientation::Vertical)
+ .spacing(12)
+ .build();
+ rent_form.append(&bike_entry);
+ rent_form.append(&rent_err);
+ rent_form.append(&rent_submit);
+ rent_form.append(&rent_spinner);
+ rent_sheet.append(&rent_form);
+
+ // — Return form —
+ let station_entry = Entry::builder()
+ .placeholder_text("Station number")
+ .input_purpose(gtk::InputPurpose::Digits)
+ .build();
+ let ret_err = Label::builder()
+ .css_classes(["error"])
+ .wrap(true)
+ .visible(false)
+ .build();
+ let ret_submit = Button::builder()
+ .label("Return Bike")
+ .css_classes(["destructive-action", "pill"])
+ .build();
+ let ret_spinner = Spinner::new();
+ let electric_msg = Label::builder()
+ .label("This bike has an electric lock.\nJust close the lock to return it.")
+ .wrap(true)
+ .justify(gtk::Justification::Center)
+ .margin_top(24)
+ .build();
+
+ let manual_form = Box::builder()
+ .orientation(Orientation::Vertical)
+ .spacing(12)
+ .build();
+ manual_form.append(&station_entry);
+ manual_form.append(&ret_err);
+ manual_form.append(&ret_submit);
+ manual_form.append(&ret_spinner);
+
+ let ret_inner = Stack::new();
+ ret_inner.add_named(&manual_form, Some("manual"));
+ ret_inner.add_named(&electric_msg, Some("electric"));
+
+ let ret_sheet = Box::builder()
+ .orientation(Orientation::Vertical)
+ .spacing(12)
+ .build();
+ ret_sheet.append(&ret_inner);
+
+ // — Shared sheet stack —
+ let sheet_stack = Stack::new();
+ sheet_stack.add_named(&rent_sheet, Some("rent"));
+ sheet_stack.add_named(&ret_sheet, Some("return"));
+
+ let sheet_box = Box::builder()
+ .orientation(Orientation::Vertical)
+ .margin_top(34)
+ .margin_bottom(18)
+ .margin_start(16)
+ .margin_end(16)
+ .build();
+ sheet_box.append(&sheet_stack);
+
+ let bottom_sheet = BottomSheet::builder()
+ .show_drag_handle(true)
+ .sheet(&sheet_box)
+ .build();
+
+ let main_content = Box::builder().orientation(Orientation::Vertical).build();
+ main_content.append(&scroll);
+ main_content.append(&rent_btn);
+ bottom_sheet.set_content(Some(&main_content));
+
+ let main_body = Box::builder().orientation(Orientation::Vertical).build();
+ main_body.append(&main_hdr);
+ main_body.append(&bottom_sheet);
+
+ let main_page = NavigationPage::builder()
+ .title("NextCompanion")
+ .child(&main_body)
+ .build();
+
+ // ── Navigation view ───────────────────────────────────────────────────────
+ let nav = NavigationView::new();
+ nav.push(&main_page);
+ if loginkey.borrow().is_none() {
+ nav.push(&login_page);
+ }
+
+ // ── Window ────────────────────────────────────────────────────────────────
+ let window = ApplicationWindow::builder()
+ .application(app)
+ .title("NextCompanion")
+ .default_width(390)
+ .default_height(700)
+ .content(&nav)
+ .build();
+
+ // ── Login button ──────────────────────────────────────────────────────────
+ {
+ let phone = phone_entry.clone();
+ let pin = pin_entry.clone();
+ let err = login_err.clone();
+ let spinner = login_spinner.clone();
+ let btn = login_btn.clone();
+ let nav = nav.clone();
+ let loginkey = loginkey.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ login_btn.connect_clicked(move |_| {
+ let p = phone.text().to_string();
+ let n = pin.text().to_string();
+ if p.is_empty() || n.is_empty() {
+ err.set_label("Phone and PIN are required");
+ err.set_visible(true);
+ return;
+ }
+ err.set_visible(false);
+ spinner.set_spinning(true);
+ btn.set_sensitive(false);
+
+ let spinner = spinner.clone();
+ let btn = btn.clone();
+ let err = err.clone();
+ let nav = nav.clone();
+ let loginkey = loginkey.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ glib::MainContext::default().spawn_local(async move {
+ let result = match gio::spawn_blocking(move || api_login(&p, &n)).await {
+ Ok(r) => r,
+ Err(_) => Err("Internal error".to_string()),
+ };
+ spinner.set_spinning(false);
+ btn.set_sensitive(true);
+ match result {
+ Ok(key) => {
+ save_loginkey(&key);
+ *loginkey.borrow_mut() = Some(key.clone());
+ nav.pop();
+ load_rentals(key, bikes, bikes_list, list_stack).await;
+ }
+ Err(e) => {
+ err.set_label(&e);
+ err.set_visible(true);
+ }
+ }
+ });
+ });
+ }
+
+ // ── Logout button ─────────────────────────────────────────────────────────
+ {
+ let nav = nav.clone();
+ let login_page = login_page.clone();
+ let loginkey = loginkey.clone();
+ logout_btn.connect_clicked(move |_| {
+ clear_loginkey();
+ *loginkey.borrow_mut() = None;
+ nav.push(&login_page);
+ });
+ }
+
+ // ── Refresh button ────────────────────────────────────────────────────────
+ {
+ let loginkey = loginkey.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ refresh_btn.connect_clicked(move |_| {
+ if let Some(key) = loginkey.borrow().clone() {
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ glib::MainContext::default().spawn_local(async move {
+ load_rentals(key, bikes, bikes_list, list_stack).await;
+ });
+ }
+ });
+ }
+
+ // ── Open rent sheet ───────────────────────────────────────────────────────
+ {
+ let bottom_sheet = bottom_sheet.clone();
+ let sheet_stack = sheet_stack.clone();
+ let bike_entry = bike_entry.clone();
+ let rent_err = rent_err.clone();
+ rent_btn.connect_clicked(move |_| {
+ bike_entry.set_text("");
+ rent_err.set_visible(false);
+ sheet_stack.set_visible_child_name("rent");
+ bottom_sheet.set_open(true);
+ });
+ }
+
+ // ── Rent submit ───────────────────────────────────────────────────────────
+ {
+ let loginkey = loginkey.clone();
+ let entry = bike_entry.clone();
+ let err = rent_err.clone();
+ let spinner = rent_spinner.clone();
+ let btn = rent_submit.clone();
+ let bottom_sheet = bottom_sheet.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ rent_submit.connect_clicked(move |_| {
+ let id = entry.text().to_string();
+ if id.is_empty() {
+ err.set_label("Enter a bike number");
+ err.set_visible(true);
+ return;
+ }
+ if let Some(key) = loginkey.borrow().clone() {
+ err.set_visible(false);
+ spinner.set_spinning(true);
+ btn.set_sensitive(false);
+
+ let spinner = spinner.clone();
+ let btn = btn.clone();
+ let err = err.clone();
+ let bottom_sheet = bottom_sheet.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ let key_reload = key.clone();
+ glib::MainContext::default().spawn_local(async move {
+ let result = match gio::spawn_blocking(move || api_rent(&key, &id)).await {
+ Ok(r) => r,
+ Err(_) => Err("Internal error".to_string()),
+ };
+ spinner.set_spinning(false);
+ btn.set_sensitive(true);
+ if let Err(e) = result {
+ err.set_label(&e);
+ err.set_visible(true);
+ } else {
+ bottom_sheet.set_open(false);
+ load_rentals(key_reload, bikes, bikes_list, list_stack).await;
+ }
+ });
+ }
+ });
+ }
+
+ // ── Click rental row → open return bottom sheet ───────────────────────────
+ {
+ let bottom_sheet = bottom_sheet.clone();
+ let sheet_stack = sheet_stack.clone();
+ let bikes = bikes.clone();
+ let return_bike = return_bike.clone();
+ let ret_inner = ret_inner.clone();
+ let station_entry = station_entry.clone();
+ let ret_err = ret_err.clone();
+ bikes_list.connect_row_activated(move |_, row| {
+ let idx = row.index() as usize;
+ let bike = bikes.borrow().get(idx).cloned();
+ if let Some(bike) = bike {
+ station_entry.set_text("");
+ ret_err.set_visible(false);
+ ret_inner.set_visible_child_name(if bike.electric_lock { "electric" } else { "manual" });
+ *return_bike.borrow_mut() = Some(bike);
+ sheet_stack.set_visible_child_name("return");
+ bottom_sheet.set_open(true);
+ }
+ });
+ }
+
+ // ── Return submit ─────────────────────────────────────────────────────────
+ {
+ let loginkey = loginkey.clone();
+ let return_bike = return_bike.clone();
+ let entry = station_entry.clone();
+ let err = ret_err.clone();
+ let spinner = ret_spinner.clone();
+ let btn = ret_submit.clone();
+ let bottom_sheet = bottom_sheet.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ ret_submit.connect_clicked(move |_| {
+ let station = entry.text().to_string();
+ if station.is_empty() {
+ err.set_label("Enter a station number");
+ err.set_visible(true);
+ return;
+ }
+ if let (Some(key), Some(bike)) =
+ (loginkey.borrow().clone(), return_bike.borrow().clone())
+ {
+ err.set_visible(false);
+ spinner.set_spinning(true);
+ btn.set_sensitive(false);
+
+ let spinner = spinner.clone();
+ let btn = btn.clone();
+ let err = err.clone();
+ let bottom_sheet = bottom_sheet.clone();
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ let key_reload = key.clone();
+ glib::MainContext::default().spawn_local(async move {
+ let result = match gio::spawn_blocking(move || {
+ api_return(&key, &bike.id, &station)
+ })
+ .await
+ {
+ Ok(r) => r,
+ Err(_) => Err("Internal error".to_string()),
+ };
+ spinner.set_spinning(false);
+ btn.set_sensitive(true);
+ if let Err(e) = result {
+ err.set_label(&e);
+ err.set_visible(true);
+ } else {
+ bottom_sheet.set_open(false);
+ load_rentals(key_reload, bikes, bikes_list, list_stack).await;
+ }
+ });
+ }
+ });
+ }
+
+ // ── Initial rentals load ──────────────────────────────────────────────────
+ if let Some(key) = loginkey.borrow().clone() {
+ let bikes = bikes.clone();
+ let bikes_list = bikes_list.clone();
+ let list_stack = list_stack.clone();
+ glib::MainContext::default().spawn_local(async move {
+ load_rentals(key, bikes, bikes_list, list_stack).await;
+ });
+ }
+
+ window.present();
+}