diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index f83a72de9..d8781bb0c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -6,7 +6,7 @@ body: id: desc attributes: label: Bug Description - description: A clear and concise description of what the bug is + description: A clear and concise description of what the bug is (if it's a keyboard issue, provide the keyboard mode you're using. e.g. legacy, map, translate) validations: required: true - type: textarea diff --git a/Cargo.lock b/Cargo.lock index 1029bfed4..c48a69e8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ "gimli", ] @@ -17,12 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "ahash" version = "0.7.6" @@ -111,12 +105,12 @@ dependencies = [ [[package]] name = "android_logger" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e9dd62f37dea550caf48c77591dc50bd1a378ce08855be1a0c42a97b7550fb" +checksum = "8619b80c242aa7bd638b5c7ddd952addeecb71f69c75e33f1d47b2804f8f883a" dependencies = [ "android_log-sys", - "env_logger 0.9.3", + "env_logger 0.10.0", "log", "once_cell", ] @@ -141,23 +135,24 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "arboard" -version = "2.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc120354d1b5ec6d7aaf4876b602def75595937b5e15d356eb554ab5177e08bb" +checksum = "d6041616acea41d67c4a984709ddab1587fd0b10efe5cc563fee954d2f011854" dependencies = [ "clipboard-win", "core-graphics 0.22.3", - "image 0.23.14", + "image", "log", "objc", "objc-foundation", "objc_id", + "once_cell", "parking_lot 0.12.1", "thiserror", "winapi 0.3.9", @@ -166,13 +161,12 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" dependencies = [ "event-listener", "futures-core", - "parking_lot 0.12.1", ] [[package]] @@ -200,6 +194,18 @@ dependencies = [ "slab", ] +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock", + "autocfg 1.1.0", + "blocking", + "futures-lite", +] + [[package]] name = "async-io" version = "1.12.0" @@ -215,19 +221,18 @@ dependencies = [ "parking", "polling", "slab", - "socket2 0.4.7", + "socket2 0.4.9", "waker-fn", "windows-sys 0.42.0", ] [[package]] name = "async-lock" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", - "futures-lite", ] [[package]] @@ -250,13 +255,13 @@ dependencies = [ [[package]] name = "async-recursion" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" +checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -267,13 +272,13 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -284,7 +289,7 @@ checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" dependencies = [ "atk-sys", "bitflags", - "glib 0.16.5", + "glib 0.16.7", "libc", ] @@ -311,9 +316,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -321,7 +326,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi 0.3.9", ] @@ -343,24 +348,30 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", - "miniz_oxide 0.5.4", + "miniz_oxide", "object", "rustc-demangle", ] [[package]] -name = "base64" -version = "0.13.1" +name = "base-x" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bindgen" @@ -377,12 +388,12 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "regex", "rustc-hash", "shlex", - "which 4.3.0", + "which", ] [[package]] @@ -397,19 +408,41 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "regex", "rustc-hash", "shlex", - "syn 1.0.105", + "syn 1.0.109", +] + +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2 1.0.51", + "quote 1.0.23", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", ] [[package]] name = "bit_field" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -437,9 +470,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -471,9 +504,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -487,15 +520,15 @@ checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytemuck" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -505,11 +538,11 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -520,7 +553,7 @@ checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" dependencies = [ "bitflags", "cairo-sys-rs", - "glib 0.16.5", + "glib 0.16.7", "libc", "once_cell", "thiserror", @@ -549,11 +582,11 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "6031a462f977dd38968b6f23378356512feeace69cef817e1a4475108093cec3" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -562,7 +595,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -573,9 +606,9 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.14", - "serde 1.0.149", - "serde_json 1.0.89", + "semver 1.0.16", + "serde 1.0.154", + "serde_json 1.0.94", ] [[package]] @@ -585,23 +618,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" dependencies = [ "clap 3.2.23", - "heck 0.4.0", + "heck 0.4.1", "indexmap", "log", - "proc-macro2 1.0.47", - "quote 1.0.21", - "serde 1.0.149", - "serde_json 1.0.89", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "serde 1.0.154", + "serde_json 1.0.94", + "syn 1.0.109", "tempfile", - "toml", + "toml 0.5.11", ] [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -659,9 +692,9 @@ dependencies = [ [[package]] name = "cidr-utils" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355d5b5df67e58b523953d0c1a8d3d2c05f5af51f1332b0199b9c92263614ed0" +checksum = "fdfa36f04861d39453affe1cf084ce2d6554021a84eb6f31ebdeafb6fb92a01c" dependencies = [ "debug-helper", "num-bigint", @@ -672,9 +705,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -705,7 +738,7 @@ dependencies = [ "atty", "bitflags", "clap_derive", - "clap_lex", + "clap_lex 0.2.4", "indexmap", "once_cell", "strsim 0.10.0", @@ -713,17 +746,30 @@ dependencies = [ "textwrap 0.16.0", ] +[[package]] +name = "clap" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +dependencies = [ + "bitflags", + "clap_lex 0.3.2", + "is-terminal", + "strsim 0.10.0", + "termcolor", +] + [[package]] name = "clap_derive" version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ - "heck 0.4.0", + "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -735,6 +781,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clipboard" version = "0.1.0" @@ -742,16 +797,16 @@ dependencies = [ "cc", "hbb_common", "lazy_static", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", "thiserror", ] [[package]] name = "clipboard-win" -version = "4.4.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" dependencies = [ "error-code", "str-buf", @@ -823,6 +878,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colored" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +dependencies = [ + "atty", + "lazy_static", + "winapi 0.3.9", +] + [[package]] name = "combine" version = "4.6.6" @@ -835,9 +901,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -848,9 +914,9 @@ version = "0.4.0" source = "git+https://github.com/open-trade/confy#630cc28a396cb7d01eefdd9f3824486fe4d8554b" dependencies = [ "directories-next", - "serde 1.0.149", + "serde 1.0.154", "thiserror", - "toml", + "toml 0.5.11", ] [[package]] @@ -972,27 +1038,26 @@ dependencies = [ [[package]] name = "cpal" -version = "0.13.5" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116" +checksum = "f342c1b63e185e9953584ff2199726bf53850d96610a310e3aca09e9405a2d0b" dependencies = [ "alsa", "core-foundation-sys 0.8.3", "coreaudio-rs", "jni 0.19.0", "js-sys", - "lazy_static", "libc", "mach", - "ndk 0.6.0", - "ndk-glue 0.6.2", - "nix 0.23.2", + "ndk 0.7.0", + "ndk-context", "oboe", - "parking_lot 0.11.2", + "once_cell", + "parking_lot 0.12.1", "stdweb", "thiserror", "web-sys", - "winapi 0.3.9", + "windows 0.37.0", ] [[package]] @@ -1015,9 +1080,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -1025,9 +1090,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -1036,14 +1101,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset 0.8.0", "scopeguard", ] @@ -1059,9 +1124,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if 1.0.0", ] @@ -1084,12 +1149,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.4" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71" +checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" dependencies = [ - "nix 0.26.1", - "windows-sys 0.42.0", + "nix 0.26.2", + "windows-sys 0.45.0", ] [[package]] @@ -1100,9 +1165,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "cxx" -version = "1.0.83" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" +checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" dependencies = [ "cc", "cxxbridge-flags", @@ -1112,34 +1177,34 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.83" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" +checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "scratch", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] name = "cxxbridge-flags" -version = "1.0.83" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" +checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" [[package]] name = "cxxbridge-macro" -version = "1.0.83" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" +checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1187,10 +1252,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "strsim 0.9.3", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] @@ -1201,10 +1266,10 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "strsim 0.10.0", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] @@ -1214,8 +1279,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core 0.10.2", - "quote 1.0.21", - "syn 1.0.105", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1225,8 +1290,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.21", - "syn 1.0.105", + "quote 1.0.23", + "syn 1.0.109", +] + +[[package]] +name = "dart-sys" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d8b5680b5c2cc52f50acb2457d9b3a3b58adcca785db13a0e3655626f601de6" +dependencies = [ + "cc", ] [[package]] @@ -1350,9 +1424,9 @@ dependencies = [ [[package]] name = "dbus" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8bcdd56d2e5c4ed26a529c5a9029f5db8290d433497506f958eae3be148eb6" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" dependencies = [ "libc", "libdbus-sys", @@ -1361,9 +1435,9 @@ dependencies = [ [[package]] name = "dbus-crossroads" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554114296d012b33fdaf362a733db6dc5f73c4c9348b8b620ddd42e61b406e30" +checksum = "3a4c83437187544ba5142427746835061b330446ca8902eabd70e4afb8f76de0" dependencies = [ "dbus", ] @@ -1392,25 +1466,15 @@ dependencies = [ "windows 0.30.0", ] -[[package]] -name = "deflate" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" -dependencies = [ - "adler32", - "byteorder", -] - [[package]] name = "delegate" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "082a24a9967533dc5d743c602157637116fc1b52806d694a5a45e6f32567fcdd" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1419,9 +1483,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1431,9 +1495,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1cf41b4580a37cca5ef2ada2cc43cf5d6be3983f4522e83010d67ab6925e84b" dependencies = [ "darling 0.10.2", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1513,6 +1577,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dispatch" version = "0.2.0" @@ -1565,7 +1635,7 @@ checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" dependencies = [ "lazy_static", "regex", - "serde 1.0.149", + "serde 1.0.154", "strsim 0.10.0", ] @@ -1588,25 +1658,25 @@ dependencies = [ "cc", "hbb_common", "lazy_static", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", "thiserror", ] [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "embed-resource" @@ -1616,16 +1686,16 @@ checksum = "e62abb876c07e4754fae5c14cafa77937841f01740637e17d78dc04352f32a5e" dependencies = [ "cc", "rustc_version 0.4.0", - "toml", + "toml 0.5.11", "vswhom", "winreg 0.10.1", ] [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if 1.0.0", ] @@ -1640,7 +1710,7 @@ dependencies = [ "objc", "pkg-config", "rdev", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", "tfc", "unicode-segmentation", @@ -1649,34 +1719,34 @@ dependencies = [ [[package]] name = "enum-map" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a56d54c8dd9b3ad34752ed197a4eb2a6601bc010808eb097a04a58ae4c43e1" +checksum = "50c25992259941eb7e57b936157961b217a4fc8597829ddef0596d6c3cd86e1a" dependencies = [ "enum-map-derive", ] [[package]] name = "enum-map-derive" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9045e2676cd5af83c3b167d917b0a5c90a4d8e266e2683d6631b235c457fc27" +checksum = "2a4da76b3b6116d758c7ba93f7ec6a35d2e2cf24feda76c6e38a375f4d5c59f2" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] name = "enum_dispatch" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb" +checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" dependencies = [ "once_cell", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1686,7 +1756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -1695,9 +1765,9 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -1723,6 +1793,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "epoll" version = "4.3.1" @@ -1740,10 +1823,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "rustversion", - "syn 1.0.105", + "syn 1.0.109", "synstructure", ] @@ -1758,6 +1841,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1804,62 +1898,52 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide 0.6.2", + "miniz_oxide", "smallvec", "threadpool", "zune-inflate", ] -[[package]] -name = "extend" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610" -dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", -] - [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] -name = "field-offset" -version = "0.3.4" +name = "fern" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" +checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" dependencies = [ - "memoffset 0.6.5", - "rustc_version 0.3.3", + "chrono", + "colored", + "log", +] + +[[package]] +name = "field-offset" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" +dependencies = [ + "memoffset 0.8.0", + "rustc_version 0.4.0", ] [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -1869,27 +1953,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", - "miniz_oxide 0.6.2", + "miniz_oxide", ] [[package]] name = "flexi_logger" -version = "0.22.6" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c76a80dd14a27fc3d8bc696502132cb52b3f227256fd8601166c3a35e45f409" +checksum = "6eae57842a8221ef13f1f207632d786a175dd13bd8fbdc8be9d852f7c9cf1046" dependencies = [ - "ansi_term", - "atty", "chrono", "crossbeam-channel", "crossbeam-queue", "glob", + "is-terminal", "lazy_static", "log", + "nu-ansi-term", "regex", - "rustversion", "thiserror", - "time 0.3.9", ] [[package]] @@ -1907,9 +1989,9 @@ dependencies = [ [[package]] name = "flutter_rust_bridge" -version = "1.61.1" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8079119bbe8fb63d7ebb731fa2aa68c6c8375f4ac95ca26d5868e64c0f4b9244" +checksum = "54f0d71ff30fc2ae7c18508b517488a89051d81e3bfc4d48d4a6cf54b5dab789" dependencies = [ "allo-isolate", "anyhow", @@ -1918,6 +2000,7 @@ dependencies = [ "cc", "chrono", "console_error_panic_hook", + "dart-sys", "flutter_rust_bridge_macros", "js-sys", "lazy_static", @@ -1931,39 +2014,41 @@ dependencies = [ [[package]] name = "flutter_rust_bridge_codegen" -version = "1.61.1" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd7396bc479eae8aa24243e4c0e3d3dbda1909134f8de6bde4f080d262c9a0d" +checksum = "2a2a75a72411f0c5b480e4671417f52780172053128cf87d5614a9757d7680a0" dependencies = [ "anyhow", + "atty", "cargo_metadata", "cbindgen", + "chrono", "clap 3.2.23", "convert_case", "delegate", "enum_dispatch", - "env_logger 0.9.3", - "extend", + "fern", "itertools 0.10.5", "lazy_static", "log", "pathdiff", - "quote 1.0.21", + "quote 1.0.23", "regex", - "serde 1.0.149", + "serde 1.0.154", "serde_yaml", - "syn 1.0.105", + "strum_macros 0.24.3", + "syn 1.0.109", "tempfile", "thiserror", - "toml", + "toml 0.5.11", "topological-sort", ] [[package]] name = "flutter_rust_bridge_macros" -version = "1.61.1" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5cd827645690ef378be57a890d0581e17c28d07b712872af7d744f454fd27d" +checksum = "f6187d1635afede47c23a9979f85c3dc57e3391eb9c690b7fe95715bf945da72" [[package]] name = "fnv" @@ -2038,9 +2123,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -2053,9 +2138,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -2063,15 +2148,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -2080,9 +2165,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" @@ -2101,32 +2186,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -2140,15 +2225,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" version = "0.16.2" @@ -2160,7 +2236,7 @@ dependencies = [ "gdk-pixbuf", "gdk-sys", "gio", - "glib 0.16.5", + "glib 0.16.7", "libc", "pango", ] @@ -2174,7 +2250,7 @@ dependencies = [ "bitflags", "gdk-pixbuf-sys", "gio", - "glib 0.16.5", + "glib 0.16.7", "libc", ] @@ -2232,7 +2308,7 @@ dependencies = [ "glib-sys 0.16.3", "libc", "system-deps 6.0.3", - "x11 2.20.1", + "x11 2.21.0", ] [[package]] @@ -2280,9 +2356,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.2" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "gio" @@ -2296,7 +2372,7 @@ dependencies = [ "futures-io", "futures-util", "gio-sys", - "glib 0.16.5", + "glib 0.16.7", "libc", "once_cell", "pin-project-lite", @@ -2338,9 +2414,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.16.5" +version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd04d150a2c63e6779f43aec7e04f5374252479b7bed5f45146d9c0e821f161" +checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" dependencies = [ "bitflags", "futures-channel", @@ -2369,9 +2445,9 @@ dependencies = [ "itertools 0.9.0", "proc-macro-crate 0.1.5", "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -2381,12 +2457,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e084807350b01348b6d9dbabb724d1a0bb987f47a2c85de200e98e12e30733bf" dependencies = [ "anyhow", - "heck 0.4.0", - "proc-macro-crate 1.2.1", + "heck 0.4.1", + "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -2411,9 +2487,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gobject-sys" @@ -2584,7 +2660,7 @@ dependencies = [ "gdk", "gdk-pixbuf", "gio", - "glib 0.16.5", + "glib 0.16.7", "gtk-sys", "gtk3-macros", "libc", @@ -2618,18 +2694,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfd6557b1018b773e43c8de9d0d13581d6b36190d0501916cbec4731db5ccff" dependencies = [ "anyhow", - "proc-macro-crate 1.2.1", + "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] name = "h2" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -2673,7 +2749,7 @@ dependencies = [ "confy", "directories-next", "dirs-next", - "env_logger 0.9.3", + "env_logger 0.10.0", "filetime", "flexi_logger", "futures", @@ -2689,16 +2765,16 @@ dependencies = [ "quinn", "rand 0.8.5", "regex", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", - "serde_json 1.0.89", + "serde_json 1.0.94", "socket2 0.3.19", "sodiumoxide", "sysinfo", "tokio", "tokio-socks", "tokio-util", - "toml", + "toml 0.7.2", "winapi 0.3.9", "zstd", ] @@ -2714,9 +2790,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -2727,6 +2803,21 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -2741,13 +2832,13 @@ checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", - "itoa 1.0.4", + "itoa 1.0.6", ] [[package]] @@ -2782,21 +2873,21 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hwcodec" version = "0.1.0" -source = "git+https://github.com/21pages/hwcodec#64f885b3787694b16dfcff08256750b0376b2eba" +source = "git+https://github.com/21pages/hwcodec#d55f7761ef692fae738259d8c14506d901eb824c" dependencies = [ "bindgen 0.59.2", "cc", "log", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", - "serde_json 1.0.89", + "serde_json 1.0.94", ] [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -2807,9 +2898,9 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.4", + "itoa 1.0.6", "pin-project-lite", - "socket2 0.4.7", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2869,22 +2960,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "image" -version = "0.23.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-iter", - "num-rational 0.3.2", - "num-traits 0.2.15", - "png 0.16.8", - "tiff 0.6.1", -] - [[package]] name = "image" version = "0.24.5" @@ -2896,12 +2971,12 @@ dependencies = [ "color_quant", "exr", "gif", - "jpeg-decoder 0.3.0", + "jpeg-decoder", "num-rational 0.4.1", "num-traits 0.2.15", - "png 0.17.7", + "png", "scoped_threadpool", - "tiff 0.8.1", + "tiff", ] [[package]] @@ -2927,8 +3002,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", ] [[package]] @@ -2973,6 +3048,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "io-lifetimes" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "iovec" version = "0.1.4" @@ -2984,9 +3069,21 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec947b7a4ce12e3b87e353abae7ce124d025b6c7d6c5aea5cc0bcf92e9510ded" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] +name = "is-terminal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] [[package]] name = "itertools" @@ -3014,9 +3111,9 @@ checksum = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jni" @@ -3054,19 +3151,13 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" - [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -3078,9 +3169,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3102,7 +3193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" dependencies = [ "bitflags", - "serde 1.0.149", + "serde 1.0.154", "unicode-segmentation", ] @@ -3130,7 +3221,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e1edfdc9b0853358306c6dfb4b77c79c779174256fe93d80c0b5ebca451a2f" dependencies = [ - "glib 0.16.5", + "glib 0.16.7", "gtk", "gtk-sys", "libappindicator-sys", @@ -3150,15 +3241,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libdbus-sys" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" +checksum = "9f8d7ae751e1cb825c840ae5e682f59b098cdfd213c350ac268b61449a5f58a0" dependencies = [ "pkg-config", ] @@ -3175,9 +3266,9 @@ dependencies = [ [[package]] name = "libpulse-binding" -version = "2.26.0" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17be42160017e0ae993c03bfdab4ecb6f82ce3f8d515bd8da8fdf18d10703663" +checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" dependencies = [ "bitflags", "libc", @@ -3189,9 +3280,9 @@ dependencies = [ [[package]] name = "libpulse-simple-binding" -version = "2.25.0" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cbf1a1dfd69a48cb60906399fa1d17f1b75029ef51c0789597be792dfd0bcd5" +checksum = "5ced94199e6e44133431374e4043f34e1f0697ebfb7b7d6c244a65bfaedf0e31" dependencies = [ "libpulse-binding", "libpulse-simple-sys", @@ -3200,9 +3291,9 @@ dependencies = [ [[package]] name = "libpulse-simple-sys" -version = "1.19.2" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c73f96f9ca34809692c4760cfe421225860aa000de50edab68a16221fd27cc1" +checksum = "84e423d9c619c908ce9b4916080e65ab586ca55b8c4939379f15e6e72fb43842" dependencies = [ "libpulse-sys", "pkg-config", @@ -3210,9 +3301,9 @@ dependencies = [ [[package]] name = "libpulse-sys" -version = "1.19.3" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991e6bd0efe2a36e6534e136e7996925e4c1a8e35b7807fe533f2beffff27c30" +checksum = "2191e6880818d1df4cf72eac8e91dce7a5a52ba0da4b2a5cdafabc22b937eadb" dependencies = [ "libc", "num-derive", @@ -3258,14 +3349,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" dependencies = [ "libc", - "x11 2.20.1", + "x11 2.21.0", +] + +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", ] [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] @@ -3276,6 +3376,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -3386,6 +3492,15 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "mime" version = "0.3.16" @@ -3398,34 +3513,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg 1.1.0", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.6.2" @@ -3456,14 +3543,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3518,9 +3605,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66365a21dc5e322c6b6ba25c735d00153c57dd2eb377926aa50e3caf547b6f6" +checksum = "0ee091608fe840d80c6b25e8f838964b264ee8e02e82ae0a38b2d900464d1582" dependencies = [ "cocoa", "crossbeam-channel", @@ -3531,7 +3618,7 @@ dependencies = [ "libxdo", "objc", "once_cell", - "png 0.17.7", + "png", "thiserror", "windows-sys 0.45.0", ] @@ -3587,7 +3674,7 @@ dependencies = [ "jni-sys", "ndk-sys 0.4.1+23.1.7779620", "num_enum", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.1", "thiserror", ] @@ -3612,21 +3699,6 @@ dependencies = [ "ndk-sys 0.2.2", ] -[[package]] -name = "ndk-glue" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" -dependencies = [ - "lazy_static", - "libc", - "log", - "ndk 0.6.0", - "ndk-context", - "ndk-macro", - "ndk-sys 0.3.0", -] - [[package]] name = "ndk-macro" version = "0.3.0" @@ -3634,10 +3706,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" dependencies = [ "darling 0.13.4", - "proc-macro-crate 1.2.1", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -3715,35 +3787,23 @@ dependencies = [ [[package]] name = "nix" -version = "0.25.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "autocfg 1.1.0", "bitflags", "cfg-if 1.0.0", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", "pin-utils", -] - -[[package]] -name = "nix" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "libc", "static_assertions", ] [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -3751,13 +3811,23 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.7" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi 0.3.9", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -3771,9 +3841,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits 0.2.15", ] @@ -3784,9 +3854,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -3799,17 +3869,6 @@ dependencies = [ "num-traits 0.2.15", ] -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg 1.1.0", - "num-integer", - "num-traits 0.2.15", -] - [[package]] name = "num-rational" version = "0.3.2" @@ -3852,42 +3911,33 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "num_enum" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate 1.2.1", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -3931,9 +3981,9 @@ dependencies = [ [[package]] name = "object" -version = "0.29.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -3963,9 +4013,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl-probe" @@ -3985,14 +4035,26 @@ dependencies = [ [[package]] name = "ordered-stream" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ca8c99d73c6e92ac1358f9f692c22c0bfd9c4701fa086f5d365c0d4ea818ea" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" dependencies = [ "futures-core", "pin-project-lite", ] +[[package]] +name = "os-version" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8a1fed76ac765e39058ca106b6229a93c5a60292a1bd4b602ce2be11e1c020" +dependencies = [ + "anyhow", + "plist", + "uname", + "winapi 0.3.9", +] + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -4005,11 +4067,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38731fa859ef679f1aec66ca9562165926b442f298467f76f5990f431efe87dc" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", "serde_derive", - "serde_json 1.0.89", + "serde_json 1.0.94", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pango" version = "0.16.5" @@ -4018,7 +4086,7 @@ checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" dependencies = [ "bitflags", "gio", - "glib 0.16.5", + "glib 0.16.7", "libc", "once_cell", "pango-sys", @@ -4065,7 +4133,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -4075,14 +4143,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if 1.0.0", "instant", @@ -4094,22 +4162,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pathdiff" @@ -4129,16 +4197,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "pest" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" -dependencies = [ - "thiserror", - "ucd-trie", -] - [[package]] name = "phf" version = "0.7.24" @@ -4192,9 +4250,9 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -4216,15 +4274,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] -name = "png" -version = "0.16.8" +name = "plist" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +checksum = "ffac6a51110e97610dd3ac73e34a65b27e56a1e305df41bad1f616d8e1cb22f4" dependencies = [ - "bitflags", - "crc32fast", - "deflate", - "miniz_oxide 0.3.7", + "base64", + "indexmap", + "line-wrap", + "quick-xml", + "serde 1.0.154", + "time 0.3.20", ] [[package]] @@ -4236,21 +4296,23 @@ dependencies = [ "bitflags", "crc32fast", "flate2", - "miniz_oxide 0.6.2", + "miniz_oxide", ] [[package]] name = "polling" -version = "2.5.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748" +checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" dependencies = [ "autocfg 1.1.0", + "bitflags", "cfg-if 1.0.0", + "concurrent-queue", "libc", "log", - "wepoll-ffi", - "windows-sys 0.42.0", + "pin-project-lite", + "windows-sys 0.45.0", ] [[package]] @@ -4280,18 +4342,17 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "thiserror", - "toml", + "toml_edit", ] [[package]] @@ -4301,9 +4362,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", "version_check", ] @@ -4313,8 +4374,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "version_check", ] @@ -4329,9 +4390,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -4376,7 +4437,7 @@ dependencies = [ "protobuf-support", "tempfile", "thiserror", - "which 4.3.0", + "which", ] [[package]] @@ -4402,17 +4463,25 @@ dependencies = [ ] [[package]] -name = "quinn" -version = "0.8.5" +name = "quick-xml" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b435e71d9bfa0d8889927231970c51fb89c58fa63bffcab117c9c7a41e5ef8f" +checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445cbfe2382fa023c4f2f3c7e1c95c03dcc1df2bf23cebcb2b13e1402c4394d1" dependencies = [ "bytes", - "futures-channel", - "futures-util", - "fxhash", + "pin-project-lite", "quinn-proto", "quinn-udp", + "rustc-hash", "rustls", "thiserror", "tokio", @@ -4422,17 +4491,16 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.8.4" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce546b9688f767a57530652488420d419a8b1f44a478b451c3d1ab6d992a55" +checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" dependencies = [ "bytes", - "fxhash", "rand 0.8.5", "ring", + "rustc-hash", "rustls", "rustls-native-certs", - "rustls-pemfile 0.2.1", "slab", "thiserror", "tinyvec", @@ -4442,16 +4510,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07946277141531aea269befd949ed16b2c85a780ba1043244eda0969e538e54" +checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ - "futures-util", "libc", "quinn-proto", - "socket2 0.4.7", - "tokio", + "socket2 0.4.9", "tracing", + "windows-sys 0.42.0", ] [[package]] @@ -4465,11 +4532,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ - "proc-macro2 1.0.47", + "proc-macro2 1.0.51", ] [[package]] @@ -4625,18 +4692,15 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] +checksum = "4f851a03551ceefd30132e447f07f96cb7011d6b658374f3aed847333adb5559" [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -4644,9 +4708,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -4670,12 +4734,12 @@ dependencies = [ "lazy_static", "libc", "log", - "mio 0.8.5", + "mio 0.8.6", "strum 0.24.1", "strum_macros 0.24.3", "widestring 1.0.2", "winapi 0.3.9", - "x11 2.20.1", + "x11 2.21.0", ] [[package]] @@ -4718,9 +4782,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -4733,15 +4797,6 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "repng" version = "0.2.2" @@ -4754,9 +4809,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ "base64", "bytes", @@ -4776,9 +4831,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile 1.0.1", - "serde 1.0.149", - "serde_json 1.0.89", + "rustls-pemfile", + "serde 1.0.154", + "serde_json 1.0.94", "serde_urlencoded", "tokio", "tokio-rustls", @@ -4852,12 +4907,12 @@ dependencies = [ [[package]] name = "runas" -version = "0.2.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a620b0994a180cdfa25c0439e6d58c0628272571501880d626ffff58e96a0799" +checksum = "ed87390fefd18965ff20baae5aeb9913bcf82d2b59dc04c0f6d8f17f7be56ff2" dependencies = [ "cc", - "which 3.1.1", + "which", ] [[package]] @@ -4892,11 +4947,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.11.0", + "semver 0.9.0", ] [[package]] @@ -4905,14 +4960,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver 1.0.16", ] [[package]] name = "rustdesk" version = "1.2.0" dependencies = [ - "android_logger 0.11.1", + "android_logger 0.11.3", "arboard", "async-process", "async-trait", @@ -4922,7 +4977,7 @@ dependencies = [ "cfg-if 1.0.0", "chrono", "cidr-utils", - "clap 3.2.23", + "clap 4.1.8", "clipboard", "cocoa", "core-foundation 0.9.3", @@ -4937,7 +4992,7 @@ dependencies = [ "dispatch", "dlopen", "enigo", - "errno", + "errno 0.3.0", "evdev", "flutter_rust_bridge", "flutter_rust_bridge_codegen", @@ -4945,7 +5000,7 @@ dependencies = [ "hbb_common", "hex", "hound", - "image 0.24.5", + "image", "impersonate_system", "include_dir", "jni 0.19.0", @@ -4959,6 +5014,7 @@ dependencies = [ "num_cpus", "objc", "objc_id", + "os-version", "parity-tokio-ipc", "rdev", "repng", @@ -4970,9 +5026,9 @@ dependencies = [ "samplerate", "sciter-rs", "scrap", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", - "serde_json 1.0.89", + "serde_json 1.0.94", "sha2", "shared_memory", "shutdown_hooks", @@ -5021,10 +5077,24 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.20.7" +name = "rustix" +version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +dependencies = [ + "bitflags", + "errno 0.2.8", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -5039,40 +5109,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.1", + "rustls-pemfile", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ "base64", ] [[package]] name = "rustversion" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "same-file" @@ -5094,12 +5161,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -5136,7 +5202,7 @@ name = "scrap" version = "0.5.0" dependencies = [ "android_logger 0.10.1", - "bindgen 0.59.2", + "bindgen 0.64.0", "block", "cfg-if 1.0.0", "dbus", @@ -5153,8 +5219,8 @@ dependencies = [ "num_cpus", "quest", "repng", - "serde 1.0.149", - "serde_json 1.0.89", + "serde 1.0.154", + "serde_json 1.0.94", "target_build_utils", "tracing", "webm", @@ -5163,9 +5229,9 @@ dependencies = [ [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "sct" @@ -5179,9 +5245,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation 0.9.3", @@ -5192,9 +5258,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys 0.8.3", "libc", @@ -5202,30 +5268,27 @@ dependencies = [ [[package]] name = "semver" -version = "0.11.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ "semver-parser", ] [[package]] name = "semver" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", ] [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" @@ -5235,22 +5298,22 @@ checksum = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" [[package]] name = "serde" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" +checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" +checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -5267,24 +5330,33 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ - "itoa 1.0.4", + "itoa 1.0.6", "ryu", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] name = "serde_repr" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde 1.0.154", ] [[package]] @@ -5294,9 +5366,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.4", + "itoa 1.0.6", "ryu", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -5307,10 +5379,19 @@ checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ "indexmap", "ryu", - "serde 1.0.149", + "serde 1.0.154", "yaml-rust", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + [[package]] name = "sha1" version = "0.10.5" @@ -5322,6 +5403,12 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.10.6" @@ -5360,9 +5447,9 @@ checksum = "6057adedbec913419c92996f395ba69931acbd50b7d56955394cd3f7bedbfa45" [[package]] name = "signal-hook" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" dependencies = [ "libc", "signal-hook-registry", @@ -5370,9 +5457,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -5395,7 +5482,7 @@ version = "0.1.0" dependencies = [ "confy", "hbb_common", - "serde 1.0.149", + "serde 1.0.154", "serde_derive", "walkdir", ] @@ -5408,9 +5495,9 @@ checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg 1.1.0", ] @@ -5453,9 +5540,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi 0.3.9", @@ -5470,7 +5557,7 @@ dependencies = [ "ed25519", "libc", "libsodium-sys", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -5496,9 +5583,52 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stdweb" -version = "0.1.3" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2 1.0.51", + "quote 1.0.23", + "serde 1.0.154", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2 1.0.51", + "quote 1.0.23", + "serde 1.0.154", + "serde_derive", + "serde_json 1.0.94", + "sha1 0.6.1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" [[package]] name = "str-buf" @@ -5549,9 +5679,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" dependencies = [ "heck 0.3.3", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -5560,11 +5690,11 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck 0.4.0", - "proc-macro2 1.0.47", - "quote 1.0.21", + "heck 0.4.1", + "proc-macro2 1.0.51", + "quote 1.0.23", "rustversion", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] @@ -5580,12 +5710,12 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.105" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "unicode-ident", ] @@ -5595,30 +5725,30 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", "unicode-xid 0.2.4", ] [[package]] name = "sys-locale" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3358acbb4acd4146138b9bda219e904a6bb5aaaa237f8eed06f4d6bc1580ecee" +checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee" dependencies = [ "js-sys", "libc", "wasm-bindgen", "web-sys", - "winapi 0.3.9", + "windows-sys 0.45.0", ] [[package]] name = "sysinfo" -version = "0.24.7" +version = "0.26.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb4ebf3d49308b99e6e9dc95e989e2fdbdc210e4f67c39db0bb89ba927001c" +checksum = "5c18a6156d1f27a9592ee18c1a846ca8dd5c258b7179fc193ae87c74ebb666f5" dependencies = [ "cfg-if 1.0.0", "core-foundation-sys 0.8.3", @@ -5661,7 +5791,7 @@ dependencies = [ "strum 0.18.0", "strum_macros 0.18.0", "thiserror", - "toml", + "toml 0.5.11", "version-compare 0.0.10", ] @@ -5672,19 +5802,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" dependencies = [ "cfg-expr", - "heck 0.4.0", + "heck 0.4.1", "pkg-config", - "toml", + "toml 0.5.11", "version-compare 0.1.1", ] [[package]] name = "system_shutdown" -version = "3.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035e081d603551d8d78db27d2232913269c749ea67648c369100049820406a14" +checksum = "7567f71160af5e9abfb4f5a21532cf2174cefe91ac5c336419295685a695cc66" dependencies = [ - "winapi 0.3.9", + "windows 0.44.0", + "zbus", ] [[package]] @@ -5706,10 +5837,10 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gio", - "glib 0.16.5", + "glib 0.16.7", "glib-sys 0.16.3", "gtk", - "image 0.24.5", + "image", "instant", "jni 0.20.0", "lazy_static", @@ -5721,8 +5852,8 @@ dependencies = [ "objc", "once_cell", "parking_lot 0.12.1", - "png 0.17.7", - "raw-window-handle 0.5.0", + "png", + "raw-window-handle 0.5.1", "scopeguard", "tao-macros", "unicode-segmentation", @@ -5737,9 +5868,9 @@ name = "tao-macros" version = "0.1.0" source = "git+https://github.com/tauri-apps/tao?branch=muda#676bd90a80286b893d8850cc4e3813a0c4a27dcf" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -5761,23 +5892,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if 1.0.0", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", + "rustix", + "windows-sys 0.42.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -5809,8 +5939,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "tfc" version = "0.6.1" -source = "git+https://github.com/fufesou/The-Fat-Controller#a5f13e6ef80327eb8d860aeb26b0af93eb5aee2b" +source = "git+https://github.com/fufesou/The-Fat-Controller#102f2ec2cb2bbbd64413d20d28323e5e77e0fe71" dependencies = [ + "anyhow", "core-graphics 0.22.3", "unicode-segmentation", "winapi 0.3.9", @@ -5819,22 +5950,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -5846,17 +5977,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "tiff" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" -dependencies = [ - "jpeg-decoder 0.1.22", - "miniz_oxide 0.4.4", - "weezl", -] - [[package]] name = "tiff" version = "0.8.1" @@ -5864,7 +5984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" dependencies = [ "flate2", - "jpeg-decoder 0.3.0", + "jpeg-decoder", "weezl", ] @@ -5881,21 +6001,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.9" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ - "itoa 1.0.4", - "libc", - "num_threads", + "itoa 1.0.6", + "serde 1.0.154", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] [[package]] name = "tinyvec" @@ -5908,28 +6037,28 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.23.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" dependencies = [ "autocfg 1.1.0", "bytes", "libc", "memchr", - "mio 0.8.5", + "mio 0.8.6", "num_cpus", "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.7", + "socket2 0.4.9", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -5938,9 +6067,9 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -5972,9 +6101,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -5990,11 +6119,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", +] + +[[package]] +name = "toml" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +dependencies = [ + "serde 1.0.154", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde 1.0.154", +] + +[[package]] +name = "toml_edit" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +dependencies = [ + "indexmap", + "serde 1.0.154", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -6027,9 +6190,9 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -6053,9 +6216,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d62801a4da61bb100b8d3174a5a46fed7b6ea03cc2ae93ee7340793b09a94ce3" +checksum = "f87445e3a107818c17d87e8369db30a6fc25539bface8351efe2132b22e47dbc" dependencies = [ "cocoa", "core-graphics 0.22.3", @@ -6065,7 +6228,7 @@ dependencies = [ "muda", "objc", "once_cell", - "png 0.17.7", + "png", "thiserror", "windows-sys 0.45.0", ] @@ -6081,9 +6244,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" @@ -6091,12 +6254,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - [[package]] name = "uds_windows" version = "1.0.2" @@ -6108,16 +6265,25 @@ dependencies = [ ] [[package]] -name = "unicode-bidi" -version = "0.3.8" +name = "uname" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -6130,9 +6296,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -6167,7 +6333,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -6273,9 +6439,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -6283,24 +6449,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6310,32 +6476,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ - "quote 1.0.21", + "quote 1.0.23", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wayland-client" @@ -6394,8 +6560,8 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro2 1.0.51", + "quote 1.0.23", "xml-rs", ] @@ -6412,9 +6578,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -6463,30 +6629,11 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "which" -version = "3.1.1" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -dependencies = [ - "failure", - "libc", -] - -[[package]] -name = "which" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -6495,11 +6642,10 @@ dependencies = [ [[package]] name = "whoami" -version = "1.2.3" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" +checksum = "45dbc71f0cdca27dc261a9bd37ddec174e4a0af2b900b890f378460f745426e3" dependencies = [ - "bumpalo", "wasm-bindgen", "web-sys", ] @@ -6603,6 +6749,19 @@ dependencies = [ "windows_x86_64_msvc 0.34.0", ] +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + [[package]] name = "windows" version = "0.44.0" @@ -6620,9 +6779,9 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -6631,9 +6790,9 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f" dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] [[package]] @@ -6661,19 +6820,6 @@ dependencies = [ "windows_x86_64_msvc 0.28.0", ] -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -6739,9 +6885,9 @@ checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" [[package]] name = "windows_aarch64_msvc" @@ -6769,9 +6915,9 @@ checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" [[package]] name = "windows_i686_gnu" @@ -6799,9 +6945,9 @@ checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" [[package]] name = "windows_i686_msvc" @@ -6829,9 +6975,9 @@ checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" [[package]] name = "windows_x86_64_gnu" @@ -6865,9 +7011,9 @@ checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" [[package]] name = "windows_x86_64_msvc" @@ -6891,9 +7037,9 @@ dependencies = [ "lazy_static", "libc", "log", - "mio 0.8.5", + "mio 0.8.6", "ndk 0.5.0", - "ndk-glue 0.5.2", + "ndk-glue", "ndk-sys 0.2.2", "objc", "parking_lot 0.11.2", @@ -6908,6 +7054,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "winnow" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.6.2" @@ -6932,17 +7087,14 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] name = "wol-rs" -version = "0.9.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f97e69b28b256ccfb02472c25057132e234aa8368fea3bb0268def564ce1f2" -dependencies = [ - "clap 3.2.23", -] +checksum = "48dc5e486e34a31515518d370cdd8bf59ec696323fe8f92b858e43942e84a765" [[package]] name = "ws2_32-sys" @@ -6974,9 +7126,9 @@ dependencies = [ [[package]] name = "x11" -version = "2.20.1" +version = "2.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2638d5b9c17ac40575fb54bb461a4b1d2a8d1b4ffcc4ff237d254ec59ddeb82" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" dependencies = [ "libc", "pkg-config", @@ -6995,14 +7147,24 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" +checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507" dependencies = [ "gethostname", - "nix 0.22.3", + "nix 0.24.3", "winapi 0.3.9", "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67" +dependencies = [ + "nix 0.24.3", ] [[package]] @@ -7027,7 +7189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5af43ba661cee58bd86b9f81a899e45a15ac7f42fa4401340f73c0c2950030c1" dependencies = [ "derive_setters", - "serde 1.0.149", + "serde 1.0.154", ] [[package]] @@ -7041,13 +7203,13 @@ dependencies = [ [[package]] name = "zbus" -version = "3.6.2" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938ea6da98c75c2c37a86007bd17fd8e208cbec24e086108c87ece98e9edec0d" +checksum = "20aae5dd5b051971cd2f49f9f3b860e57b2b495ba5ba254eaec42d34ede57e97" dependencies = [ "async-broadcast", - "async-channel", "async-executor", + "async-fs", "async-io", "async-lock", "async-recursion", @@ -7062,13 +7224,13 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix 0.25.1", + "nix 0.26.2", "once_cell", "ordered-stream", "rand 0.8.5", - "serde 1.0.149", + "serde 1.0.154", "serde_repr", - "sha1", + "sha1 0.10.5", "static_assertions", "tracing", "uds_windows", @@ -7080,24 +7242,25 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.6.2" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45066039ebf3330820e495e854f8b312abb68f0a39e97972d092bd72e8bb3e8e" +checksum = "9264b3a1bcf5503d4e0348b6e7efe1da58d4f92a913c15ed9e63b52de85faaa1" dependencies = [ - "proc-macro-crate 1.2.1", - "proc-macro2 1.0.47", - "quote 1.0.21", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.51", + "quote 1.0.23", "regex", - "syn 1.0.105", + "syn 1.0.109", + "zvariant_utils", ] [[package]] name = "zbus_names" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c737644108627748a660d038974160e0cbb62605536091bdfa28fd7f64d43c8" +checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3" dependencies = [ - "serde 1.0.149", + "serde 1.0.154", "static_assertions", "zvariant", ] @@ -7133,35 +7296,47 @@ dependencies = [ [[package]] name = "zune-inflate" -version = "0.2.42" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c473377c11c4a3ac6a2758f944cd336678e9c977aa0abf54f6450cf77e902d6d" +checksum = "a01728b79fb9b7e28a8c11f715e1cd8dc2cda7416a007d66cac55cebb3a8ac6b" dependencies = [ "simd-adler32", ] [[package]] name = "zvariant" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8c89c183461e11867ded456db252eae90874bc6769b7adbea464caa777e51" +checksum = "46fe4914a985446d6fd287019b5fceccce38303d71407d9e6e711d44954a05d8" dependencies = [ "byteorder", "enumflags2", "libc", - "serde 1.0.149", + "serde 1.0.154", "static_assertions", "zvariant_derive", ] [[package]] name = "zvariant_derive" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "155247a5d1ab55e335421c104ccd95d64f17cebbd02f50cdbc1c33385f9c4d81" +checksum = "34c20260af4b28b3275d6676c7e2a6be0d4332e8e0aba4616d34007fd84e462a" dependencies = [ - "proc-macro-crate 1.2.1", - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.105", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b22993dbc4d128a17a3b6c92f1c63872dd67198537ee728d8b5d7c40640a8b" +dependencies = [ + "proc-macro2 1.0.51", + "quote 1.0.23", + "syn 1.0.109", ] diff --git a/Cargo.toml b/Cargo.toml index 47c2bb0e7..7ad979f8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,22 +45,22 @@ lazy_static = "1.4" sha2 = "0.10" repng = "0.2" parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" } -runas = "0.2" +runas = "1.0" magnum-opus = { git = "https://github.com/rustdesk/magnum-opus" } dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true } rubato = { version = "0.12", optional = true } samplerate = { version = "0.2", optional = true } async-trait = "0.1" uuid = { version = "1.0", features = ["v4"] } -clap = "3.0" +clap = "4.1" rpassword = "7.0" -base64 = "0.13" +base64 = "0.21" num_cpus = "1.13" bytes = { version = "1.2", features = ["serde"] } default-net = "0.12.0" -wol-rs = "0.9.1" +wol-rs = "1.0" flutter_rust_bridge = { version = "1.61.1", optional = true } -errno = "0.2.8" +errno = "0.3" rdev = { git = "https://github.com/fufesou/rdev" } url = { version = "2.1", features = ["serde"] } dlopen = "0.1" @@ -71,7 +71,7 @@ chrono = "0.4.23" cidr-utils = "0.5.9" [target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] -cpal = "0.13.5" +cpal = "0.14" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] machine-uid = "0.2" @@ -81,9 +81,9 @@ sys-locale = "0.2" enigo = { path = "libs/enigo", features = [ "with_serde" ] } clipboard = { path = "libs/clipboard" } ctrlc = "3.2" -arboard = "2.0" +arboard = "3.2" #minreq = { version = "2.4", features = ["punycode", "https-native"] } -system_shutdown = "3.0.0" +system_shutdown = "4.0" [target.'cfg(target_os = "windows")'.dependencies] trayicon = { git = "https://github.com/open-trade/trayicon-rs", features = ["winit"] } @@ -148,6 +148,7 @@ cc = "1.0" hbb_common = { path = "libs/hbb_common" } simple_rc = { path = "libs/simple_rc", optional = true } flutter_rust_bridge_codegen = "1.61.1" +os-version = "0.2" [dev-dependencies] hound = "3.5" diff --git a/build.rs b/build.rs index d15f27424..bf141e539 100644 --- a/build.rs +++ b/build.rs @@ -9,7 +9,14 @@ fn build_windows() { #[cfg(target_os = "macos")] fn build_mac() { let file = "src/platform/macos.mm"; - cc::Build::new().file(file).compile("macos"); + let mut b = cc::Build::new(); + if let Ok(os_version::OsVersion::MacOS(v)) = os_version::detect() { + let v = v.version; + if v.contains("10.14") { + b.flag("-DNO_InputMonitoringAuthStatus=1"); + } + } + b.file(file).compile("macos"); println!("cargo:rerun-if-changed={}", file); } diff --git a/docs/README-GR.md b/docs/README-GR.md index b4a7d5c47..8ec98030d 100644 --- a/docs/README-GR.md +++ b/docs/README-GR.md @@ -37,9 +37,9 @@ | Σεούλ | AWS lightsail | 1 vCPU / 0.5GB RAM | | Γερμανία | Hetzner | 2 vCPU / 4GB RAM | | Γερμανία | Codext | 4 vCPU / 8GB RAM | -| Φινλανδία (Ελσίνκι) | 0x101 Cyber Security | 4 vCPU / 8GB RAM | -| ΗΠΑ (Άσμπερν) | 0x101 Cyber Security | 4 vCPU / 8GB RAM | -| Ουκρανία (Κίεβο) | dc.volia (2VM) | 2 vCPU / 4GB RAM | +| Φινλανδία (Ελσίνκι) | [Netlock](https://netlockendpoint.com) | 4 vCPU / 8GB RAM | +| ΗΠΑ (Άσμπερν) | [Netlock](https://netlockendpoint.com) | 4 vCPU / 8GB RAM | +| Ουκρανία (Κίεβο) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4GB RAM | ## Dev Container diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 666eab0ba..d9c052723 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -430,7 +430,7 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom( ); List<Locale> supportedLocales = const [ - // specify CN/TW to fix CJK issue in flutter + Locale('en', 'US'), Locale('zh', 'CN'), Locale('zh', 'TW'), Locale('zh', 'SG'), @@ -452,7 +452,7 @@ List<Locale> supportedLocales = const [ Locale('vi'), Locale('pl'), Locale('kz'), - Locale('en', 'US'), + Locale('es'), ]; String formatDurationToTime(Duration duration) { diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index 640f7d085..197e55376 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -68,7 +68,7 @@ class _PeersViewState extends State<_PeersView> with WindowListener { var _lastChangeTime = DateTime.now(); var _lastQueryPeers = <String>{}; var _lastQueryTime = DateTime.now().subtract(const Duration(hours: 1)); - var _queryCoun = 0; + var _queryCount = 0; var _exit = false; late final mobileWidth = () { @@ -101,12 +101,12 @@ class _PeersViewState extends State<_PeersView> with WindowListener { @override void onWindowFocus() { - _queryCoun = 0; + _queryCount = 0; } @override void onWindowMinimize() { - _queryCoun = _maxQueryCount; + _queryCount = _maxQueryCount; } @override @@ -123,6 +123,19 @@ class _PeersViewState extends State<_PeersView> with WindowListener { ); } + onVisibilityChanged(VisibilityInfo info) { + final peerId = _peerId((info.key as ValueKey).value); + if (info.visibleFraction > 0.00001) { + _curPeers.add(peerId); + } else { + _curPeers.remove(peerId); + } + _lastChangeTime = DateTime.now(); + } + + String _cardId(String id) => widget.peers.name + id; + String _peerId(String cardId) => cardId.replaceAll(widget.peers.name, ''); + Widget _buildPeersView(Peers peers) { final body = ObxValue<RxList>((filters) { return FutureBuilder<List<Peer>>( @@ -132,16 +145,8 @@ class _PeersViewState extends State<_PeersView> with WindowListener { final cards = <Widget>[]; for (final peer in peers) { final visibilityChild = VisibilityDetector( - key: ValueKey(peer.id), - onVisibilityChanged: (info) { - final peerId = (info.key as ValueKey).value; - if (info.visibleFraction > 0.00001) { - _curPeers.add(peerId); - } else { - _curPeers.remove(peerId); - } - _lastChangeTime = DateTime.now(); - }, + key: ValueKey(_cardId(peer.id)), + onVisibilityChanged: onVisibilityChanged, child: widget.peerCardBuilder(peer), ); cards.add(isDesktop @@ -172,6 +177,7 @@ class _PeersViewState extends State<_PeersView> with WindowListener { // ignore: todo // TODO: variables walk through async tasks? void _startCheckOnlines() { + final queryInterval = const Duration(seconds: 20); () async { while (!_exit) { final now = DateTime.now(); @@ -181,18 +187,18 @@ class _PeersViewState extends State<_PeersView> with WindowListener { platformFFI.ffiBind .queryOnlines(ids: _curPeers.toList(growable: false)); _lastQueryPeers = {..._curPeers}; - _lastQueryTime = DateTime.now(); - _queryCoun = 0; + _lastQueryTime = DateTime.now().subtract(queryInterval); + _queryCount = 0; } } } else { - if (_queryCoun < _maxQueryCount) { - if (now.difference(_lastQueryTime) > const Duration(seconds: 20)) { + if (_queryCount < _maxQueryCount) { + if (now.difference(_lastQueryTime) >= queryInterval) { if (_curPeers.isNotEmpty) { platformFFI.ffiBind .queryOnlines(ids: _curPeers.toList(growable: false)); _lastQueryTime = DateTime.now(); - _queryCoun += 1; + _queryCount += 1; } } } diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index 8bb57145f..44def46c2 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -15,7 +15,6 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/models/file_model.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; -import 'package:provider/provider.dart'; import 'package:wakelock/wakelock.dart'; import '../../consts.dart'; @@ -61,52 +60,15 @@ class FileManagerPage extends StatefulWidget { class _FileManagerPageState extends State<FileManagerPage> with AutomaticKeepAliveClientMixin { - final _localSelectedItems = SelectedItems(); - final _remoteSelectedItems = SelectedItems(); - - final _locationStatusLocal = LocationStatus.bread.obs; - final _locationStatusRemote = LocationStatus.bread.obs; - final _locationNodeLocal = FocusNode(debugLabel: "locationNodeLocal"); - final _locationNodeRemote = FocusNode(debugLabel: "locationNodeRemote"); - final _locationBarKeyLocal = GlobalKey(debugLabel: "locationBarKeyLocal"); - final _locationBarKeyRemote = GlobalKey(debugLabel: "locationBarKeyRemote"); - final _searchTextLocal = "".obs; - final _searchTextRemote = "".obs; - final _breadCrumbScrollerLocal = ScrollController(); - final _breadCrumbScrollerRemote = ScrollController(); final _mouseFocusScope = Rx<MouseFocusScope>(MouseFocusScope.none); - final _keyboardNodeLocal = FocusNode(debugLabel: "keyboardNodeLocal"); - final _keyboardNodeRemote = FocusNode(debugLabel: "keyboardNodeRemote"); - final _listSearchBufferLocal = TimeoutStringBuffer(); - final _listSearchBufferRemote = TimeoutStringBuffer(); - final _nameColWidthLocal = kDesktopFileTransferNameColWidth.obs; - final _modifiedColWidthLocal = kDesktopFileTransferModifiedColWidth.obs; - final _nameColWidthRemote = kDesktopFileTransferNameColWidth.obs; - final _modifiedColWidthRemote = kDesktopFileTransferModifiedColWidth.obs; - - /// [_lastClickTime], [_lastClickEntry] help to handle double click - int _lastClickTime = - DateTime.now().millisecondsSinceEpoch - bind.getDoubleClickTime() - 1000; - Entry? _lastClickEntry; final _dropMaskVisible = false.obs; // TODO impl drop mask final _overlayKeyState = OverlayKeyState(); - ScrollController getBreadCrumbScrollController(bool isLocal) { - return isLocal ? _breadCrumbScrollerLocal : _breadCrumbScrollerRemote; - } - - GlobalKey getLocationBarKey(bool isLocal) { - return isLocal ? _locationBarKeyLocal : _locationBarKeyRemote; - } - late FFI _ffi; FileModel get model => _ffi.fileModel; - - SelectedItems getSelectedItems(bool isLocal) { - return isLocal ? _localSelectedItems : _remoteSelectedItems; - } + JobController get jobController => model.jobController; @override void initState() { @@ -122,448 +84,61 @@ class _FileManagerPageState extends State<FileManagerPage> Wakelock.enable(); } debugPrint("File manager page init success with id ${widget.id}"); - model.onDirChanged = breadCrumbScrollToEnd; - // register location listener - _locationNodeLocal.addListener(onLocalLocationFocusChanged); - _locationNodeRemote.addListener(onRemoteLocationFocusChanged); _ffi.dialogManager.setOverlayState(_overlayKeyState); } @override void dispose() { - model.onClose().whenComplete(() { + model.close().whenComplete(() { _ffi.close(); _ffi.dialogManager.dismissAll(); if (!Platform.isLinux) { Wakelock.disable(); } Get.delete<FFI>(tag: 'ft_${widget.id}'); - _locationNodeLocal.removeListener(onLocalLocationFocusChanged); - _locationNodeRemote.removeListener(onRemoteLocationFocusChanged); - _locationNodeLocal.dispose(); - _locationNodeRemote.dispose(); }); super.dispose(); } + @override + bool get wantKeepAlive => true; + @override Widget build(BuildContext context) { super.build(context); return Overlay(key: _overlayKeyState.key, initialEntries: [ OverlayEntry(builder: (_) { - return ChangeNotifierProvider.value( - value: _ffi.fileModel, - child: Consumer<FileModel>(builder: (context, model, child) { - return Scaffold( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - body: Row( - children: [ - Flexible(flex: 3, child: body(isLocal: true)), - Flexible(flex: 3, child: body(isLocal: false)), - Flexible(flex: 2, child: statusList()) - ], - ), - ); - })); + return Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + body: Row( + children: [ + Flexible( + flex: 3, + child: dropArea(FileManagerView( + model.localController, _ffi, _mouseFocusScope))), + Flexible( + flex: 3, + child: dropArea(FileManagerView( + model.remoteController, _ffi, _mouseFocusScope))), + Flexible(flex: 2, child: statusList()) + ], + ), + ); }) ]); } - Widget menu({bool isLocal = false}) { - var menuPos = RelativeRect.fill; - - final List<MenuEntryBase<String>> items = [ - MenuEntrySwitch<String>( - switchType: SwitchType.scheckbox, - text: translate("Show Hidden Files"), - getter: () async { - return model.getCurrentShowHidden(isLocal); - }, - setter: (bool v) async { - model.toggleShowHidden(local: isLocal); - }, - padding: kDesktopMenuPadding, - dismissOnClicked: true, - ), - MenuEntryButton( - childBuilder: (style) => Text(translate("Select All"), style: style), - proc: () => setState(() => getSelectedItems(isLocal) - .selectAll(model.getCurrentDir(isLocal).entries)), - padding: kDesktopMenuPadding, - dismissOnClicked: true), - MenuEntryButton( - childBuilder: (style) => - Text(translate("Unselect All"), style: style), - proc: () => setState(() => getSelectedItems(isLocal).clear()), - padding: kDesktopMenuPadding, - dismissOnClicked: true) - ]; - - return Listener( - onPointerDown: (e) { - final x = e.position.dx; - final y = e.position.dy; - menuPos = RelativeRect.fromLTRB(x, y, x, y); - }, - child: MenuButton( - onPressed: () => mod_menu.showMenu( - context: context, - position: menuPos, - items: items - .map( - (e) => e.build( - context, - MenuConfig( - commonColor: CustomPopupMenuTheme.commonColor, - height: CustomPopupMenuTheme.height, - dividerHeight: CustomPopupMenuTheme.dividerHeight), - ), - ) - .expand((i) => i) - .toList(), - elevation: 8, - ), - child: SvgPicture.asset( - "assets/dots.svg", - color: Theme.of(context).tabBarTheme.labelColor, - ), - color: Theme.of(context).cardColor, - hoverColor: Theme.of(context).hoverColor, - ), - ); - } - - Widget body({bool isLocal = false}) { - final scrollController = ScrollController(); - return Container( - margin: const EdgeInsets.all(16.0), - padding: const EdgeInsets.all(8.0), - child: DropTarget( - onDragDone: (detail) => handleDragDone(detail, isLocal), + Widget dropArea(FileManagerView fileView) { + return DropTarget( + onDragDone: (detail) => + handleDragDone(detail, fileView.controller.isLocal), onDragEntered: (enter) { _dropMaskVisible.value = true; }, onDragExited: (exit) { _dropMaskVisible.value = false; }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - headTools(isLocal), - Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: _buildFileList(context, isLocal, scrollController), - ) - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildFileList( - BuildContext context, bool isLocal, ScrollController scrollController) { - final fd = model.getCurrentDir(isLocal); - final entries = fd.entries; - final selectedEntries = getSelectedItems(isLocal); - - return MouseRegion( - onEnter: (evt) { - _mouseFocusScope.value = - isLocal ? MouseFocusScope.local : MouseFocusScope.remote; - if (isLocal) { - _keyboardNodeLocal.requestFocus(); - } else { - _keyboardNodeRemote.requestFocus(); - } - }, - onExit: (evt) { - _mouseFocusScope.value = MouseFocusScope.none; - }, - child: ListSearchActionListener( - node: isLocal ? _keyboardNodeLocal : _keyboardNodeRemote, - buffer: isLocal ? _listSearchBufferLocal : _listSearchBufferRemote, - onNext: (buffer) { - debugPrint("searching next for $buffer"); - assert(buffer.length == 1); - assert(selectedEntries.length <= 1); - var skipCount = 0; - if (selectedEntries.items.isNotEmpty) { - final index = entries.indexOf(selectedEntries.items.first); - if (index < 0) { - return; - } - skipCount = index + 1; - } - var searchResult = entries.skip(skipCount).where( - (element) => element.name.toLowerCase().startsWith(buffer)); - if (searchResult.isEmpty) { - // cannot find next, lets restart search from head - debugPrint("restart search from head"); - searchResult = entries.where( - (element) => element.name.toLowerCase().startsWith(buffer)); - } - if (searchResult.isEmpty) { - setState(() { - getSelectedItems(isLocal).clear(); - }); - return; - } - _jumpToEntry(isLocal, searchResult.first, scrollController, - kDesktopFileTransferRowHeight); - }, - onSearch: (buffer) { - debugPrint("searching for $buffer"); - final selectedEntries = getSelectedItems(isLocal); - final searchResult = entries.where( - (element) => element.name.toLowerCase().startsWith(buffer)); - selectedEntries.clear(); - if (searchResult.isEmpty) { - setState(() { - getSelectedItems(isLocal).clear(); - }); - return; - } - _jumpToEntry(isLocal, searchResult.first, scrollController, - kDesktopFileTransferRowHeight); - }, - child: ObxValue<RxString>( - (searchText) { - final filteredEntries = searchText.isNotEmpty - ? entries.where((element) { - return element.name.contains(searchText.value); - }).toList(growable: false) - : entries; - final rows = filteredEntries.map((entry) { - final sizeStr = - entry.isFile ? readableFileSize(entry.size.toDouble()) : ""; - final lastModifiedStr = entry.isDrive - ? " " - : "${entry.lastModified().toString().replaceAll(".000", "")} "; - final isSelected = selectedEntries.contains(entry); - return Padding( - padding: EdgeInsets.symmetric(vertical: 1), - child: Container( - decoration: BoxDecoration( - color: isSelected - ? Theme.of(context).hoverColor - : Theme.of(context).cardColor, - borderRadius: BorderRadius.all( - Radius.circular(5.0), - ), - ), - key: ValueKey(entry.name), - height: kDesktopFileTransferRowHeight, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Expanded( - child: InkWell( - child: Row( - children: [ - GestureDetector( - child: Obx( - () => Container( - width: isLocal - ? _nameColWidthLocal.value - : _nameColWidthRemote.value, - child: Tooltip( - waitDuration: - Duration(milliseconds: 500), - message: entry.name, - child: Row(children: [ - entry.isDrive - ? Image( - image: iconHardDrive, - fit: BoxFit.scaleDown, - color: Theme.of(context) - .iconTheme - .color - ?.withOpacity(0.7)) - .paddingAll(4) - : SvgPicture.asset( - entry.isFile - ? "assets/file.svg" - : "assets/folder.svg", - color: Theme.of(context) - .tabBarTheme - .labelColor, - ), - Expanded( - child: Text( - entry.name.nonBreaking, - overflow: - TextOverflow.ellipsis)) - ]), - )), - ), - onTap: () { - final items = getSelectedItems(isLocal); - // handle double click - if (_checkDoubleClick(entry)) { - openDirectory(entry.path, - isLocal: isLocal); - items.clear(); - return; - } - _onSelectedChanged( - items, filteredEntries, entry, isLocal); - }, - ), - SizedBox( - width: 2.0, - ), - GestureDetector( - child: Obx( - () => SizedBox( - width: isLocal - ? _modifiedColWidthLocal.value - : _modifiedColWidthRemote.value, - child: Tooltip( - waitDuration: - Duration(milliseconds: 500), - message: lastModifiedStr, - child: Text( - lastModifiedStr, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 12, - color: MyTheme.darkGray, - ), - )), - ), - ), - ), - // Divider from header. - SizedBox( - width: 2.0, - ), - Expanded( - // width: 100, - child: GestureDetector( - child: Tooltip( - waitDuration: Duration(milliseconds: 500), - message: sizeStr, - child: Text( - sizeStr, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 10, - color: MyTheme.darkGray), - ), - ), - ), - ), - ], - ), - ), - ), - ], - )), - ); - }).toList(growable: false); - - return Column( - children: [ - // Header - Row( - children: [ - Expanded(child: _buildFileBrowserHeader(context, isLocal)), - ], - ), - // Body - Expanded( - child: ListView.builder( - controller: scrollController, - itemExtent: kDesktopFileTransferRowHeight, - itemBuilder: (context, index) { - return rows[index]; - }, - itemCount: rows.length, - ), - ), - ], - ); - }, - isLocal ? _searchTextLocal : _searchTextRemote, - ), - ), - ); - } - - void _jumpToEntry(bool isLocal, Entry entry, - ScrollController scrollController, double rowHeight) { - final entries = model.getCurrentDir(isLocal).entries; - final index = entries.indexOf(entry); - if (index == -1) { - debugPrint("entry is not valid: ${entry.path}"); - } - final selectedEntries = getSelectedItems(isLocal); - final searchResult = entries.where((element) => element == entry); - selectedEntries.clear(); - if (searchResult.isEmpty) { - return; - } - final offset = min( - max(scrollController.position.minScrollExtent, - entries.indexOf(searchResult.first) * rowHeight), - scrollController.position.maxScrollExtent); - scrollController.jumpTo(offset); - setState(() { - selectedEntries.add(isLocal, searchResult.first); - debugPrint("focused on ${searchResult.first.name}"); - }); - } - - void _onSelectedChanged(SelectedItems selectedItems, List<Entry> entries, - Entry entry, bool isLocal) { - final isCtrlDown = RawKeyboard.instance.keysPressed - .contains(LogicalKeyboardKey.controlLeft); - final isShiftDown = - RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.shiftLeft); - if (isCtrlDown) { - if (selectedItems.contains(entry)) { - selectedItems.remove(entry); - } else { - selectedItems.add(isLocal, entry); - } - } else if (isShiftDown) { - final List<int> indexGroup = []; - for (var selected in selectedItems.items) { - indexGroup.add(entries.indexOf(selected)); - } - indexGroup.add(entries.indexOf(entry)); - indexGroup.removeWhere((e) => e == -1); - final maxIndex = indexGroup.reduce(max); - final minIndex = indexGroup.reduce(min); - selectedItems.clear(); - entries - .getRange(minIndex, maxIndex + 1) - .forEach((e) => selectedItems.add(isLocal, e)); - } else { - selectedItems.clear(); - selectedItems.add(isLocal, entry); - } - setState(() {}); - } - - bool _checkDoubleClick(Entry entry) { - final current = DateTime.now().millisecondsSinceEpoch; - final elapsed = current - _lastClickTime; - _lastClickTime = current; - if (_lastClickEntry == entry) { - if (elapsed < bind.getDoubleClickTime()) { - return true; - } - } else { - _lastClickEntry = entry; - } - return false; + child: fileView); } Widget generateCard(Widget child) { @@ -581,179 +156,281 @@ class _FileManagerPageState extends State<FileManagerPage> /// transfer status list /// watch transfer status Widget statusList() { + statusListView(List<JobProgress> jobs) => ListView.builder( + controller: ScrollController(), + itemBuilder: (BuildContext context, int index) { + final item = jobs[index]; + return Padding( + padding: const EdgeInsets.only(bottom: 5), + child: generateCard( + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Transform.rotate( + angle: item.isRemoteToLocal ? pi : 0, + child: SvgPicture.asset( + "assets/arrow.svg", + color: Theme.of(context).tabBarTheme.labelColor, + ), + ).paddingOnly(left: 15), + const SizedBox( + width: 16.0, + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Tooltip( + waitDuration: Duration(milliseconds: 500), + message: item.jobName, + child: Text( + item.fileName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ).paddingSymmetric(vertical: 10), + ), + Text( + '${translate("Total")} ${readableFileSize(item.totalSize.toDouble())}', + style: TextStyle( + fontSize: 12, + color: MyTheme.darkGray, + ), + ), + Offstage( + offstage: item.state != JobState.inProgress, + child: Text( + '${translate("Speed")} ${readableFileSize(item.speed)}/s', + style: TextStyle( + fontSize: 12, + color: MyTheme.darkGray, + ), + ), + ), + Offstage( + offstage: item.state == JobState.inProgress, + child: Text( + translate( + item.display(), + ), + style: TextStyle( + fontSize: 12, + color: MyTheme.darkGray, + ), + ), + ), + Offstage( + offstage: item.state != JobState.inProgress, + child: LinearPercentIndicator( + padding: EdgeInsets.only(right: 15), + animateFromLastPercent: true, + center: Text( + '${(item.finishedSize / item.totalSize * 100).toStringAsFixed(0)}%', + ), + barRadius: Radius.circular(15), + percent: item.finishedSize / item.totalSize, + progressColor: MyTheme.accent, + backgroundColor: Theme.of(context).hoverColor, + lineHeight: kDesktopFileTransferRowHeight, + ).paddingSymmetric(vertical: 15), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Offstage( + offstage: item.state != JobState.paused, + child: MenuButton( + onPressed: () { + jobController.resumeJob(item.id); + }, + child: SvgPicture.asset( + "assets/refresh.svg", + color: Colors.white, + ), + color: MyTheme.accent, + hoverColor: MyTheme.accent80, + ), + ), + MenuButton( + padding: EdgeInsets.only(right: 15), + child: SvgPicture.asset( + "assets/close.svg", + color: Colors.white, + ), + onPressed: () { + jobController.jobTable.removeAt(index); + jobController.cancelJob(item.id); + }, + color: MyTheme.accent, + hoverColor: MyTheme.accent80, + ), + ], + ), + ], + ), + ], + ).paddingSymmetric(vertical: 10), + ), + ); + }, + itemCount: jobController.jobTable.length, + ); + return PreferredSize( preferredSize: const Size(200, double.infinity), child: Container( - margin: const EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0), - padding: const EdgeInsets.all(8.0), - child: model.jobTable.isEmpty - ? generateCard( - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - "assets/transfer.svg", - color: Theme.of(context).tabBarTheme.labelColor, - height: 40, - ).paddingOnly(bottom: 10), - Text( - translate("No transfers in progress"), - textAlign: TextAlign.center, - textScaleFactor: 1.20, - style: TextStyle( - color: Theme.of(context).tabBarTheme.labelColor), + margin: const EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0), + padding: const EdgeInsets.all(8.0), + child: Obx( + () => jobController.jobTable.isEmpty + ? generateCard( + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + "assets/transfer.svg", + color: Theme.of(context).tabBarTheme.labelColor, + height: 40, + ).paddingOnly(bottom: 10), + Text( + translate("No transfers in progress"), + textAlign: TextAlign.center, + textScaleFactor: 1.20, + style: TextStyle( + color: + Theme.of(context).tabBarTheme.labelColor), + ), + ], ), - ], - ), - ), - ) - : Obx( - () => ListView.builder( - controller: ScrollController(), - itemBuilder: (BuildContext context, int index) { - final item = model.jobTable[index]; - return Padding( - padding: const EdgeInsets.only(bottom: 5), - child: generateCard( - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Transform.rotate( - angle: item.isRemote ? pi : 0, - child: SvgPicture.asset( - "assets/arrow.svg", - color: Theme.of(context) - .tabBarTheme - .labelColor, - ), - ).paddingOnly(left: 15), - const SizedBox( - width: 16.0, - ), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Tooltip( - waitDuration: - Duration(milliseconds: 500), - message: item.jobName, - child: Text( - item.fileName, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ).paddingSymmetric(vertical: 10), - ), - Text( - '${translate("Total")} ${readableFileSize(item.totalSize.toDouble())}', - style: TextStyle( - fontSize: 12, - color: MyTheme.darkGray, - ), - ), - Offstage( - offstage: - item.state != JobState.inProgress, - child: Text( - '${translate("Speed")} ${readableFileSize(item.speed)}/s', - style: TextStyle( - fontSize: 12, - color: MyTheme.darkGray, - ), - ), - ), - Offstage( - offstage: - item.state == JobState.inProgress, - child: Text( - translate( - item.display(), - ), - style: TextStyle( - fontSize: 12, - color: MyTheme.darkGray, - ), - ), - ), - Offstage( - offstage: - item.state != JobState.inProgress, - child: LinearPercentIndicator( - padding: EdgeInsets.only(right: 15), - animateFromLastPercent: true, - center: Text( - '${(item.finishedSize / item.totalSize * 100).toStringAsFixed(0)}%', - ), - barRadius: Radius.circular(15), - percent: item.finishedSize / - item.totalSize, - progressColor: MyTheme.accent, - backgroundColor: - Theme.of(context).hoverColor, - lineHeight: - kDesktopFileTransferRowHeight, - ).paddingSymmetric(vertical: 15), - ), - ], - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Offstage( - offstage: item.state != JobState.paused, - child: MenuButton( - onPressed: () { - model.resumeJob(item.id); - }, - child: SvgPicture.asset( - "assets/refresh.svg", - color: Colors.white, - ), - color: MyTheme.accent, - hoverColor: MyTheme.accent80, - ), - ), - MenuButton( - padding: EdgeInsets.only(right: 15), - child: SvgPicture.asset( - "assets/close.svg", - color: Colors.white, - ), - onPressed: () { - model.jobTable.removeAt(index); - model.cancelJob(item.id); - }, - color: MyTheme.accent, - hoverColor: MyTheme.accent80, - ), - ], - ), - ], - ), - ], - ).paddingSymmetric(vertical: 10), - ), - ); + ), + ) + : statusListView(jobController.jobTable), + )), + ); + } + + void handleDragDone(DropDoneDetails details, bool isLocal) { + if (isLocal) { + // ignore local + return; + } + final items = SelectedItems(isLocal: false); + for (var file in details.files) { + final f = File(file.path); + items.add(Entry() + ..path = file.path + ..name = file.name + ..size = FileSystemEntity.isDirectorySync(f.path) ? 0 : f.lengthSync()); + } + final otherSideData = model.localController.directoryData(); + model.remoteController.sendFiles(items, otherSideData); + } +} + +class FileManagerView extends StatefulWidget { + final FileController controller; + final FFI _ffi; + final Rx<MouseFocusScope> _mouseFocusScope; + + FileManagerView(this.controller, this._ffi, this._mouseFocusScope); + + @override + State<StatefulWidget> createState() => _FileManagerViewState(); +} + +class _FileManagerViewState extends State<FileManagerView> { + final _locationStatus = LocationStatus.bread.obs; + final _locationNode = FocusNode(); + final _locationBarKey = GlobalKey(); + final _searchText = "".obs; + final _breadCrumbScroller = ScrollController(); + final _keyboardNode = FocusNode(); + final _listSearchBuffer = TimeoutStringBuffer(); + final _nameColWidth = kDesktopFileTransferNameColWidth.obs; + final _modifiedColWidth = kDesktopFileTransferModifiedColWidth.obs; + final _fileListScrollController = ScrollController(); + + /// [_lastClickTime], [_lastClickEntry] help to handle double click + var _lastClickTime = + DateTime.now().millisecondsSinceEpoch - bind.getDoubleClickTime() - 1000; + Entry? _lastClickEntry; + + FileController get controller => widget.controller; + bool get isLocal => widget.controller.isLocal; + FFI get _ffi => widget._ffi; + SelectedItems get selectedItems => controller.selectedItems; + + @override + void initState() { + super.initState(); + // register location listener + _locationNode.addListener(onLocationFocusChanged); + controller.directory.listen((e) => breadCrumbScrollToEnd()); + } + + @override + void dispose() { + _locationNode.removeListener(onLocationFocusChanged); + _locationNode.dispose(); + _keyboardNode.dispose(); + _breadCrumbScroller.dispose(); + _fileListScrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + headTools(), + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: MouseRegion( + onEnter: (evt) { + widget._mouseFocusScope.value = isLocal + ? MouseFocusScope.local + : MouseFocusScope.remote; + _keyboardNode.requestFocus(); }, - itemCount: model.jobTable.length, - ), - ), + onExit: (evt) => + widget._mouseFocusScope.value = MouseFocusScope.none, + child: _buildFileList(context, _fileListScrollController), + )) + ], + ), + ), + ], ), ); } - Widget headTools(bool isLocal) { - final locationStatus = - isLocal ? _locationStatusLocal : _locationStatusRemote; - final locationFocus = isLocal ? _locationNodeLocal : _locationNodeRemote; - final selectedItems = getSelectedItems(isLocal); + void onLocationFocusChanged() { + debugPrint("focus changed on local"); + if (_locationNode.hasFocus) { + // ignore + } else { + // lost focus, change to bread + if (_locationStatus.value != LocationStatus.fileSearchBar) { + _locationStatus.value = LocationStatus.bread; + } + } + } + + Widget headTools() { return Container( child: Column( children: [ @@ -813,7 +490,7 @@ class _FileManagerPageState extends State<FileManagerPage> hoverColor: Theme.of(context).hoverColor, onPressed: () { selectedItems.clear(); - model.goBack(isLocal: isLocal); + controller.goBack(); }, ), MenuButton( @@ -828,7 +505,7 @@ class _FileManagerPageState extends State<FileManagerPage> hoverColor: Theme.of(context).hoverColor, onPressed: () { selectedItems.clear(); - model.goToParentDirectory(isLocal: isLocal); + controller.goToParentDirectory(); }, ), ], @@ -847,14 +524,14 @@ class _FileManagerPageState extends State<FileManagerPage> padding: EdgeInsets.symmetric(vertical: 2.5), child: GestureDetector( onTap: () { - locationStatus.value = - locationStatus.value == LocationStatus.bread + _locationStatus.value = + _locationStatus.value == LocationStatus.bread ? LocationStatus.pathLocation : LocationStatus.bread; Future.delayed(Duration.zero, () { - if (locationStatus.value == + if (_locationStatus.value == LocationStatus.pathLocation) { - locationFocus.requestFocus(); + _locationNode.requestFocus(); } }); }, @@ -863,10 +540,10 @@ class _FileManagerPageState extends State<FileManagerPage> child: Row( children: [ Expanded( - child: locationStatus.value == + child: _locationStatus.value == LocationStatus.bread - ? buildBread(isLocal) - : buildPathLocation(isLocal)), + ? buildBread() + : buildPathLocation()), ], ), ), @@ -877,15 +554,13 @@ class _FileManagerPageState extends State<FileManagerPage> ), ), Obx(() { - switch (locationStatus.value) { + switch (_locationStatus.value) { case LocationStatus.bread: return MenuButton( onPressed: () { - locationStatus.value = LocationStatus.fileSearchBar; - final focusNode = - isLocal ? _locationNodeLocal : _locationNodeRemote; + _locationStatus.value = LocationStatus.fileSearchBar; Future.delayed( - Duration.zero, () => focusNode.requestFocus()); + Duration.zero, () => _locationNode.requestFocus()); }, child: SvgPicture.asset( "assets/search.svg", @@ -908,7 +583,7 @@ class _FileManagerPageState extends State<FileManagerPage> return MenuButton( onPressed: () { onSearchText("", isLocal); - locationStatus.value = LocationStatus.bread; + _locationStatus.value = LocationStatus.bread; }, child: SvgPicture.asset( "assets/close.svg", @@ -924,7 +599,7 @@ class _FileManagerPageState extends State<FileManagerPage> left: 3, ), onPressed: () { - model.refresh(isLocal: isLocal); + controller.refresh(); }, child: SvgPicture.asset( "assets/refresh.svg", @@ -948,7 +623,7 @@ class _FileManagerPageState extends State<FileManagerPage> right: 3, ), onPressed: () { - model.goHome(isLocal: isLocal); + controller.goToHomeDirectory(); }, child: SvgPicture.asset( "assets/home.svg", @@ -963,12 +638,11 @@ class _FileManagerPageState extends State<FileManagerPage> _ffi.dialogManager.show((setState, close) { submit() { if (name.value.text.isNotEmpty) { - model.createDir( - PathUtil.join( - model.getCurrentDir(isLocal).path, - name.value.text, - model.getCurrentIsWindows(isLocal)), - isLocal: isLocal); + controller.createDir(PathUtil.join( + controller.directory.value.path, + name.value.text, + controller.options.value.isWindows, + )); close(); } } @@ -1026,86 +700,93 @@ class _FileManagerPageState extends State<FileManagerPage> color: Theme.of(context).cardColor, hoverColor: Theme.of(context).hoverColor, ), - MenuButton( - onPressed: validItems(selectedItems) - ? () async { - await (model.removeAction(selectedItems, - isLocal: isLocal)); - selectedItems.clear(); - } - : null, - child: SvgPicture.asset( - "assets/trash.svg", - color: Theme.of(context).tabBarTheme.labelColor, - ), - color: Theme.of(context).cardColor, - hoverColor: Theme.of(context).hoverColor, - ), + Obx(() => MenuButton( + onPressed: SelectedItems.valid(selectedItems.items) + ? () async { + await (controller + .removeAction(selectedItems)); + selectedItems.clear(); + } + : null, + child: SvgPicture.asset( + "assets/trash.svg", + color: Theme.of(context).tabBarTheme.labelColor, + ), + color: Theme.of(context).cardColor, + hoverColor: Theme.of(context).hoverColor, + )), menu(isLocal: isLocal), ], ), ), - ElevatedButton.icon( - style: ButtonStyle( - padding: MaterialStateProperty.all<EdgeInsetsGeometry>(isLocal - ? EdgeInsets.only(left: 10) - : EdgeInsets.only(right: 10)), - backgroundColor: MaterialStateProperty.all( - selectedItems.length == 0 - ? MyTheme.accent80 - : MyTheme.accent, - ), - ), - onPressed: validItems(selectedItems) - ? () { - model.sendFiles(selectedItems, isRemote: !isLocal); - selectedItems.clear(); - } - : null, - icon: isLocal - ? Text( - translate('Send'), - textAlign: TextAlign.right, - style: TextStyle( - color: selectedItems.length == 0 - ? Theme.of(context).brightness == Brightness.light - ? MyTheme.grayBg - : MyTheme.darkGray - : Colors.white, - ), - ) - : RotatedBox( - quarterTurns: 2, - child: SvgPicture.asset( - "assets/arrow.svg", - color: selectedItems.length == 0 - ? Theme.of(context).brightness == Brightness.light - ? MyTheme.grayBg - : MyTheme.darkGray - : Colors.white, - alignment: Alignment.bottomRight, - ), + Obx(() => ElevatedButton.icon( + style: ButtonStyle( + padding: MaterialStateProperty.all<EdgeInsetsGeometry>( + isLocal + ? EdgeInsets.only(left: 10) + : EdgeInsets.only(right: 10)), + backgroundColor: MaterialStateProperty.all( + selectedItems.items.isEmpty + ? MyTheme.accent80 + : MyTheme.accent, ), - label: isLocal - ? SvgPicture.asset( - "assets/arrow.svg", - color: selectedItems.length == 0 - ? Theme.of(context).brightness == Brightness.light - ? MyTheme.grayBg - : MyTheme.darkGray - : Colors.white, - ) - : Text( - translate('Receive'), - style: TextStyle( - color: selectedItems.length == 0 - ? Theme.of(context).brightness == Brightness.light - ? MyTheme.grayBg - : MyTheme.darkGray - : Colors.white, - ), - ), - ), + ), + onPressed: SelectedItems.valid(selectedItems.items) + ? () { + final otherSideData = + controller.getOtherSideDirectoryData(); + controller.sendFiles(selectedItems, otherSideData); + selectedItems.clear(); + } + : null, + icon: isLocal + ? Text( + translate('Send'), + textAlign: TextAlign.right, + style: TextStyle( + color: selectedItems.items.isEmpty + ? Theme.of(context).brightness == + Brightness.light + ? MyTheme.grayBg + : MyTheme.darkGray + : Colors.white, + ), + ) + : RotatedBox( + quarterTurns: 2, + child: SvgPicture.asset( + "assets/arrow.svg", + color: selectedItems.items.isEmpty + ? Theme.of(context).brightness == + Brightness.light + ? MyTheme.grayBg + : MyTheme.darkGray + : Colors.white, + alignment: Alignment.bottomRight, + ), + ), + label: isLocal + ? SvgPicture.asset( + "assets/arrow.svg", + color: selectedItems.items.isEmpty + ? Theme.of(context).brightness == + Brightness.light + ? MyTheme.grayBg + : MyTheme.darkGray + : Colors.white, + ) + : Text( + translate('Receive'), + style: TextStyle( + color: selectedItems.items.isEmpty + ? Theme.of(context).brightness == + Brightness.light + ? MyTheme.grayBg + : MyTheme.darkGray + : Colors.white, + ), + ), + )), ], ).marginOnly(top: 8.0) ], @@ -1113,55 +794,443 @@ class _FileManagerPageState extends State<FileManagerPage> ); } - bool validItems(SelectedItems items) { - if (items.length > 0) { - // exclude DirDrive type - return items.items.any((item) => !item.isDrive); + Widget menu({bool isLocal = false}) { + var menuPos = RelativeRect.fill; + + final List<MenuEntryBase<String>> items = [ + MenuEntrySwitch<String>( + switchType: SwitchType.scheckbox, + text: translate("Show Hidden Files"), + getter: () async { + return controller.options.value.isWindows; + }, + setter: (bool v) async { + controller.toggleShowHidden(); + }, + padding: kDesktopMenuPadding, + dismissOnClicked: true, + ), + MenuEntryButton( + childBuilder: (style) => Text(translate("Select All"), style: style), + proc: () => setState(() => + selectedItems.selectAll(controller.directory.value.entries)), + padding: kDesktopMenuPadding, + dismissOnClicked: true), + MenuEntryButton( + childBuilder: (style) => + Text(translate("Unselect All"), style: style), + proc: () => selectedItems.clear(), + padding: kDesktopMenuPadding, + dismissOnClicked: true) + ]; + + return Listener( + onPointerDown: (e) { + final x = e.position.dx; + final y = e.position.dy; + menuPos = RelativeRect.fromLTRB(x, y, x, y); + }, + child: MenuButton( + onPressed: () => mod_menu.showMenu( + context: context, + position: menuPos, + items: items + .map( + (e) => e.build( + context, + MenuConfig( + commonColor: CustomPopupMenuTheme.commonColor, + height: CustomPopupMenuTheme.height, + dividerHeight: CustomPopupMenuTheme.dividerHeight), + ), + ) + .expand((i) => i) + .toList(), + elevation: 8, + ), + child: SvgPicture.asset( + "assets/dots.svg", + color: Theme.of(context).tabBarTheme.labelColor, + ), + color: Theme.of(context).cardColor, + hoverColor: Theme.of(context).hoverColor, + ), + ); + } + + Widget _buildFileList( + BuildContext context, ScrollController scrollController) { + final fd = controller.directory.value; + final entries = fd.entries; + + return ListSearchActionListener( + node: _keyboardNode, + buffer: _listSearchBuffer, + onNext: (buffer) { + debugPrint("searching next for $buffer"); + assert(buffer.length == 1); + assert(selectedItems.items.length <= 1); + var skipCount = 0; + if (selectedItems.items.isNotEmpty) { + final index = entries.indexOf(selectedItems.items.first); + if (index < 0) { + return; + } + skipCount = index + 1; + } + var searchResult = entries + .skip(skipCount) + .where((element) => element.name.toLowerCase().startsWith(buffer)); + if (searchResult.isEmpty) { + // cannot find next, lets restart search from head + debugPrint("restart search from head"); + searchResult = entries.where( + (element) => element.name.toLowerCase().startsWith(buffer)); + } + if (searchResult.isEmpty) { + selectedItems.clear(); + return; + } + _jumpToEntry(isLocal, searchResult.first, scrollController, + kDesktopFileTransferRowHeight); + }, + onSearch: (buffer) { + debugPrint("searching for $buffer"); + final selectedEntries = selectedItems; + final searchResult = entries + .where((element) => element.name.toLowerCase().startsWith(buffer)); + selectedEntries.clear(); + if (searchResult.isEmpty) { + selectedItems.clear(); + return; + } + _jumpToEntry(isLocal, searchResult.first, scrollController, + kDesktopFileTransferRowHeight); + }, + child: Obx(() { + final entries = controller.directory.value.entries; + final filteredEntries = _searchText.isNotEmpty + ? entries.where((element) { + return element.name.contains(_searchText.value); + }).toList(growable: false) + : entries; + final rows = filteredEntries.map((entry) { + final sizeStr = + entry.isFile ? readableFileSize(entry.size.toDouble()) : ""; + final lastModifiedStr = entry.isDrive + ? " " + : "${entry.lastModified().toString().replaceAll(".000", "")} "; + return Padding( + padding: EdgeInsets.symmetric(vertical: 1), + child: Obx(() => Container( + decoration: BoxDecoration( + color: selectedItems.items.contains(entry) + ? Theme.of(context).hoverColor + : Theme.of(context).cardColor, + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + key: ValueKey(entry.name), + height: kDesktopFileTransferRowHeight, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: InkWell( + child: Row( + children: [ + GestureDetector( + child: Obx( + () => Container( + width: _nameColWidth.value, + child: Tooltip( + waitDuration: Duration(milliseconds: 500), + message: entry.name, + child: Row(children: [ + entry.isDrive + ? Image( + image: iconHardDrive, + fit: BoxFit.scaleDown, + color: Theme.of(context) + .iconTheme + .color + ?.withOpacity(0.7)) + .paddingAll(4) + : SvgPicture.asset( + entry.isFile + ? "assets/file.svg" + : "assets/folder.svg", + color: Theme.of(context) + .tabBarTheme + .labelColor, + ), + Expanded( + child: Text(entry.name.nonBreaking, + overflow: + TextOverflow.ellipsis)) + ]), + )), + ), + onTap: () { + final items = selectedItems; + // handle double click + if (_checkDoubleClick(entry)) { + controller.openDirectory(entry.path); + items.clear(); + return; + } + _onSelectedChanged( + items, filteredEntries, entry, isLocal); + }, + ), + SizedBox( + width: 2.0, + ), + GestureDetector( + child: Obx( + () => SizedBox( + width: _modifiedColWidth.value, + child: Tooltip( + waitDuration: Duration(milliseconds: 500), + message: lastModifiedStr, + child: Text( + lastModifiedStr, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12, + color: MyTheme.darkGray, + ), + )), + ), + ), + ), + // Divider from header. + SizedBox( + width: 2.0, + ), + Expanded( + // width: 100, + child: GestureDetector( + child: Tooltip( + waitDuration: Duration(milliseconds: 500), + message: sizeStr, + child: Text( + sizeStr, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 10, color: MyTheme.darkGray), + ), + ), + ), + ), + ], + ), + ), + ), + ], + ))), + ); + }).toList(growable: false); + + return Column( + children: [ + // Header + Row( + children: [ + Expanded(child: _buildFileBrowserHeader(context)), + ], + ), + // Body + Expanded( + child: ListView.builder( + controller: scrollController, + itemExtent: kDesktopFileTransferRowHeight, + itemBuilder: (context, index) { + return rows[index]; + }, + itemCount: rows.length, + ), + ), + ], + ); + }), + ); + } + + onSearchText(String searchText, bool isLocal) { + selectedItems.clear(); + _searchText.value = searchText; + } + + void _jumpToEntry(bool isLocal, Entry entry, + ScrollController scrollController, double rowHeight) { + final entries = controller.directory.value.entries; + final index = entries.indexOf(entry); + if (index == -1) { + debugPrint("entry is not valid: ${entry.path}"); + } + final selectedEntries = selectedItems; + final searchResult = entries.where((element) => element == entry); + selectedEntries.clear(); + if (searchResult.isEmpty) { + return; + } + final offset = min( + max(scrollController.position.minScrollExtent, + entries.indexOf(searchResult.first) * rowHeight), + scrollController.position.maxScrollExtent); + scrollController.jumpTo(offset); + selectedEntries.add(searchResult.first); + debugPrint("focused on ${searchResult.first.name}"); + } + + void _onSelectedChanged(SelectedItems selectedItems, List<Entry> entries, + Entry entry, bool isLocal) { + final isCtrlDown = RawKeyboard.instance.keysPressed + .contains(LogicalKeyboardKey.controlLeft); + final isShiftDown = + RawKeyboard.instance.keysPressed.contains(LogicalKeyboardKey.shiftLeft); + if (isCtrlDown) { + if (selectedItems.items.contains(entry)) { + selectedItems.remove(entry); + } else { + selectedItems.add(entry); + } + } else if (isShiftDown) { + final List<int> indexGroup = []; + for (var selected in selectedItems.items) { + indexGroup.add(entries.indexOf(selected)); + } + indexGroup.add(entries.indexOf(entry)); + indexGroup.removeWhere((e) => e == -1); + final maxIndex = indexGroup.reduce(max); + final minIndex = indexGroup.reduce(min); + selectedItems.clear(); + entries + .getRange(minIndex, maxIndex + 1) + .forEach((e) => selectedItems.add(e)); + } else { + selectedItems.clear(); + selectedItems.add(entry); + } + setState(() {}); + } + + bool _checkDoubleClick(Entry entry) { + final current = DateTime.now().millisecondsSinceEpoch; + final elapsed = current - _lastClickTime; + _lastClickTime = current; + if (_lastClickEntry == entry) { + if (elapsed < bind.getDoubleClickTime()) { + return true; + } + } else { + _lastClickEntry = entry; } return false; } - @override - bool get wantKeepAlive => true; - - void onLocalLocationFocusChanged() { - debugPrint("focus changed on local"); - if (_locationNodeLocal.hasFocus) { - // ignore - } else { - // lost focus, change to bread - if (_locationStatusLocal.value != LocationStatus.fileSearchBar) { - _locationStatusLocal.value = LocationStatus.bread; - } - } + Widget _buildFileBrowserHeader(BuildContext context) { + final padding = EdgeInsets.all(1.0); + return SizedBox( + height: kDesktopFileTransferHeaderHeight, + child: Row( + children: [ + Obx( + () => headerItemFunc( + _nameColWidth.value, SortBy.name, translate("Name")), + ), + DraggableDivider( + axis: Axis.vertical, + onPointerMove: (dx) { + _nameColWidth.value += dx; + _nameColWidth.value = min(kDesktopFileTransferMaximumWidth, + max(kDesktopFileTransferMinimumWidth, _nameColWidth.value)); + }, + padding: padding, + ), + Obx( + () => headerItemFunc(_modifiedColWidth.value, SortBy.modified, + translate("Modified")), + ), + DraggableDivider( + axis: Axis.vertical, + onPointerMove: (dx) { + _modifiedColWidth.value += dx; + _modifiedColWidth.value = min( + kDesktopFileTransferMaximumWidth, + max(kDesktopFileTransferMinimumWidth, + _modifiedColWidth.value)); + }, + padding: padding), + Expanded(child: headerItemFunc(null, SortBy.size, translate("Size"))) + ], + ), + ); } - void onRemoteLocationFocusChanged() { - debugPrint("focus changed on remote"); - if (_locationNodeRemote.hasFocus) { - // ignore - } else { - // lost focus, change to bread - if (_locationStatusRemote.value != LocationStatus.fileSearchBar) { - _locationStatusRemote.value = LocationStatus.bread; + Widget headerItemFunc(double? width, SortBy sortBy, String name) { + final headerTextStyle = + Theme.of(context).dataTableTheme.headingTextStyle ?? TextStyle(); + return ObxValue<Rx<bool?>>( + (ascending) => InkWell( + onTap: () { + if (ascending.value == null) { + ascending.value = true; + } else { + ascending.value = !ascending.value!; + } + controller.changeSortStyle(sortBy, + isLocal: isLocal, ascending: ascending.value!); + }, + child: SizedBox( + width: width, + height: kDesktopFileTransferHeaderHeight, + child: Row( + children: [ + Flexible( + flex: 2, + child: Text( + name, + style: headerTextStyle, + overflow: TextOverflow.ellipsis, + ).marginSymmetric(horizontal: 4), + ), + Flexible( + flex: 1, + child: ascending.value != null + ? Icon( + ascending.value! + ? Icons.keyboard_arrow_up_rounded + : Icons.keyboard_arrow_down_rounded, + ) + : const Offstage()) + ], + ), + ), + ), () { + if (controller.sortBy.value == sortBy) { + return controller.sortAscending.obs; + } else { + return Rx<bool?>(null); } - } + }()); } - Widget buildBread(bool isLocal) { + Widget buildBread() { final items = getPathBreadCrumbItems(isLocal, (list) { var path = ""; for (var item in list) { - path = PathUtil.join(path, item, model.getCurrentIsWindows(isLocal)); + path = PathUtil.join(path, item, controller.options.value.isWindows); } - openDirectory(path, isLocal: isLocal); + controller.openDirectory(path); }); - final locationBarKey = getLocationBarKey(isLocal); return items.isEmpty ? Offstage() : Row( - key: locationBarKey, + key: _locationBarKey, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( @@ -1169,7 +1238,7 @@ class _FileManagerPageState extends State<FileManagerPage> // handle mouse wheel onPointerSignal: (e) { if (e is PointerScrollEvent) { - final sc = getBreadCrumbScrollController(isLocal); + final sc = _breadCrumbScroller; final scale = Platform.isWindows ? 2 : 4; sc.jumpTo(sc.offset + e.scrollDelta.dy / scale); } @@ -1178,7 +1247,7 @@ class _FileManagerPageState extends State<FileManagerPage> items: items, divider: const Icon(Icons.keyboard_arrow_right_rounded), overflow: ScrollableOverflow( - controller: getBreadCrumbScrollController(isLocal), + controller: _breadCrumbScroller, ), ), ), @@ -1187,9 +1256,9 @@ class _FileManagerPageState extends State<FileManagerPage> message: "", icon: Icons.keyboard_arrow_down_rounded, onTap: () async { - final renderBox = locationBarKey.currentContext + final renderBox = _locationBarKey.currentContext ?.findRenderObject() as RenderBox; - locationBarKey.currentContext?.size; + _locationBarKey.currentContext?.size; final size = renderBox.size; final offset = renderBox.localToGlobal(Offset.zero); @@ -1197,17 +1266,17 @@ class _FileManagerPageState extends State<FileManagerPage> final x = offset.dx; final y = offset.dy + size.height + 1; - final isPeerWindows = model.getCurrentIsWindows(isLocal); + final isPeerWindows = controller.options.value.isWindows; final List<MenuEntryBase> menuItems = [ MenuEntryButton( childBuilder: (TextStyle? style) => isPeerWindows - ? buildWindowsThisPC(style) + ? buildWindowsThisPC(context, style) : Text( '/', style: style, ), proc: () { - openDirectory('/', isLocal: isLocal); + controller.openDirectory('/'); }, dismissOnClicked: true), MenuEntryDivider() @@ -1218,8 +1287,9 @@ class _FileManagerPageState extends State<FileManagerPage> loadingTag = _ffi.dialogManager.showLoading("Waiting"); } try { - final fd = - await model.fetchDirectory("/", isLocal, isLocal); + final showHidden = controller.options.value.showHidden; + final fd = await controller.fileFetcher + .fetchDirectory("/", isLocal, showHidden); for (var entry in fd.entries) { menuItems.add(MenuEntryButton( childBuilder: (TextStyle? style) => @@ -1238,8 +1308,7 @@ class _FileManagerPageState extends State<FileManagerPage> ) ]), proc: () { - openDirectory('${entry.name}\\', - isLocal: isLocal); + controller.openDirectory('${entry.name}\\'); }, dismissOnClicked: true)); } @@ -1274,24 +1343,15 @@ class _FileManagerPageState extends State<FileManagerPage> ]); } - Widget buildWindowsThisPC([TextStyle? textStyle]) { - final color = Theme.of(context).iconTheme.color?.withOpacity(0.7); - return Row(children: [ - Icon(Icons.computer, size: 20, color: color), - SizedBox(width: 10), - Text(translate('This PC'), style: textStyle) - ]); - } - List<BreadCrumbItem> getPathBreadCrumbItems( bool isLocal, void Function(List<String>) onPressed) { - final path = model.getCurrentDir(isLocal).path; + final path = controller.directory.value.path; final breadCrumbList = List<BreadCrumbItem>.empty(growable: true); - final isWindows = model.getCurrentIsWindows(isLocal); + final isWindows = controller.options.value.isWindows; if (isWindows && path == '/') { breadCrumbList.add(BreadCrumbItem( content: TextButton( - child: buildWindowsThisPC(), + child: buildWindowsThisPC(context), style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size(0, 0))), onPressed: () => onPressed(['/'])) @@ -1319,39 +1379,34 @@ class _FileManagerPageState extends State<FileManagerPage> return breadCrumbList; } - breadCrumbScrollToEnd(bool isLocal) { + breadCrumbScrollToEnd() { Future.delayed(Duration(milliseconds: 200), () { - final breadCrumbScroller = getBreadCrumbScrollController(isLocal); - if (breadCrumbScroller.hasClients) { - breadCrumbScroller.animateTo( - breadCrumbScroller.position.maxScrollExtent, + if (_breadCrumbScroller.hasClients) { + _breadCrumbScroller.animateTo( + _breadCrumbScroller.position.maxScrollExtent, duration: Duration(milliseconds: 200), curve: Curves.fastLinearToSlowEaseIn); } }); } - Widget buildPathLocation(bool isLocal) { - final searchTextObs = isLocal ? _searchTextLocal : _searchTextRemote; - final locationStatus = - isLocal ? _locationStatusLocal : _locationStatusRemote; - final focusNode = isLocal ? _locationNodeLocal : _locationNodeRemote; - final text = locationStatus.value == LocationStatus.pathLocation - ? model.getCurrentDir(isLocal).path - : searchTextObs.value; + Widget buildPathLocation() { + final text = _locationStatus.value == LocationStatus.pathLocation + ? controller.directory.value.path + : _searchText.value; final textController = TextEditingController(text: text) ..selection = TextSelection.collapsed(offset: text.length); return Row( children: [ SvgPicture.asset( - locationStatus.value == LocationStatus.pathLocation + _locationStatus.value == LocationStatus.pathLocation ? "assets/folder.svg" : "assets/search.svg", color: Theme.of(context).tabBarTheme.labelColor, ), Expanded( child: TextField( - focusNode: focusNode, + focusNode: _locationNode, decoration: InputDecoration( border: InputBorder.none, isDense: true, @@ -1361,9 +1416,9 @@ class _FileManagerPageState extends State<FileManagerPage> ), controller: textController, onSubmitted: (path) { - openDirectory(path, isLocal: isLocal); + controller.openDirectory(path); }, - onChanged: locationStatus.value == LocationStatus.fileSearchBar + onChanged: _locationStatus.value == LocationStatus.fileSearchBar ? (searchText) => onSearchText(searchText, isLocal) : null, ), @@ -1372,139 +1427,16 @@ class _FileManagerPageState extends State<FileManagerPage> ); } - onSearchText(String searchText, bool isLocal) { - if (isLocal) { - _localSelectedItems.clear(); - _searchTextLocal.value = searchText; - } else { - _remoteSelectedItems.clear(); - _searchTextRemote.value = searchText; - } - } - - openDirectory(String path, {bool isLocal = false}) { - model.openDirectory(path, isLocal: isLocal); - } - - void handleDragDone(DropDoneDetails details, bool isLocal) { - if (isLocal) { - // ignore local - return; - } - var items = SelectedItems(); - for (var file in details.files) { - final f = File(file.path); - items.add( - true, - Entry() - ..path = file.path - ..name = file.name - ..size = - FileSystemEntity.isDirectorySync(f.path) ? 0 : f.lengthSync()); - } - model.sendFiles(items, isRemote: false); - } - - void refocusKeyboardListener(bool isLocal) { - Future.delayed(Duration.zero, () { - if (isLocal) { - _keyboardNodeLocal.requestFocus(); - } else { - _keyboardNodeRemote.requestFocus(); - } - }); - } - - Widget headerItemFunc( - double? width, SortBy sortBy, String name, bool isLocal) { - final headerTextStyle = - Theme.of(context).dataTableTheme.headingTextStyle ?? TextStyle(); - return ObxValue<Rx<bool?>>( - (ascending) => InkWell( - onTap: () { - if (ascending.value == null) { - ascending.value = true; - } else { - ascending.value = !ascending.value!; - } - model.changeSortStyle(sortBy, - isLocal: isLocal, ascending: ascending.value!); - }, - child: SizedBox( - width: width, - height: kDesktopFileTransferHeaderHeight, - child: Row( - children: [ - Flexible( - flex: 2, - child: Text( - name, - style: headerTextStyle, - overflow: TextOverflow.ellipsis, - ).marginSymmetric(horizontal: 4), - ), - Flexible( - flex: 1, - child: ascending.value != null - ? Icon( - ascending.value! - ? Icons.keyboard_arrow_up_rounded - : Icons.keyboard_arrow_down_rounded, - ) - : const Offstage()) - ], - ), - ), - ), () { - if (model.getSortStyle(isLocal) == sortBy) { - return model.getSortAscending(isLocal).obs; - } else { - return Rx<bool?>(null); - } - }()); - } - - Widget _buildFileBrowserHeader(BuildContext context, bool isLocal) { - final nameColWidth = isLocal ? _nameColWidthLocal : _nameColWidthRemote; - final modifiedColWidth = - isLocal ? _modifiedColWidthLocal : _modifiedColWidthRemote; - final padding = EdgeInsets.all(1.0); - return SizedBox( - height: kDesktopFileTransferHeaderHeight, - child: Row( - children: [ - Obx( - () => headerItemFunc( - nameColWidth.value, SortBy.name, translate("Name"), isLocal), - ), - DraggableDivider( - axis: Axis.vertical, - onPointerMove: (dx) { - nameColWidth.value += dx; - nameColWidth.value = min(kDesktopFileTransferMaximumWidth, - max(kDesktopFileTransferMinimumWidth, nameColWidth.value)); - }, - padding: padding, - ), - Obx( - () => headerItemFunc(modifiedColWidth.value, SortBy.modified, - translate("Modified"), isLocal), - ), - DraggableDivider( - axis: Axis.vertical, - onPointerMove: (dx) { - modifiedColWidth.value += dx; - modifiedColWidth.value = min( - kDesktopFileTransferMaximumWidth, - max(kDesktopFileTransferMinimumWidth, - modifiedColWidth.value)); - }, - padding: padding), - Expanded( - child: - headerItemFunc(null, SortBy.size, translate("Size"), isLocal)) - ], - ), - ); - } + // openDirectory(String path, {bool isLocal = false}) { + // model.openDirectory(path, isLocal: isLocal); + // } +} + +Widget buildWindowsThisPC(BuildContext context, [TextStyle? textStyle]) { + final color = Theme.of(context).iconTheme.color?.withOpacity(0.7); + return Row(children: [ + Icon(Icons.computer, size: 20, color: color), + SizedBox(width: 10), + Text(translate('This PC'), style: textStyle) + ]); } diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index 7aa9a0005..c6ba42d31 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; import 'package:flutter_hbb/models/file_model.dart'; -import 'package:provider/provider.dart'; +import 'package:get/get.dart'; import 'package:toggle_switch/toggle_switch.dart'; import 'package:wakelock/wakelock.dart'; @@ -18,10 +18,51 @@ class FileManagerPage extends StatefulWidget { State<StatefulWidget> createState() => _FileManagerPageState(); } +enum SelectMode { local, remote, none } + +extension SelectModeEq on SelectMode { + bool eq(bool? currentIsLocal) { + if (currentIsLocal == null) { + return false; + } + if (currentIsLocal) { + return this == SelectMode.local; + } else { + return this == SelectMode.remote; + } + } +} + +extension SelectModeExt on Rx<SelectMode> { + void toggle(bool currentIsLocal) { + switch (value) { + case SelectMode.local: + value = SelectMode.none; + break; + case SelectMode.remote: + value = SelectMode.none; + break; + case SelectMode.none: + if (currentIsLocal) { + value = SelectMode.local; + } else { + value = SelectMode.remote; + } + break; + } + } +} + class _FileManagerPageState extends State<FileManagerPage> { final model = gFFI.fileModel; - final _selectedItems = SelectedItems(); - final _breadCrumbScroller = ScrollController(); + final selectMode = SelectMode.none.obs; + + var showLocal = true; + + FileController get currentFileController => + showLocal ? model.localController : model.remoteController; + FileDirectory get currentDir => currentFileController.directory.value; + DirectoryOptions get currentOptions => currentFileController.options.value; @override void initState() { @@ -32,13 +73,12 @@ class _FileManagerPageState extends State<FileManagerPage> { .showLoading(translate('Connecting...'), onCancel: closeConnection); }); gFFI.ffiModel.updateEventListener(widget.id); - model.onDirChanged = (_) => breadCrumbScrollToEnd(); Wakelock.enable(); } @override void dispose() { - model.onClose().whenComplete(() { + model.close().whenComplete(() { gFFI.close(); gFFI.dialogManager.dismissAll(); Wakelock.disable(); @@ -47,288 +87,455 @@ class _FileManagerPageState extends State<FileManagerPage> { } @override - Widget build(BuildContext context) => ChangeNotifierProvider.value( - value: model, - child: Consumer<FileModel>(builder: (_context, _model, _child) { - return WillPopScope( - onWillPop: () async { - if (model.selectMode) { - model.toggleSelectMode(); - } else { - model.goBack(); + Widget build(BuildContext context) => WillPopScope( + onWillPop: () async { + if (selectMode.value != SelectMode.none) { + selectMode.value = SelectMode.none; + setState(() {}); + } else { + currentFileController.goBack(); + } + return false; + }, + child: Scaffold( + // backgroundColor: MyTheme.grayBg, + appBar: AppBar( + leading: Row(children: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () => clientClose(widget.id, gFFI.dialogManager)), + ]), + centerTitle: true, + title: ToggleSwitch( + initialLabelIndex: showLocal ? 0 : 1, + activeBgColor: [MyTheme.idColor], + inactiveBgColor: Theme.of(context).brightness == Brightness.light + ? MyTheme.grayBg + : null, + inactiveFgColor: Theme.of(context).brightness == Brightness.light + ? Colors.black54 + : null, + totalSwitches: 2, + minWidth: 100, + fontSize: 15, + iconSize: 18, + labels: [translate("Local"), translate("Remote")], + icons: [Icons.phone_android_sharp, Icons.screen_share], + onToggle: (index) { + final current = showLocal ? 0 : 1; + if (index != current) { + setState(() => showLocal = !showLocal); } - return false; }, - child: Scaffold( - // backgroundColor: MyTheme.grayBg, - appBar: AppBar( - leading: Row(children: [ - IconButton( - icon: Icon(Icons.close), - onPressed: () => - clientClose(widget.id, gFFI.dialogManager)), - ]), - centerTitle: true, - title: ToggleSwitch( - initialLabelIndex: model.isLocal ? 0 : 1, - activeBgColor: [MyTheme.idColor], - inactiveBgColor: - Theme.of(context).brightness == Brightness.light - ? MyTheme.grayBg - : null, - inactiveFgColor: - Theme.of(context).brightness == Brightness.light - ? Colors.black54 - : null, - totalSwitches: 2, - minWidth: 100, - fontSize: 15, - iconSize: 18, - labels: [translate("Local"), translate("Remote")], - icons: [Icons.phone_android_sharp, Icons.screen_share], - onToggle: (index) { - final current = model.isLocal ? 0 : 1; - if (index != current) { - model.togglePage(); - } - }, - ), - actions: [ - PopupMenuButton<String>( - icon: Icon(Icons.more_vert), - itemBuilder: (context) { - return [ - PopupMenuItem( - child: Row( - children: [ - Icon(Icons.refresh, - color: Theme.of(context).iconTheme.color), - SizedBox(width: 5), - Text(translate("Refresh File")) - ], - ), - value: "refresh", - ), - PopupMenuItem( - enabled: model.currentDir.path != "/", - child: Row( - children: [ - Icon(Icons.check, - color: Theme.of(context).iconTheme.color), - SizedBox(width: 5), - Text(translate("Multi Select")) - ], - ), - value: "select", - ), - PopupMenuItem( - enabled: model.currentDir.path != "/", - child: Row( - children: [ - Icon(Icons.folder_outlined, - color: Theme.of(context).iconTheme.color), - SizedBox(width: 5), - Text(translate("Create Folder")) - ], - ), - value: "folder", - ), - PopupMenuItem( - enabled: model.currentDir.path != "/", - child: Row( - children: [ - Icon( - model.getCurrentShowHidden() - ? Icons.check_box_outlined - : Icons.check_box_outline_blank, - color: Theme.of(context).iconTheme.color), - SizedBox(width: 5), - Text(translate("Show Hidden Files")) - ], - ), - value: "hidden", - ) - ]; - }, - onSelected: (v) { - if (v == "refresh") { - model.refresh(); - } else if (v == "select") { - _selectedItems.clear(); - model.toggleSelectMode(); - } else if (v == "folder") { - final name = TextEditingController(); - gFFI.dialogManager - .show((setState, close) => CustomAlertDialog( - title: Text(translate("Create Folder")), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextFormField( - decoration: InputDecoration( - labelText: translate( - "Please enter the folder name"), - ), - controller: name, - ), - ], + ), + actions: [ + PopupMenuButton<String>( + icon: Icon(Icons.more_vert), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Row( + children: [ + Icon(Icons.refresh, + color: Theme.of(context).iconTheme.color), + SizedBox(width: 5), + Text(translate("Refresh File")) + ], + ), + value: "refresh", + ), + PopupMenuItem( + enabled: currentDir.path != "/", + child: Row( + children: [ + Icon(Icons.check, + color: Theme.of(context).iconTheme.color), + SizedBox(width: 5), + Text(translate("Multi Select")) + ], + ), + value: "select", + ), + PopupMenuItem( + enabled: currentDir.path != "/", + child: Row( + children: [ + Icon(Icons.folder_outlined, + color: Theme.of(context).iconTheme.color), + SizedBox(width: 5), + Text(translate("Create Folder")) + ], + ), + value: "folder", + ), + PopupMenuItem( + enabled: currentDir.path != "/", + child: Row( + children: [ + Icon( + currentOptions.showHidden + ? Icons.check_box_outlined + : Icons.check_box_outline_blank, + color: Theme.of(context).iconTheme.color), + SizedBox(width: 5), + Text(translate("Show Hidden Files")) + ], + ), + value: "hidden", + ) + ]; + }, + onSelected: (v) { + if (v == "refresh") { + currentFileController.refresh(); + } else if (v == "select") { + model.localController.selectedItems.clear(); + model.remoteController.selectedItems.clear(); + selectMode.toggle(showLocal); + setState(() {}); + } else if (v == "folder") { + final name = TextEditingController(); + gFFI.dialogManager + .show((setState, close) => CustomAlertDialog( + title: Text(translate("Create Folder")), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + decoration: InputDecoration( + labelText: translate( + "Please enter the folder name"), ), - actions: [ - dialogButton("Cancel", - onPressed: () => close(false), - isOutline: true), - dialogButton("OK", onPressed: () { - if (name.value.text.isNotEmpty) { - model.createDir(PathUtil.join( - model.currentDir.path, - name.value.text, - model.getCurrentIsWindows())); - close(); - } - }) - ])); - } else if (v == "hidden") { - model.toggleShowHidden(); - } - }), - ], + controller: name, + ), + ], + ), + actions: [ + dialogButton("Cancel", + onPressed: () => close(false), + isOutline: true), + dialogButton("OK", onPressed: () { + if (name.value.text.isNotEmpty) { + currentFileController.createDir( + PathUtil.join( + currentDir.path, + name.value.text, + currentOptions.isWindows)); + close(); + } + }) + ])); + } else if (v == "hidden") { + currentFileController.toggleShowHidden(); + } + }), + ], + ), + body: showLocal + ? FileManagerView( + controller: model.localController, + selectMode: selectMode, + ) + : FileManagerView( + controller: model.remoteController, + selectMode: selectMode, ), - body: body(), - bottomSheet: bottomSheet(), - )); - })); + bottomSheet: bottomSheet(), + )); - bool showCheckBox() { - if (!model.selectMode) { - return false; - } - return !_selectedItems.isOtherPage(model.isLocal); + Widget? bottomSheet() { + return Obx(() { + final selectedItems = getActiveSelectedItems(); + final jobTable = model.jobController.jobTable; + + final localLabel = selectedItems?.isLocal == null + ? "" + : " [${selectedItems!.isLocal ? translate("Local") : translate("Remote")}]"; + if (!(selectMode.value == SelectMode.none)) { + final selectedItemsLen = + "${selectedItems?.items.length ?? 0} ${translate("items")}"; + if (selectedItems == null || + selectedItems.items.isEmpty || + selectMode.value.eq(showLocal)) { + return BottomSheetBody( + leading: Icon(Icons.check), + title: translate("Selected"), + text: selectedItemsLen + localLabel, + onCanceled: () { + selectedItems?.items.clear(); + selectMode.value = SelectMode.none; + setState(() {}); + }, + actions: [ + IconButton( + icon: Icon(Icons.compare_arrows), + onPressed: () => setState(() => showLocal = !showLocal), + ), + IconButton( + icon: Icon(Icons.delete_forever), + onPressed: selectedItems != null + ? () async { + if (selectedItems.items.isNotEmpty) { + await currentFileController + .removeAction(selectedItems); + selectedItems.items.clear(); + selectMode.value = SelectMode.none; + } + } + : null, + ) + ]); + } else { + return BottomSheetBody( + leading: Icon(Icons.input), + title: translate("Paste here?"), + text: selectedItemsLen + localLabel, + onCanceled: () { + selectedItems.items.clear(); + selectMode.value = SelectMode.none; + setState(() {}); + }, + actions: [ + IconButton( + icon: Icon(Icons.compare_arrows), + onPressed: () => setState(() => showLocal = !showLocal), + ), + IconButton( + icon: Icon(Icons.paste), + onPressed: () { + selectMode.value = SelectMode.none; + final otherSide = showLocal + ? model.remoteController + : model.localController; + final thisSideData = + DirectoryData(currentDir, currentOptions); + otherSide.sendFiles(selectedItems, thisSideData); + selectedItems.items.clear(); + selectMode.value = SelectMode.none; + }, + ) + ]); + } + } + + if (jobTable.isEmpty) { + return Offstage(); + } + + switch (jobTable.last.state) { + case JobState.inProgress: + return BottomSheetBody( + leading: CircularProgressIndicator(), + title: translate("Waiting"), + text: + "${translate("Speed")}: ${readableFileSize(jobTable.last.speed)}/s", + onCanceled: () { + model.jobController.cancelJob(jobTable.last.id); + jobTable.clear(); + }, + ); + case JobState.done: + return BottomSheetBody( + leading: Icon(Icons.check), + title: "${translate("Successful")}!", + text: jobTable.last.display(), + onCanceled: () => jobTable.clear(), + ); + case JobState.error: + return BottomSheetBody( + leading: Icon(Icons.error), + title: "${translate("Error")}!", + text: "", + onCanceled: () => jobTable.clear(), + ); + case JobState.none: + break; + case JobState.paused: + // TODO: Handle this case. + break; + } + return Offstage(); + }); } - Widget body() { - final isLocal = model.isLocal; - final fd = model.currentDir; - final entries = fd.entries; + SelectedItems? getActiveSelectedItems() { + final localSelectedItems = model.localController.selectedItems; + final remoteSelectedItems = model.remoteController.selectedItems; + + if (localSelectedItems.items.isNotEmpty && + remoteSelectedItems.items.isNotEmpty) { + // assert unreachable + debugPrint("Wrong SelectedItems state, reset"); + localSelectedItems.clear(); + remoteSelectedItems.clear(); + } + + if (localSelectedItems.items.isEmpty && remoteSelectedItems.items.isEmpty) { + return null; + } + + if (localSelectedItems.items.length > remoteSelectedItems.items.length) { + return localSelectedItems; + } else { + return remoteSelectedItems; + } + } +} + +class FileManagerView extends StatefulWidget { + final FileController controller; + final Rx<SelectMode> selectMode; + + FileManagerView({required this.controller, required this.selectMode}); + + @override + State<StatefulWidget> createState() => _FileManagerViewState(); +} + +class _FileManagerViewState extends State<FileManagerView> { + final _listScrollController = ScrollController(); + final _breadCrumbScroller = ScrollController(); + + bool get isLocal => widget.controller.isLocal; + FileController get controller => widget.controller; + SelectedItems get _selectedItems => widget.controller.selectedItems; + + @override + void initState() { + super.initState(); + controller.directory.listen((e) => breadCrumbScrollToEnd()); + } + + @override + Widget build(BuildContext context) { return Column(children: [ headTools(), - Expanded( - child: ListView.builder( - controller: ScrollController(), - itemCount: entries.length + 1, - itemBuilder: (context, index) { - if (index >= entries.length) { - return listTail(); - } - var selected = false; - if (model.selectMode) { - selected = _selectedItems.contains(entries[index]); - } + Expanded(child: Obx(() { + final entries = controller.directory.value.entries; + return ListView.builder( + controller: _listScrollController, + itemCount: entries.length + 1, + itemBuilder: (context, index) { + if (index >= entries.length) { + return listTail(); + } + var selected = false; + if (widget.selectMode.value != SelectMode.none) { + selected = _selectedItems.items.contains(entries[index]); + } - final sizeStr = entries[index].isFile - ? readableFileSize(entries[index].size.toDouble()) - : ""; - return Card( - child: ListTile( - leading: entries[index].isDrive - ? Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: Image( - image: iconHardDrive, - fit: BoxFit.scaleDown, - color: Theme.of(context) - .iconTheme - .color - ?.withOpacity(0.7))) - : Icon( - entries[index].isFile - ? Icons.feed_outlined - : Icons.folder, - size: 40), - title: Text(entries[index].name), - selected: selected, - subtitle: entries[index].isDrive - ? null - : Text( - "${entries[index].lastModified().toString().replaceAll(".000", "")} $sizeStr", - style: TextStyle(fontSize: 12, color: MyTheme.darkGray), - ), - trailing: entries[index].isDrive - ? null - : showCheckBox() - ? Checkbox( - value: selected, - onChanged: (v) { - if (v == null) return; - if (v && !selected) { - _selectedItems.add(isLocal, entries[index]); - } else if (!v && selected) { - _selectedItems.remove(entries[index]); - } - setState(() {}); - }) - : PopupMenuButton<String>( - icon: Icon(Icons.more_vert), - itemBuilder: (context) { - return [ - PopupMenuItem( - child: Text(translate("Delete")), - value: "delete", - ), - PopupMenuItem( - child: Text(translate("Multi Select")), - value: "multi_select", - ), - PopupMenuItem( - child: Text(translate("Properties")), - value: "properties", - enabled: false, - ) - ]; - }, - onSelected: (v) { - if (v == "delete") { - final items = SelectedItems(); - items.add(isLocal, entries[index]); - model.removeAction(items); - } else if (v == "multi_select") { - _selectedItems.clear(); - model.toggleSelectMode(); - } - }), - onTap: () { - if (model.selectMode && !_selectedItems.isOtherPage(isLocal)) { - if (selected) { - _selectedItems.remove(entries[index]); - } else { - _selectedItems.add(isLocal, entries[index]); + final sizeStr = entries[index].isFile + ? readableFileSize(entries[index].size.toDouble()) + : ""; + + final showCheckBox = () { + return widget.selectMode.value != SelectMode.none && + widget.selectMode.value.eq(controller.selectedItems.isLocal); + }(); + return Card( + child: ListTile( + leading: entries[index].isDrive + ? Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Image( + image: iconHardDrive, + fit: BoxFit.scaleDown, + color: Theme.of(context) + .iconTheme + .color + ?.withOpacity(0.7))) + : Icon( + entries[index].isFile + ? Icons.feed_outlined + : Icons.folder, + size: 40), + title: Text(entries[index].name), + selected: selected, + subtitle: entries[index].isDrive + ? null + : Text( + "${entries[index].lastModified().toString().replaceAll(".000", "")} $sizeStr", + style: TextStyle(fontSize: 12, color: MyTheme.darkGray), + ), + trailing: entries[index].isDrive + ? null + : showCheckBox + ? Checkbox( + value: selected, + onChanged: (v) { + if (v == null) return; + if (v && !selected) { + _selectedItems.add(entries[index]); + } else if (!v && selected) { + _selectedItems.remove(entries[index]); + } + setState(() {}); + }) + : PopupMenuButton<String>( + icon: Icon(Icons.more_vert), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text(translate("Delete")), + value: "delete", + ), + PopupMenuItem( + child: Text(translate("Multi Select")), + value: "multi_select", + ), + PopupMenuItem( + child: Text(translate("Properties")), + value: "properties", + enabled: false, + ) + ]; + }, + onSelected: (v) { + if (v == "delete") { + final items = SelectedItems(isLocal: isLocal); + items.add(entries[index]); + controller.removeAction(items); + } else if (v == "multi_select") { + _selectedItems.clear(); + widget.selectMode.toggle(isLocal); + setState(() {}); + } + }), + onTap: () { + if (showCheckBox) { + if (selected) { + _selectedItems.remove(entries[index]); + } else { + _selectedItems.add(entries[index]); + } + setState(() {}); + return; } - setState(() {}); - return; - } - if (entries[index].isDirectory || entries[index].isDrive) { - model.openDirectory(entries[index].path); - } else { - // Perform file-related tasks. - } - }, - onLongPress: entries[index].isDrive - ? null - : () { - _selectedItems.clear(); - model.toggleSelectMode(); - if (model.selectMode) { - _selectedItems.add(isLocal, entries[index]); - } - setState(() {}); - }, - ), - ); - }, - )) + if (entries[index].isDirectory || entries[index].isDrive) { + controller.openDirectory(entries[index].path); + } else { + // Perform file-related tasks. + } + }, + onLongPress: entries[index].isDrive + ? null + : () { + _selectedItems.clear(); + widget.selectMode.toggle(isLocal); + if (widget.selectMode.value != SelectMode.none) { + _selectedItems.add(entries[index]); + } + setState(() {}); + }, + ), + ); + }, + ); + })) ]); } - breadCrumbScrollToEnd() { + void breadCrumbScrollToEnd() { Future.delayed(Duration(milliseconds: 200), () { if (_breadCrumbScroller.hasClients) { _breadCrumbScroller.animateTo( @@ -342,35 +549,39 @@ class _FileManagerPageState extends State<FileManagerPage> { Widget headTools() => Container( child: Row( children: [ - Expanded( - child: BreadCrumb( - items: getPathBreadCrumbItems(() => model.goHome(), (list) { - var path = ""; - if (model.currentHome.startsWith(list[0])) { - // absolute path - for (var item in list) { - path = PathUtil.join(path, item, model.getCurrentIsWindows()); + Expanded(child: Obx(() { + final home = controller.options.value.home; + final isWindows = controller.options.value.isWindows; + return BreadCrumb( + items: getPathBreadCrumbItems(controller.shortPath, isWindows, + () => controller.goToHomeDirectory(), (list) { + var path = ""; + if (home.startsWith(list[0])) { + // absolute path + for (var item in list) { + path = PathUtil.join(path, item, isWindows); + } + } else { + path += home; + for (var item in list) { + path = PathUtil.join(path, item, isWindows); + } } - } else { - path += model.currentHome; - for (var item in list) { - path = PathUtil.join(path, item, model.getCurrentIsWindows()); - } - } - model.openDirectory(path); - }), - divider: Icon(Icons.chevron_right), - overflow: ScrollableOverflow(controller: _breadCrumbScroller), - )), + controller.openDirectory(path); + }), + divider: Icon(Icons.chevron_right), + overflow: ScrollableOverflow(controller: _breadCrumbScroller), + ); + })), Row( children: [ IconButton( icon: Icon(Icons.arrow_back), - onPressed: model.goBack, + onPressed: controller.goBack, ), IconButton( icon: Icon(Icons.arrow_upward), - onPressed: model.goToParentDirectory, + onPressed: controller.goToParentDirectory, ), PopupMenuButton<SortBy>( icon: Icon(Icons.sort), @@ -382,123 +593,37 @@ class _FileManagerPageState extends State<FileManagerPage> { )) .toList(); }, - onSelected: model.changeSortStyle), + onSelected: controller.changeSortStyle), ], ) ], )); - Widget listTail() { - return Container( - height: 100, - child: Column( - children: [ - Padding( - padding: EdgeInsets.fromLTRB(30, 5, 30, 0), - child: Text( - model.currentDir.path, - style: TextStyle(color: MyTheme.darkGray), - ), - ), - Padding( - padding: EdgeInsets.all(2), - child: Text( - "${translate("Total")}: ${model.currentDir.entries.length} ${translate("items")}", - style: TextStyle(color: MyTheme.darkGray), - ), - ) - ], - ), - ); - } - - Widget? bottomSheet() { - final state = model.jobState; - final isOtherPage = _selectedItems.isOtherPage(model.isLocal); - final selectedItemsLen = "${_selectedItems.length} ${translate("items")}"; - final local = _selectedItems.isLocal == null - ? "" - : " [${_selectedItems.isLocal! ? translate("Local") : translate("Remote")}]"; - - if (model.selectMode) { - if (_selectedItems.length == 0 || !isOtherPage) { - return BottomSheetBody( - leading: Icon(Icons.check), - title: translate("Selected"), - text: selectedItemsLen + local, - onCanceled: () => model.toggleSelectMode(), - actions: [ - IconButton( - icon: Icon(Icons.compare_arrows), - onPressed: model.togglePage, + Widget listTail() => Obx(() => Container( + height: 100, + child: Column( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(30, 5, 30, 0), + child: Text( + controller.directory.value.path, + style: TextStyle(color: MyTheme.darkGray), ), - IconButton( - icon: Icon(Icons.delete_forever), - onPressed: () { - if (_selectedItems.length > 0) { - model.removeAction(_selectedItems); - } - }, - ) - ]); - } else { - return BottomSheetBody( - leading: Icon(Icons.input), - title: translate("Paste here?"), - text: selectedItemsLen + local, - onCanceled: () => model.toggleSelectMode(), - actions: [ - IconButton( - icon: Icon(Icons.compare_arrows), - onPressed: model.togglePage, + ), + Padding( + padding: EdgeInsets.all(2), + child: Text( + "${translate("Total")}: ${controller.directory.value.entries.length} ${translate("items")}", + style: TextStyle(color: MyTheme.darkGray), ), - IconButton( - icon: Icon(Icons.paste), - onPressed: () { - model.toggleSelectMode(); - model.sendFiles(_selectedItems); - }, - ) - ]); - } - } + ) + ], + ), + )); - switch (state) { - case JobState.inProgress: - return BottomSheetBody( - leading: CircularProgressIndicator(), - title: translate("Waiting"), - text: - "${translate("Speed")}: ${readableFileSize(model.jobProgress.speed)}/s", - onCanceled: () => model.cancelJob(model.jobProgress.id), - ); - case JobState.done: - return BottomSheetBody( - leading: Icon(Icons.check), - title: "${translate("Successful")}!", - text: model.jobProgress.display(), - onCanceled: () => model.jobReset(), - ); - case JobState.error: - return BottomSheetBody( - leading: Icon(Icons.error), - title: "${translate("Error")}!", - text: "", - onCanceled: () => model.jobReset(), - ); - case JobState.none: - break; - case JobState.paused: - // TODO: Handle this case. - break; - } - return null; - } - - List<BreadCrumbItem> getPathBreadCrumbItems( + List<BreadCrumbItem> getPathBreadCrumbItems(String shortPath, bool isWindows, void Function() onHome, void Function(List<String>) onPressed) { - final path = model.currentShortPath; - final list = PathUtil.split(path, model.getCurrentIsWindows()); + final list = PathUtil.split(shortPath, isWindows); final breadCrumbList = [ BreadCrumbItem( content: IconButton( diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index feaecd356..4170a5461 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -24,298 +24,83 @@ enum SortBy { } } -class FileModel extends ChangeNotifier { - /// mobile, current selected page show on mobile screen - var _isSelectedLocal = false; - - /// mobile, select mode state - var _selectMode = false; - - final _localOption = DirectoryOption(); - final _remoteOption = DirectoryOption(); - - List<String> localHistory = []; - List<String> remoteHistory = []; - - var _jobId = 0; - - final _jobProgress = JobProgress(); // from rust update - - /// JobTable <jobId, JobProgress> - final _jobTable = List<JobProgress>.empty(growable: true).obs; - - /// `isLocal` bool - Function(bool)? onDirChanged; - - RxList<JobProgress> get jobTable => _jobTable; - - bool get isLocal => _isSelectedLocal; - - bool get selectMode => _selectMode; - - JobProgress get jobProgress => _jobProgress; - - JobState get jobState => _jobProgress.state; - - SortBy _sortStyle = SortBy.name; - - SortBy get sortStyle => _sortStyle; - - SortBy _localSortStyle = SortBy.name; - - bool _localSortAscending = true; - - bool _remoteSortAscending = true; - - SortBy _remoteSortStyle = SortBy.name; - - bool get localSortAscending => _localSortAscending; - - SortBy getSortStyle(bool isLocal) { - return isLocal ? _localSortStyle : _remoteSortStyle; +class JobID { + int _count = 0; + int next() { + _count++; + return _count; } +} - bool getSortAscending(bool isLocal) { - return isLocal ? _localSortAscending : _remoteSortAscending; - } - - FileDirectory _currentLocalDir = FileDirectory(); - - FileDirectory get currentLocalDir => _currentLocalDir; - - FileDirectory _currentRemoteDir = FileDirectory(); - - FileDirectory get currentRemoteDir => _currentRemoteDir; - - FileDirectory get currentDir => - _isSelectedLocal ? currentLocalDir : currentRemoteDir; - - FileDirectory getCurrentDir(bool isLocal) { - return isLocal ? currentLocalDir : currentRemoteDir; - } - - String getCurrentShortPath(bool isLocal) { - final currentDir = getCurrentDir(isLocal); - final currentHome = getCurrentHome(isLocal); - if (currentDir.path.startsWith(currentHome)) { - var path = currentDir.path.replaceFirst(currentHome, ""); - if (path.isEmpty) return ""; - if (path[0] == "/" || path[0] == "\\") { - // remove more '/' or '\' - path = path.replaceFirst(path[0], ""); - } - return path; - } else { - return currentDir.path.replaceFirst(currentHome, ""); - } - } - - String get currentHome => - _isSelectedLocal ? _localOption.home : _remoteOption.home; - - String getCurrentHome(bool isLocal) { - return isLocal ? _localOption.home : _remoteOption.home; - } - - int getJob(int id) { - return jobTable.indexWhere((element) => element.id == id); - } - - String get currentShortPath { - if (currentDir.path.startsWith(currentHome)) { - var path = currentDir.path.replaceFirst(currentHome, ""); - if (path.isEmpty) return ""; - if (path[0] == "/" || path[0] == "\\") { - // remove more '/' or '\' - path = path.replaceFirst(path[0], ""); - } - return path; - } else { - return currentDir.path.replaceFirst(currentHome, ""); - } - } - - String shortPath(bool isLocal) { - final dir = isLocal ? currentLocalDir : currentRemoteDir; - if (dir.path.startsWith(currentHome)) { - var path = dir.path.replaceFirst(currentHome, ""); - if (path.isEmpty) return ""; - if (path[0] == "/" || path[0] == "\\") { - // remove more '/' or '\' - path = path.replaceFirst(path[0], ""); - } - return path; - } else { - return dir.path.replaceFirst(currentHome, ""); - } - } - - bool getCurrentShowHidden([bool? isLocal]) { - final isLocal_ = isLocal ?? _isSelectedLocal; - return isLocal_ ? _localOption.showHidden : _remoteOption.showHidden; - } - - bool getCurrentIsWindows([bool? isLocal]) { - final isLocal_ = isLocal ?? _isSelectedLocal; - return isLocal_ ? _localOption.isWindows : _remoteOption.isWindows; - } - - final _fileFetcher = FileFetcher(); - - final _jobResultListener = JobResultListener<Map<String, dynamic>>(); +typedef GetSessionID = String Function(); +class FileModel { final WeakReference<FFI> parent; + // late final String sessionID; + late final FileFetcher fileFetcher; + late final JobController jobController; - FileModel(this.parent); + late final FileController localController; + late final FileController remoteController; - toggleSelectMode() { - if (jobState == JobState.inProgress) { - return; - } - _selectMode = !_selectMode; - notifyListeners(); + late final GetSessionID getSessionID; + String get sessionID => getSessionID(); + + FileModel(this.parent) { + getSessionID = () => parent.target?.id ?? ""; + fileFetcher = FileFetcher(getSessionID); + jobController = JobController(getSessionID); + localController = FileController( + isLocal: true, + getSessionID: getSessionID, + dialogManager: parent.target?.dialogManager, + jobController: jobController, + fileFetcher: fileFetcher, + getOtherSideDirectoryData: () => remoteController.directoryData()); + remoteController = FileController( + isLocal: false, + getSessionID: getSessionID, + dialogManager: parent.target?.dialogManager, + jobController: jobController, + fileFetcher: fileFetcher, + getOtherSideDirectoryData: () => localController.directoryData()); } - togglePage() { - _isSelectedLocal = !_isSelectedLocal; - notifyListeners(); + Future<void> onReady() async { + await localController.onReady(); + await remoteController.onReady(); } - toggleShowHidden({bool? showHidden, bool? local}) { - final isLocal = local ?? _isSelectedLocal; - if (isLocal) { - _localOption.showHidden = showHidden ?? !_localOption.showHidden; - } else { - _remoteOption.showHidden = showHidden ?? !_remoteOption.showHidden; - } - refresh(isLocal: local); + Future<void> close() async { + parent.target?.dialogManager.dismissAll(); + await localController.close(); + await remoteController.close(); } - tryUpdateJobProgress(Map<String, dynamic> evt) { - try { - int id = int.parse(evt['id']); - if (!isDesktop) { - _jobProgress.id = id; - _jobProgress.fileNum = int.parse(evt['file_num']); - _jobProgress.speed = double.parse(evt['speed']); - _jobProgress.finishedSize = int.parse(evt['finished_size']); - } else { - // Desktop uses jobTable - // id = index + 1 - final jobIndex = getJob(id); - if (jobIndex >= 0 && _jobTable.length > jobIndex) { - final job = _jobTable[jobIndex]; - job.fileNum = int.parse(evt['file_num']); - job.speed = double.parse(evt['speed']); - job.finishedSize = int.parse(evt['finished_size']); - debugPrint("update job $id with $evt"); - } - } - notifyListeners(); - } catch (e) { - debugPrint("Failed to tryUpdateJobProgress,evt:${evt.toString()}"); - } + Future<void> refreshAll() async { + await localController.refresh(); + await remoteController.refresh(); } - receiveFileDir(Map<String, dynamic> evt) { + void receiveFileDir(Map<String, dynamic> evt) { if (evt['is_local'] == "false") { - // init remote home, the connection will automatic read remote home when established, - try { - final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); - fd.format(_remoteOption.isWindows, sort: _sortStyle); - if (fd.id > 0) { - final jobIndex = getJob(fd.id); - if (jobIndex != -1) { - final job = jobTable[jobIndex]; - var totalSize = 0; - var fileCount = fd.entries.length; - for (var element in fd.entries) { - totalSize += element.size; - } - job.totalSize = totalSize; - job.fileCount = fileCount; - debugPrint("update receive details:${fd.path}"); - } - } else if (_remoteOption.home.isEmpty) { - _remoteOption.home = fd.path; - debugPrint("init remote home:${fd.path}"); - _currentRemoteDir = fd; - } - } catch (e) { - debugPrint("receiveFileDir err=$e"); - } + // init remote home, the remote connection will send one dir event when established. TODO opt + remoteController.initDirAndHome(evt); } - _fileFetcher.tryCompleteTask(evt['value'], evt['is_local']); - notifyListeners(); + fileFetcher.tryCompleteTask(evt['value'], evt['is_local']); } - jobDone(Map<String, dynamic> evt) async { - if (_jobResultListener.isListening) { - _jobResultListener.complete(evt); - return; - } - if (!isDesktop) { - _selectMode = false; - _jobProgress.state = JobState.done; - } else { - int id = int.parse(evt['id']); - final jobIndex = getJob(id); - if (jobIndex != -1) { - final job = jobTable[jobIndex]; - job.finishedSize = job.totalSize; - job.state = JobState.done; - job.fileNum = int.parse(evt['file_num']); - } - } - await Future.wait([ - refresh(isLocal: false), - refresh(isLocal: true), - ]); - } - - jobError(Map<String, dynamic> evt) { - final err = evt['err'].toString(); - if (!isDesktop) { - if (_jobResultListener.isListening) { - _jobResultListener.complete(evt); - return; - } - _selectMode = false; - _jobProgress.clear(); - _jobProgress.err = err; - _jobProgress.state = JobState.error; - _jobProgress.fileNum = int.parse(evt['file_num']); - if (err == "skipped") { - _jobProgress.state = JobState.done; - _jobProgress.finishedSize = _jobProgress.totalSize; - } - } else { - int jobIndex = getJob(int.parse(evt['id'])); - if (jobIndex != -1) { - final job = jobTable[jobIndex]; - job.state = JobState.error; - job.err = err; - job.fileNum = int.parse(evt['file_num']); - if (err == "skipped") { - job.state = JobState.done; - job.finishedSize = job.totalSize; - } - } - } - debugPrint("jobError $evt"); - notifyListeners(); - } - - overrideFileConfirm(Map<String, dynamic> evt) async { + void overrideFileConfirm(Map<String, dynamic> evt) async { final resp = await showFileConfirmDialog( translate("Overwrite"), "${evt['read_path']}", true); final id = int.tryParse(evt['id']) ?? 0; if (false == resp) { - final jobIndex = getJob(id); + final jobIndex = jobController.getJob(id); if (jobIndex != -1) { - cancelJob(id); - final job = jobTable[jobIndex]; + jobController.cancelJob(id); + final job = jobController.jobTable[jobIndex]; job.state = JobState.done; + jobController.jobTable.refresh(); } } else { var need_override = false; @@ -327,7 +112,7 @@ class FileModel extends ChangeNotifier { need_override = true; } bind.sessionSetConfirmOverrideFile( - id: parent.target?.id ?? "", + id: sessionID, actId: id, fileNum: int.parse(evt['file_num']), needOverride: need_override, @@ -336,367 +121,6 @@ class FileModel extends ChangeNotifier { } } - jobReset() { - _jobProgress.clear(); - notifyListeners(); - } - - onReady() async { - _localOption.home = await bind.mainGetHomeDir(); - _localOption.showHidden = (await bind.sessionGetPeerOption( - id: parent.target?.id ?? "", name: "local_show_hidden")) - .isNotEmpty; - _localOption.isWindows = Platform.isWindows; - - _remoteOption.showHidden = (await bind.sessionGetPeerOption( - id: parent.target?.id ?? "", name: "remote_show_hidden")) - .isNotEmpty; - _remoteOption.isWindows = - parent.target?.ffiModel.pi.platform == kPeerPlatformWindows; - - await Future.delayed(Duration(milliseconds: 100)); - - final local = (await bind.sessionGetPeerOption( - id: parent.target?.id ?? "", name: "local_dir")); - final remote = (await bind.sessionGetPeerOption( - id: parent.target?.id ?? "", name: "remote_dir")); - openDirectory(local.isEmpty ? _localOption.home : local, isLocal: true); - openDirectory(remote.isEmpty ? _remoteOption.home : remote, isLocal: false); - await Future.delayed(Duration(seconds: 1)); - if (_currentLocalDir.path.isEmpty) { - openDirectory(_localOption.home, isLocal: true); - } - if (_currentRemoteDir.path.isEmpty) { - openDirectory(_remoteOption.home, isLocal: false); - } - } - - Future<void> onClose() async { - parent.target?.dialogManager.dismissAll(); - jobReset(); - - onDirChanged = null; - - // save config - Map<String, String> msgMap = {}; - - msgMap["local_dir"] = _currentLocalDir.path; - msgMap["local_show_hidden"] = _localOption.showHidden ? "Y" : ""; - msgMap["remote_dir"] = _currentRemoteDir.path; - msgMap["remote_show_hidden"] = _remoteOption.showHidden ? "Y" : ""; - final id = parent.target?.id ?? ""; - for (final msg in msgMap.entries) { - await bind.sessionPeerOption(id: id, name: msg.key, value: msg.value); - } - _currentLocalDir.clear(); - _currentRemoteDir.clear(); - _localOption.clear(); - _remoteOption.clear(); - } - - Future refresh({bool? isLocal}) async { - if (isDesktop) { - isLocal = isLocal ?? _isSelectedLocal; - isLocal - ? await openDirectory(currentLocalDir.path, isLocal: isLocal) - : await openDirectory(currentRemoteDir.path, isLocal: isLocal); - } else { - await openDirectory(currentDir.path); - } - } - - openDirectory(String path, {bool? isLocal, bool isBack = false}) async { - isLocal = isLocal ?? _isSelectedLocal; - if (path == ".") { - refresh(isLocal: isLocal); - return; - } - if (path == "..") { - goToParentDirectory(isLocal: isLocal); - return; - } - if (!isBack) { - pushHistory(isLocal); - } - final showHidden = getCurrentShowHidden(isLocal); - final isWindows = getCurrentIsWindows(isLocal); - // process /C:\ -> C:\ on Windows - if (isWindows && path.length > 1 && path[0] == '/') { - path = path.substring(1); - if (path[path.length - 1] != '\\') { - path = "$path\\"; - } - } - try { - final fd = await _fileFetcher.fetchDirectory(path, isLocal, showHidden); - fd.format(isWindows, sort: _sortStyle); - if (isLocal) { - _currentLocalDir = fd; - } else { - _currentRemoteDir = fd; - } - notifyListeners(); - onDirChanged?.call(isLocal); - } catch (e) { - debugPrint("Failed to openDirectory $path: $e"); - } - } - - Future<FileDirectory> fetchDirectory(path, isLocal, showHidden) async { - return await _fileFetcher.fetchDirectory(path, isLocal, showHidden); - } - - void pushHistory(bool isLocal) { - final history = isLocal ? localHistory : remoteHistory; - final currPath = isLocal ? currentLocalDir.path : currentRemoteDir.path; - if (history.isNotEmpty && history.last == currPath) { - return; - } - history.add(currPath); - } - - goHome({bool? isLocal}) { - isLocal = isLocal ?? _isSelectedLocal; - openDirectory(getCurrentHome(isLocal), isLocal: isLocal); - } - - goBack({bool? isLocal}) { - isLocal = isLocal ?? _isSelectedLocal; - final history = isLocal ? localHistory : remoteHistory; - if (history.isEmpty) return; - final path = history.removeAt(history.length - 1); - if (path.isEmpty) return; - final currPath = isLocal ? currentLocalDir.path : currentRemoteDir.path; - if (currPath == path) { - goBack(isLocal: isLocal); - return; - } - openDirectory(path, isLocal: isLocal, isBack: true); - } - - goToParentDirectory({bool? isLocal}) { - isLocal = isLocal ?? _isSelectedLocal; - final isWindows = - isLocal ? _localOption.isWindows : _remoteOption.isWindows; - final currDir = isLocal ? currentLocalDir : currentRemoteDir; - var parent = PathUtil.dirname(currDir.path, isWindows); - // specially for C:\, D:\, goto '/' - if (parent == currDir.path && isWindows) { - openDirectory('/', isLocal: isLocal); - return; - } - openDirectory(parent, isLocal: isLocal); - } - - /// isRemote only for desktop now, [isRemote == true] means [remote -> local] - sendFiles(SelectedItems items, {bool isRemote = false}) { - if (isDesktop) { - // desktop sendFiles - final toPath = isRemote ? currentLocalDir.path : currentRemoteDir.path; - final isWindows = - isRemote ? _localOption.isWindows : _remoteOption.isWindows; - final showHidden = - isRemote ? _localOption.showHidden : _remoteOption.showHidden; - for (var from in items.items) { - final jobId = ++_jobId; - _jobTable.add(JobProgress() - ..fileName = path.basename(from.path) - ..jobName = from.path - ..totalSize = from.size - ..state = JobState.inProgress - ..id = jobId - ..isRemote = isRemote); - bind.sessionSendFiles( - id: '${parent.target?.id}', - actId: _jobId, - path: from.path, - to: PathUtil.join(toPath, from.name, isWindows), - fileNum: 0, - includeHidden: showHidden, - isRemote: isRemote); - debugPrint( - "path:${from.path}, toPath:$toPath, to:${PathUtil.join(toPath, from.name, isWindows)}"); - } - } else { - if (items.isLocal == null) { - debugPrint("Failed to sendFiles ,wrong path state"); - return; - } - _jobProgress.state = JobState.inProgress; - final toPath = - items.isLocal! ? currentRemoteDir.path : currentLocalDir.path; - final isWindows = - items.isLocal! ? _localOption.isWindows : _remoteOption.isWindows; - final showHidden = - items.isLocal! ? _localOption.showHidden : _remoteOption.showHidden; - items.items.forEach((from) async { - _jobId++; - await bind.sessionSendFiles( - id: '${parent.target?.id}', - actId: _jobId, - path: from.path, - to: PathUtil.join(toPath, from.name, isWindows), - fileNum: 0, - includeHidden: showHidden, - isRemote: !(items.isLocal!)); - }); - } - } - - bool removeCheckboxRemember = false; - - removeAction(SelectedItems items, {bool? isLocal}) async { - isLocal = isLocal ?? _isSelectedLocal; - removeCheckboxRemember = false; - if (items.isLocal == null) { - debugPrint("Failed to removeFile, wrong path state"); - return; - } - final isWindows = - items.isLocal! ? _localOption.isWindows : _remoteOption.isWindows; - await Future.forEach(items.items, (Entry item) async { - _jobId++; - var title = ""; - var content = ""; - late final List<Entry> entries; - if (item.isFile) { - title = translate("Are you sure you want to delete this file?"); - content = item.name; - entries = [item]; - } else if (item.isDirectory) { - title = translate("Not an empty directory"); - parent.target?.dialogManager.showLoading(translate("Waiting")); - final fd = await _fileFetcher.fetchDirectoryRecursive( - _jobId, item.path, items.isLocal!, true); - if (fd.path.isEmpty) { - fd.path = item.path; - } - fd.format(isWindows); - parent.target?.dialogManager.dismissAll(); - if (fd.entries.isEmpty) { - final confirm = await showRemoveDialog( - translate( - "Are you sure you want to delete this empty directory?"), - item.name, - false); - if (confirm == true) { - sendRemoveEmptyDir(item.path, 0, items.isLocal!); - } - return; - } - entries = fd.entries; - } else { - entries = []; - } - - for (var i = 0; i < entries.length; i++) { - final dirShow = item.isDirectory - ? "${translate("Are you sure you want to delete the file of this directory?")}\n" - : ""; - final count = entries.length > 1 ? "${i + 1}/${entries.length}" : ""; - content = "$dirShow\n\n${entries[i].path}".trim(); - final confirm = await showRemoveDialog( - count.isEmpty ? title : "$title ($count)", - content, - item.isDirectory, - ); - try { - if (confirm == true) { - sendRemoveFile(entries[i].path, i, items.isLocal!); - final res = await _jobResultListener.start(); - // handle remove res; - if (item.isDirectory && - res['file_num'] == (entries.length - 1).toString()) { - sendRemoveEmptyDir(item.path, i, items.isLocal!); - } - } - if (removeCheckboxRemember) { - if (confirm == true) { - for (var j = i + 1; j < entries.length; j++) { - sendRemoveFile(entries[j].path, j, items.isLocal!); - final res = await _jobResultListener.start(); - if (item.isDirectory && - res['file_num'] == (entries.length - 1).toString()) { - sendRemoveEmptyDir(item.path, i, items.isLocal!); - } - } - } - break; - } - } catch (e) { - print("remove error: $e"); - } - } - }); - _selectMode = false; - refresh(isLocal: isLocal); - } - - Future<bool?> showRemoveDialog( - String title, String content, bool showCheckbox) async { - return await parent.target?.dialogManager.show<bool>( - (setState, Function(bool v) close) { - cancel() => close(false); - submit() => close(true); - return CustomAlertDialog( - title: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.warning_rounded, color: Colors.red), - Text(title).paddingOnly( - left: 10, - ), - ], - ), - contentBoxConstraints: - BoxConstraints(minHeight: 100, minWidth: 400, maxWidth: 400), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(content), - Text( - translate("This is irreversible!"), - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.red, - ), - ).paddingOnly(top: 20), - showCheckbox - ? CheckboxListTile( - contentPadding: const EdgeInsets.all(0), - dense: true, - controlAffinity: ListTileControlAffinity.leading, - title: Text( - translate("Do this for all conflicts"), - ), - value: removeCheckboxRemember, - onChanged: (v) { - if (v == null) return; - setState(() => removeCheckboxRemember = v); - }, - ) - : const SizedBox.shrink() - ], - ), - actions: [ - dialogButton( - "Cancel", - icon: Icon(Icons.close_rounded), - onPressed: cancel, - isOutline: true, - ), - dialogButton( - "OK", - icon: Icon(Icons.done_rounded), - onPressed: submit, - ), - ], - onSubmit: submit, - onCancel: cancel, - ); - }, useAnimation: false); - } - bool fileConfirmCheckboxRemember = false; Future<bool?> showFileConfirmDialog( @@ -765,65 +189,542 @@ class FileModel extends ChangeNotifier { ); }, useAnimation: false); } +} - sendRemoveFile(String path, int fileNum, bool isLocal) { +class DirectoryData { + final DirectoryOptions options; + final FileDirectory directory; + DirectoryData(this.directory, this.options); +} + +class FileController { + final bool isLocal; + final GetSessionID getSessionID; + String get sessionID => getSessionID(); + + final FileFetcher fileFetcher; + + final options = DirectoryOptions().obs; + final directory = FileDirectory().obs; + + final history = RxList<String>.empty(growable: true); + final sortBy = SortBy.name.obs; + var sortAscending = true; + final JobController jobController; + final OverlayDialogManager? dialogManager; + + final DirectoryData Function() getOtherSideDirectoryData; + late final SelectedItems selectedItems = SelectedItems(isLocal: isLocal); + + FileController( + {required this.isLocal, + required this.getSessionID, + required this.dialogManager, + required this.jobController, + required this.fileFetcher, + required this.getOtherSideDirectoryData}); + + String get homePath => options.value.home; + + String get shortPath { + final dirPath = directory.value.path; + if (dirPath.startsWith(homePath)) { + var path = dirPath.replaceFirst(homePath, ""); + if (path.isEmpty) return ""; + if (path[0] == "/" || path[0] == "\\") { + // remove more '/' or '\' + path = path.replaceFirst(path[0], ""); + } + return path; + } else { + return dirPath.replaceFirst(homePath, ""); + } + } + + DirectoryData directoryData() { + return DirectoryData(directory.value, options.value); + } + + Future<void> onReady() async { + options.value.home = await bind.mainGetHomeDir(); + options.value.showHidden = (await bind.sessionGetPeerOption( + id: sessionID, + name: isLocal ? "local_show_hidden" : "remote_show_hidden")) + .isNotEmpty; + options.value.isWindows = Platform.isWindows; + + await Future.delayed(Duration(milliseconds: 100)); + + final dir = (await bind.sessionGetPeerOption( + id: sessionID, name: isLocal ? "local_dir" : "remote_dir")); + openDirectory(dir.isEmpty ? options.value.home : dir); + + await Future.delayed(Duration(seconds: 1)); + + if (directory.value.path.isEmpty) { + openDirectory(options.value.home); + } + } + + Future<void> close() async { + // save config + Map<String, String> msgMap = {}; + msgMap[isLocal ? "local_dir" : "remote_dir"] = directory.value.path; + msgMap[isLocal ? "local_show_hidden" : "remote_show_hidden"] = + options.value.showHidden ? "Y" : ""; + for (final msg in msgMap.entries) { + await bind.sessionPeerOption( + id: sessionID, name: msg.key, value: msg.value); + } + directory.value.clear(); + options.value.clear(); + } + + void toggleShowHidden({bool? showHidden}) { + options.value.showHidden = showHidden ?? !options.value.showHidden; + refresh(); + } + + void changeSortStyle(SortBy sort, {bool? isLocal, bool ascending = true}) { + sortBy.value = sort; + sortAscending = ascending; + directory.update((dir) { + dir?.changeSortStyle(sort, ascending: ascending); + }); + } + + Future<void> refresh() async { + await openDirectory(directory.value.path); + } + + Future<void> openDirectory(String path, {bool isBack = false}) async { + if (path == ".") { + refresh(); + return; + } + if (path == "..") { + goToParentDirectory(); + return; + } + if (!isBack) { + pushHistory(); + } + final showHidden = options.value.showHidden; + final isWindows = options.value.isWindows; + // process /C:\ -> C:\ on Windows + if (isWindows && path.length > 1 && path[0] == '/') { + path = path.substring(1); + if (path[path.length - 1] != '\\') { + path = "$path\\"; + } + } + try { + final fd = await fileFetcher.fetchDirectory(path, isLocal, showHidden); + fd.format(isWindows, sort: sortBy.value); + directory.value = fd; + } catch (e) { + debugPrint("Failed to openDirectory $path: $e"); + } + } + + void pushHistory() { + if (history.isNotEmpty && history.last == directory.value.path) { + return; + } + history.add(directory.value.path); + } + + void goToHomeDirectory() { + openDirectory(homePath); + } + + void goBack() { + if (history.isEmpty) return; + final path = history.removeAt(history.length - 1); + if (path.isEmpty) return; + if (directory.value.path == path) { + goBack(); + return; + } + openDirectory(path, isBack: true); + } + + void goToParentDirectory() { + final isWindows = options.value.isWindows; + final dirPath = directory.value.path; + var parent = PathUtil.dirname(dirPath, isWindows); + // specially for C:\, D:\, goto '/' + if (parent == dirPath && isWindows) { + openDirectory('/'); + return; + } + openDirectory(parent); + } + + // TODO deprecated this + void initDirAndHome(Map<String, dynamic> evt) { + try { + final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); + fd.format(options.value.isWindows, sort: sortBy.value); + if (fd.id > 0) { + final jobIndex = jobController.getJob(fd.id); + if (jobIndex != -1) { + final job = jobController.jobTable[jobIndex]; + var totalSize = 0; + var fileCount = fd.entries.length; + for (var element in fd.entries) { + totalSize += element.size; + } + job.totalSize = totalSize; + job.fileCount = fileCount; + debugPrint("update receive details:${fd.path}"); + jobController.jobTable.refresh(); + } + } else if (options.value.home.isEmpty) { + options.value.home = fd.path; + debugPrint("init remote home:${fd.path}"); + directory.value = fd; + } + } catch (e) { + debugPrint("initDirAndHome err=$e"); + } + } + + /// sendFiles from current side (FileController.isLocal) to other side (SelectedItems). + void sendFiles(SelectedItems items, DirectoryData otherSideData) { + /// ignore wrong items side status + if (items.isLocal != isLocal) { + return; + } + + // alias + final isRemoteToLocal = !isLocal; + + final toPath = otherSideData.directory.path; + final isWindows = otherSideData.options.isWindows; + final showHidden = otherSideData.options.showHidden; + for (var from in items.items) { + final jobID = jobController.add(from, isRemoteToLocal); + bind.sessionSendFiles( + id: sessionID, + actId: jobID, + path: from.path, + to: PathUtil.join(toPath, from.name, isWindows), + fileNum: 0, + includeHidden: showHidden, + isRemote: isRemoteToLocal); + debugPrint( + "path:${from.path}, toPath:$toPath, to:${PathUtil.join(toPath, from.name, isWindows)}"); + } + } + + bool _removeCheckboxRemember = false; + + Future<void> removeAction(SelectedItems items) async { + _removeCheckboxRemember = false; + if (items.isLocal != isLocal) { + debugPrint("Failed to removeFile, wrong files"); + return; + } + final isWindows = options.value.isWindows; + await Future.forEach(items.items, (Entry item) async { + final jobID = JobController.jobID.next(); + var title = ""; + var content = ""; + late final List<Entry> entries; + if (item.isFile) { + title = translate("Are you sure you want to delete this file?"); + content = item.name; + entries = [item]; + } else if (item.isDirectory) { + title = translate("Not an empty directory"); + dialogManager?.showLoading(translate("Waiting")); + final fd = await fileFetcher.fetchDirectoryRecursive( + jobID, item.path, items.isLocal!, true); + if (fd.path.isEmpty) { + fd.path = item.path; + } + fd.format(isWindows); + dialogManager?.dismissAll(); + if (fd.entries.isEmpty) { + final confirm = await showRemoveDialog( + translate( + "Are you sure you want to delete this empty directory?"), + item.name, + false); + if (confirm == true) { + sendRemoveEmptyDir(item.path, 0); + } + return; + } + entries = fd.entries; + } else { + entries = []; + } + + for (var i = 0; i < entries.length; i++) { + final dirShow = item.isDirectory + ? "${translate("Are you sure you want to delete the file of this directory?")}\n" + : ""; + final count = entries.length > 1 ? "${i + 1}/${entries.length}" : ""; + content = "$dirShow\n\n${entries[i].path}".trim(); + final confirm = await showRemoveDialog( + count.isEmpty ? title : "$title ($count)", + content, + item.isDirectory, + ); + try { + if (confirm == true) { + sendRemoveFile(entries[i].path, i); + final res = await jobController.jobResultListener.start(); + // handle remove res; + if (item.isDirectory && + res['file_num'] == (entries.length - 1).toString()) { + sendRemoveEmptyDir(item.path, i); + } + } + if (_removeCheckboxRemember) { + if (confirm == true) { + for (var j = i + 1; j < entries.length; j++) { + sendRemoveFile(entries[j].path, j); + final res = await jobController.jobResultListener.start(); + if (item.isDirectory && + res['file_num'] == (entries.length - 1).toString()) { + sendRemoveEmptyDir(item.path, i); + } + } + } + break; + } + } catch (e) { + print("remove error: $e"); + } + } + }); + refresh(); + } + + Future<bool?> showRemoveDialog( + String title, String content, bool showCheckbox) async { + return await dialogManager?.show<bool>((setState, Function(bool v) close) { + cancel() => close(false); + submit() => close(true); + return CustomAlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.warning_rounded, color: Colors.red), + Text(title).paddingOnly( + left: 10, + ), + ], + ), + contentBoxConstraints: + BoxConstraints(minHeight: 100, minWidth: 400, maxWidth: 400), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(content), + Text( + translate("This is irreversible!"), + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.red, + ), + ).paddingOnly(top: 20), + showCheckbox + ? CheckboxListTile( + contentPadding: const EdgeInsets.all(0), + dense: true, + controlAffinity: ListTileControlAffinity.leading, + title: Text( + translate("Do this for all conflicts"), + ), + value: _removeCheckboxRemember, + onChanged: (v) { + if (v == null) return; + setState(() => _removeCheckboxRemember = v); + }, + ) + : const SizedBox.shrink() + ], + ), + actions: [ + dialogButton( + "Cancel", + icon: Icon(Icons.close_rounded), + onPressed: cancel, + isOutline: true, + ), + dialogButton( + "OK", + icon: Icon(Icons.done_rounded), + onPressed: submit, + ), + ], + onSubmit: submit, + onCancel: cancel, + ); + }, useAnimation: false); + } + + void sendRemoveFile(String path, int fileNum) { bind.sessionRemoveFile( - id: '${parent.target?.id}', - actId: _jobId, + id: sessionID, + actId: JobController.jobID.next(), path: path, isRemote: !isLocal, fileNum: fileNum); } - sendRemoveEmptyDir(String path, int fileNum, bool isLocal) { - final history = isLocal ? localHistory : remoteHistory; + void sendRemoveEmptyDir(String path, int fileNum) { history.removeWhere((element) => element.contains(path)); bind.sessionRemoveAllEmptyDirs( - id: '${parent.target?.id}', - actId: _jobId, + id: sessionID, + actId: JobController.jobID.next(), path: path, isRemote: !isLocal); } - createDir(String path, {bool? isLocal}) async { - isLocal = isLocal ?? this.isLocal; - _jobId++; + Future<void> createDir(String path) async { bind.sessionCreateDir( - id: '${parent.target?.id}', - actId: _jobId, + id: sessionID, + actId: JobController.jobID.next(), path: path, isRemote: !isLocal); } +} - cancelJob(int id) async { - bind.sessionCancelJob(id: '${parent.target?.id}', actId: id); - jobReset(); +class JobController { + static final JobID jobID = JobID(); + final jobTable = List<JobProgress>.empty(growable: true).obs; + final jobResultListener = JobResultListener<Map<String, dynamic>>(); + final GetSessionID getSessionID; + String get sessionID => getSessionID(); + + JobController(this.getSessionID); + + int getJob(int id) { + return jobTable.indexWhere((element) => element.id == id); } - changeSortStyle(SortBy sort, {bool? isLocal, bool ascending = true}) { - _sortStyle = sort; - if (isLocal == null) { - // compatible for mobile logic - _currentLocalDir.changeSortStyle(sort, ascending: ascending); - _currentRemoteDir.changeSortStyle(sort, ascending: ascending); - _localSortStyle = sort; - _localSortAscending = ascending; - _remoteSortStyle = sort; - _remoteSortAscending = ascending; - } else if (isLocal) { - _currentLocalDir.changeSortStyle(sort, ascending: ascending); - _localSortStyle = sort; - _localSortAscending = ascending; - } else { - _currentRemoteDir.changeSortStyle(sort, ascending: ascending); - _remoteSortStyle = sort; - _remoteSortAscending = ascending; + // JobProgress? getJob(int id) { + // return jobTable.firstWhere((element) => element.id == id); + // } + + // return jobID + int add(Entry from, bool isRemoteToLocal) { + final jobID = JobController.jobID.next(); + jobTable.add(JobProgress() + ..fileName = path.basename(from.path) + ..jobName = from.path + ..totalSize = from.size + ..state = JobState.inProgress + ..id = jobID + ..isRemoteToLocal = isRemoteToLocal); + return jobID; + } + + void tryUpdateJobProgress(Map<String, dynamic> evt) { + try { + int id = int.parse(evt['id']); + // id = index + 1 + final jobIndex = getJob(id); + if (jobIndex >= 0 && jobTable.length > jobIndex) { + final job = jobTable[jobIndex]; + job.fileNum = int.parse(evt['file_num']); + job.speed = double.parse(evt['speed']); + job.finishedSize = int.parse(evt['finished_size']); + debugPrint("update job $id with $evt"); + jobTable.refresh(); + } + } catch (e) { + debugPrint("Failed to tryUpdateJobProgress,evt:${evt.toString()}"); } - notifyListeners(); } - initFileFetcher() { - _fileFetcher.id = parent.target?.id; + void jobDone(Map<String, dynamic> evt) async { + if (jobResultListener.isListening) { + jobResultListener.complete(evt); + return; + } + + int id = int.parse(evt['id']); + final jobIndex = getJob(id); + if (jobIndex != -1) { + final job = jobTable[jobIndex]; + job.finishedSize = job.totalSize; + job.state = JobState.done; + job.fileNum = int.parse(evt['file_num']); + jobTable.refresh(); + } + } + + void jobError(Map<String, dynamic> evt) { + final err = evt['err'].toString(); + int jobIndex = getJob(int.parse(evt['id'])); + if (jobIndex != -1) { + final job = jobTable[jobIndex]; + job.state = JobState.error; + job.err = err; + job.fileNum = int.parse(evt['file_num']); + if (err == "skipped") { + job.state = JobState.done; + job.finishedSize = job.totalSize; + } + jobTable.refresh(); + } + debugPrint("jobError $evt"); + } + + void cancelJob(int id) async { + bind.sessionCancelJob(id: sessionID, actId: id); + } + + void loadLastJob(Map<String, dynamic> evt) { + debugPrint("load last job: $evt"); + Map<String, dynamic> jobDetail = json.decode(evt['value']); + // int id = int.parse(jobDetail['id']); + String remote = jobDetail['remote']; + String to = jobDetail['to']; + bool showHidden = jobDetail['show_hidden']; + int fileNum = jobDetail['file_num']; + bool isRemote = jobDetail['is_remote']; + final currJobId = JobController.jobID.next(); + String fileName = path.basename(isRemote ? remote : to); + var jobProgress = JobProgress() + ..fileName = fileName + ..jobName = isRemote ? remote : to + ..id = currJobId + ..isRemoteToLocal = isRemote + ..fileNum = fileNum + ..remote = remote + ..to = to + ..showHidden = showHidden + ..state = JobState.paused; + jobTable.add(jobProgress); + bind.sessionAddJob( + id: sessionID, + isRemote: isRemote, + includeHidden: showHidden, + actId: currJobId, + path: isRemote ? remote : to, + to: isRemote ? to : remote, + fileNum: fileNum, + ); + } + + void resumeJob(int jobId) { + final jobIndex = getJob(jobId); + if (jobIndex != -1) { + final job = jobTable[jobIndex]; + bind.sessionResumeJob( + id: sessionID, actId: job.id, isRemote: job.isRemoteToLocal); + job.state = JobState.inProgress; + jobTable.refresh(); + } else { + debugPrint("jobId $jobId is not exists"); + } } void updateFolderFiles(Map<String, dynamic> evt) { @@ -837,57 +738,9 @@ class FileModel extends ChangeNotifier { final job = jobTable[jobIndex]; job.fileCount = num_entries; job.totalSize = total_size.toInt(); + jobTable.refresh(); } debugPrint("update folder files: $info"); - notifyListeners(); - } - - bool get remoteSortAscending => _remoteSortAscending; - - void loadLastJob(Map<String, dynamic> evt) { - debugPrint("load last job: $evt"); - Map<String, dynamic> jobDetail = json.decode(evt['value']); - // int id = int.parse(jobDetail['id']); - String remote = jobDetail['remote']; - String to = jobDetail['to']; - bool showHidden = jobDetail['show_hidden']; - int fileNum = jobDetail['file_num']; - bool isRemote = jobDetail['is_remote']; - final currJobId = _jobId++; - String fileName = path.basename(isRemote ? remote : to); - var jobProgress = JobProgress() - ..fileName = fileName - ..jobName = isRemote ? remote : to - ..id = currJobId - ..isRemote = isRemote - ..fileNum = fileNum - ..remote = remote - ..to = to - ..showHidden = showHidden - ..state = JobState.paused; - jobTable.add(jobProgress); - bind.sessionAddJob( - id: '${parent.target?.id}', - isRemote: isRemote, - includeHidden: showHidden, - actId: currJobId, - path: isRemote ? remote : to, - to: isRemote ? to : remote, - fileNum: fileNum, - ); - } - - resumeJob(int jobId) { - final jobIndex = getJob(jobId); - if (jobIndex != -1) { - final job = jobTable[jobIndex]; - bind.sessionResumeJob( - id: '${parent.target?.id}', actId: job.id, isRemote: job.isRemote); - job.state = JobState.inProgress; - } else { - debugPrint("jobId $jobId is not exists"); - } - notifyListeners(); } } @@ -936,10 +789,10 @@ class FileFetcher { Map<String, Completer<FileDirectory>> remoteTasks = {}; Map<int, Completer<FileDirectory>> readRecursiveTasks = {}; - String? id; + final GetSessionID getSessionID; + String get sessionID => getSessionID(); - // if id == null, means to fetch global FFI - FFI get _ffi => ffi(id ?? ""); + FileFetcher(this.getSessionID); Future<FileDirectory> registerReadTask(bool isLocal, String path) { // final jobs = isLocal?localJobs:remoteJobs; // maybe we will use read local dir async later @@ -958,16 +811,16 @@ class FileFetcher { return c.future; } - Future<FileDirectory> registerReadRecursiveTask(int id) { + Future<FileDirectory> registerReadRecursiveTask(int actID) { final tasks = readRecursiveTasks; - if (tasks.containsKey(id)) { + if (tasks.containsKey(actID)) { throw "Failed to registerRemoveTask, already have same ReadRecursive job"; } final c = Completer<FileDirectory>(); - tasks[id] = c; + tasks[actID] = c; Timer(Duration(seconds: 2), () { - tasks.remove(id); + tasks.remove(actID); if (c.isCompleted) return; c.completeError("Failed to read dir,timeout"); }); @@ -1002,12 +855,12 @@ class FileFetcher { try { if (isLocal) { final res = await bind.sessionReadLocalDirSync( - id: id ?? "", path: path, showHidden: showHidden); + id: sessionID ?? "", path: path, showHidden: showHidden); final fd = FileDirectory.fromJson(jsonDecode(res)); return fd; } else { await bind.sessionReadRemoteDir( - id: id ?? "", path: path, includeHidden: showHidden); + id: sessionID ?? "", path: path, includeHidden: showHidden); return registerReadTask(isLocal, path); } } catch (e) { @@ -1016,16 +869,16 @@ class FileFetcher { } Future<FileDirectory> fetchDirectoryRecursive( - int id, String path, bool isLocal, bool showHidden) async { + int actID, String path, bool isLocal, bool showHidden) async { // TODO test Recursive is show hidden default? try { await bind.sessionReadDirRecursive( - id: _ffi.id, - actId: id, + id: sessionID, + actId: actID, path: path, isRemote: !isLocal, showHidden: showHidden); - return registerReadRecursiveTask(id); + return registerReadRecursiveTask(actID); } catch (e) { return Future.error(e); } @@ -1122,7 +975,10 @@ class JobProgress { var finishedSize = 0; var totalSize = 0; var fileCount = 0; - var isRemote = false; + // [isRemote == true] means [remote -> local] + // var isRemote = false; + // to-do use enum + var isRemoteToLocal = false; var jobName = ""; var fileName = ""; var remote = ""; @@ -1179,12 +1035,12 @@ class PathUtil { } } -class DirectoryOption { +class DirectoryOptions { String home; bool showHidden; bool isWindows; - DirectoryOption( + DirectoryOptions( {this.home = "", this.showHidden = false, this.isWindows = false}); clear() { @@ -1195,53 +1051,37 @@ class DirectoryOption { } class SelectedItems { - bool? _isLocal; - final List<Entry> _items = []; + final bool isLocal; + final items = RxList<Entry>.empty(growable: true); - List<Entry> get items => _items; + SelectedItems({required this.isLocal}); - int get length => _items.length; - - bool? get isLocal => _isLocal; - - add(bool isLocal, Entry e) { + void add(Entry e) { if (e.isDrive) return; - _isLocal ??= isLocal; - if (_isLocal != null && _isLocal != isLocal) { - return; - } - if (!_items.contains(e)) { - _items.add(e); + if (!items.contains(e)) { + items.add(e); } } - bool contains(Entry e) { - return _items.contains(e); + void remove(Entry e) { + items.remove(e); } - remove(Entry e) { - _items.remove(e); - if (_items.isEmpty) { - _isLocal = null; - } - } - - bool isOtherPage(bool currentIsLocal) { - if (_isLocal == null) { - return false; - } else { - return _isLocal != currentIsLocal; - } - } - - clear() { - _items.clear(); - _isLocal = null; + void clear() { + items.clear(); } void selectAll(List<Entry> entries) { - _items.clear(); - _items.addAll(entries); + items.clear(); + items.addAll(entries); + } + + static bool valid(RxList<Entry> items) { + if (items.isNotEmpty) { + // exclude DirDrive type + return items.any((item) => !item.isDrive); + } + return false; } } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 802a18a52..94e28ea21 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -166,17 +166,18 @@ class FfiModel with ChangeNotifier { } else if (name == 'file_dir') { parent.target?.fileModel.receiveFileDir(evt); } else if (name == 'job_progress') { - parent.target?.fileModel.tryUpdateJobProgress(evt); + parent.target?.fileModel.jobController.tryUpdateJobProgress(evt); } else if (name == 'job_done') { - parent.target?.fileModel.jobDone(evt); + parent.target?.fileModel.jobController.jobDone(evt); + parent.target?.fileModel.refreshAll(); } else if (name == 'job_error') { - parent.target?.fileModel.jobError(evt); + parent.target?.fileModel.jobController.jobError(evt); } else if (name == 'override_file_confirm') { parent.target?.fileModel.overrideFileConfirm(evt); } else if (name == 'load_last_job') { - parent.target?.fileModel.loadLastJob(evt); + parent.target?.fileModel.jobController.loadLastJob(evt); } else if (name == 'update_folder_files') { - parent.target?.fileModel.updateFolderFiles(evt); + parent.target?.fileModel.jobController.updateFolderFiles(evt); } else if (name == 'add_connection') { parent.target?.serverModel.addConnection(evt); } else if (name == 'on_client_remove') { @@ -371,7 +372,11 @@ class FfiModel with ChangeNotifier { _updateSessionWidthHeight(String id) { parent.target?.canvasModel.updateViewStyle(); - bind.sessionSetSize(id: id, width: display.width, height: display.height); + if (display.width <= 0 || display.height <= 0) { + debugPrintStack(label: 'invalid display size (${display.width},${display.height})'); + } else { + bind.sessionSetSize(id: id, width: display.width, height: display.height); + } } /// Handle the peer info event based on [evt]. @@ -1571,9 +1576,6 @@ class FFI { }(); // every instance will bind a stream this.id = id; - if (isFileTransfer) { - fileModel.initFileFetcher(); - } } /// Login with [password], choose if the client should [remember] it. diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index aa4fab86e..187b1ffc5 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -28,10 +28,9 @@ class StateGlobal { setWindowId(int id) => _windowId = id; setMaximize(bool v) { - if (_maximize != v) { + if (_maximize != v && !_fullscreen) { _maximize = v; - _resizeEdgeSize.value = - _maximize ? kMaximizeEdgeSize : kWindowEdgeSize; + _resizeEdgeSize.value = _maximize ? kMaximizeEdgeSize : kWindowEdgeSize; } } setFullscreen(bool v) { @@ -39,7 +38,13 @@ class StateGlobal { _fullscreen = v; _showTabBar.value = !_fullscreen; _resizeEdgeSize.value = - fullscreen ? kFullScreenEdgeSize : kWindowEdgeSize; + fullscreen + ? kFullScreenEdgeSize + : _maximize + ? kMaximizeEdgeSize + : kWindowEdgeSize; + print( + "fullscreen: ${fullscreen}, resizeEdgeSize: ${_resizeEdgeSize.value}"); _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; WindowController.fromWindowId(windowId) .setFullscreen(_fullscreen) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index a212a5093..46278bf0d 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: 3e2655677c54f421f9e378680d8171b95a211e0f + ref: e3947d4b4f8edaa655de63cd47f2a59a6e024218 freezed_annotation: ^2.0.3 flutter_custom_cursor: ^0.0.4 window_size: diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index c77f11eb5..fd02639ed 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -7,17 +7,17 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] } +flexi_logger = { version = "0.25", features = ["async"] } protobuf = { version = "3.1", features = ["with-bytes"] } tokio = { version = "1.20", features = ["full"] } tokio-util = { version = "0.7", features = ["full"] } futures = "0.3" bytes = { version = "1.2", features = ["serde"] } log = "0.4" -env_logger = "0.9" +env_logger = "0.10" socket2 = { version = "0.3", features = ["reuseport"] } zstd = "0.9" -quinn = {version = "0.8", optional = true } +quinn = {version = "0.9", optional = true } anyhow = "1.0" futures-util = "0.3" directories-next = "2.0" @@ -34,7 +34,7 @@ tokio-socks = { git = "https://github.com/open-trade/tokio-socks" } chrono = "0.4" backtrace = "0.3" libc = "0.2" -sysinfo = "0.24" +sysinfo = "0.26" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] mac_address = "1.1" @@ -54,5 +54,5 @@ winapi = { version = "0.3", features = ["winuser"] } osascript = "0.3.0" [dev-dependencies] -toml = "0.5" -serde_json = "1.0" +toml = "0.7" +serde_json = "1.0" \ No newline at end of file diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index ed7270a85..4ce2cf07e 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -4,7 +4,7 @@ use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::{Path, PathBuf}, sync::{Arc, Mutex, RwLock}, - time::SystemTime, + time::{Duration, Instant, SystemTime}, }; use anyhow::Result; @@ -51,6 +51,7 @@ lazy_static::lazy_static! { pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned())); static ref KEY_PAIR: Arc<Mutex<Option<KeyPair>>> = Default::default(); static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load())); + static ref USER_DEFAULT_CONFIG: Arc<RwLock<(UserDefaultConfig, Instant)>> = Arc::new(RwLock::new((UserDefaultConfig::load(), Instant::now()))); } lazy_static::lazy_static! { @@ -123,7 +124,7 @@ macro_rules! serde_field_bool { } impl $struct_name { pub fn $func() -> bool { - UserDefaultConfig::load().get($field_name) == "Y" + UserDefaultConfig::read().get($field_name) == "Y" } } }; @@ -980,21 +981,21 @@ impl PeerConfig { serde_field_string!( default_view_style, deserialize_view_style, - UserDefaultConfig::load().get("view_style") + UserDefaultConfig::read().get("view_style") ); serde_field_string!( default_scroll_style, deserialize_scroll_style, - UserDefaultConfig::load().get("scroll_style") + UserDefaultConfig::read().get("scroll_style") ); serde_field_string!( default_image_quality, deserialize_image_quality, - UserDefaultConfig::load().get("image_quality") + UserDefaultConfig::read().get("image_quality") ); fn default_custom_image_quality() -> Vec<i32> { - let f: f64 = UserDefaultConfig::load() + let f: f64 = UserDefaultConfig::read() .get("custom_image_quality") .parse() .unwrap_or(50.0); @@ -1020,15 +1021,15 @@ impl PeerConfig { let mut mp: HashMap<String, String> = de::Deserialize::deserialize(deserializer)?; let mut key = "codec-preference"; if !mp.contains_key(key) { - mp.insert(key.to_owned(), UserDefaultConfig::load().get(key)); + mp.insert(key.to_owned(), UserDefaultConfig::read().get(key)); } key = "custom-fps"; if !mp.contains_key(key) { - mp.insert(key.to_owned(), UserDefaultConfig::load().get(key)); + mp.insert(key.to_owned(), UserDefaultConfig::read().get(key)); } key = "zoom-cursor"; if !mp.contains_key(key) { - mp.insert(key.to_owned(), UserDefaultConfig::load().get(key)); + mp.insert(key.to_owned(), UserDefaultConfig::read().get(key)); } Ok(mp) } @@ -1046,7 +1047,12 @@ serde_field_bool!( default_show_quality_monitor, "ShowQualityMonitor::default_show_quality_monitor" ); -serde_field_bool!(DisableAudio, "disable_audio", default_disable_audio, "DisableAudio::default_disable_audio"); +serde_field_bool!( + DisableAudio, + "disable_audio", + default_disable_audio, + "DisableAudio::default_disable_audio" +); serde_field_bool!( EnableFileTransfer, "enable_file_transfer", @@ -1065,9 +1071,19 @@ serde_field_bool!( default_lock_after_session_end, "LockAfterSessionEnd::default_lock_after_session_end" ); -serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode, "PrivacyMode::default_privacy_mode"); +serde_field_bool!( + PrivacyMode, + "privacy_mode", + default_privacy_mode, + "PrivacyMode::default_privacy_mode" +); -serde_field_bool!(AllowSwapKey, "allow_swap_key", default_allow_swap_key, "AllowSwapKey::default_allow_swap_key"); +serde_field_bool!( + AllowSwapKey, + "allow_swap_key", + default_allow_swap_key, + "AllowSwapKey::default_allow_swap_key" +); #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct LocalConfig { @@ -1282,6 +1298,14 @@ pub struct UserDefaultConfig { } impl UserDefaultConfig { + pub fn read() -> UserDefaultConfig { + let mut cfg = USER_DEFAULT_CONFIG.write().unwrap(); + if cfg.1.elapsed() > Duration::from_secs(1) { + *cfg = (Self::load(), Instant::now()); + } + cfg.0.clone() + } + pub fn load() -> UserDefaultConfig { Config::load_::<UserDefaultConfig>("_default") } diff --git a/libs/scrap/Cargo.toml b/libs/scrap/Cargo.toml index 82cb88faf..99e15aeef 100644 --- a/libs/scrap/Cargo.toml +++ b/libs/scrap/Cargo.toml @@ -42,7 +42,7 @@ quest = "0.3" [build-dependencies] target_build_utils = "0.3" -bindgen = "0.59" +bindgen = "0.64" [target.'cfg(target_os = "linux")'.dependencies] dbus = { version = "0.9", optional = true } diff --git a/libs/scrap/src/common/quartz.rs b/libs/scrap/src/common/quartz.rs index a02d55ebb..dc59edac1 100644 --- a/libs/scrap/src/common/quartz.rs +++ b/libs/scrap/src/common/quartz.rs @@ -83,7 +83,7 @@ impl crate::TraitCapturer for Capturer { } } -pub struct Frame<'a>(quartz::Frame, PhantomData<&'a [u8]>); +pub struct Frame<'a>(pub quartz::Frame, PhantomData<&'a [u8]>); impl<'a> ops::Deref for Frame<'a> { type Target = [u8]; diff --git a/src/client.rs b/src/client.rs index ab27c0185..705b387a8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -708,6 +708,7 @@ pub struct AudioHandler { audio_stream: Option<Box<dyn StreamTrait>>, channels: u16, latency_controller: Arc<Mutex<LatencyController>>, + ignore_count: i32, } impl AudioHandler { @@ -810,7 +811,11 @@ impl AudioHandler { .check_audio(frame.timestamp) .not() { - log::debug!("audio frame {} is ignored", frame.timestamp); + self.ignore_count += 1; + if self.ignore_count == 100 { + self.ignore_count = 0; + log::debug!("100 audio frames are ignored"); + } return; } } @@ -2233,7 +2238,7 @@ fn get_pk(pk: &[u8]) -> Option<[u8; 32]> { #[inline] fn get_rs_pk(str_base64: &str) -> Option<sign::PublicKey> { - if let Ok(pk) = base64::decode(str_base64) { + if let Ok(pk) = crate::decode64(str_base64) { get_pk(&pk).map(|x| sign::PublicKey(x)) } else { None diff --git a/src/common.rs b/src/common.rs index 28d8dddc4..0b475805d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -787,3 +787,15 @@ pub fn handle_url_scheme(url: String) { let _ = crate::run_me(vec![url]); } } + +#[inline] +pub fn encode64<T: AsRef<[u8]>>(input: T) -> String { + #[allow(deprecated)] + base64::encode(input) +} + +#[inline] +pub fn decode64<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, base64::DecodeError> { + #[allow(deprecated)] + base64::decode(input) +} diff --git a/src/lang/el.rs b/src/lang/el.rs index 052ce1cfd..6599e7a59 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -461,9 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Resolution", "Ανάλυση"), ("No transfers in progress", "Δεν υπάρχει μεταφορά σε εξέλιξη"), ("Set one-time password length", "Μέγεθος κωδικού μιας χρήσης"), - ("idd_driver_tip", ""), - ("confirm_idd_driver_tip", ""), - ("RDP Settings", ""), + ("idd_driver_tip", "Εγκαταστήστε το πρόγραμμα οδήγησης εικονικής οθόνης που χρησιμοποιείται όταν δεν έχετε φυσικές οθόνες."), + ("confirm_idd_driver_tip", "Είναι ενεργοποιημένη η επιλογή εγκατάστασης του προγράμματος οδήγησης εικονικής οθόνης. Λάβετε υπόψη ότι θα εγκατασταθεί ένα δοκιμαστικό πιστοποιητικό για το πρόγραμμα οδήγησης εικονικής οθόνης. Αυτό το πιστοποιητικό θα χρησιμοποιηθεί μόνο για την πιστοποίηση των προγραμμάτων οδήγησης του Rustdesk."), + ("RDP Settings", "Ρυθμίσεις RDP"), ("Sort by", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index b644add49..85239cdd1 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -461,9 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Resolution", "Resolución"), ("No transfers in progress", "No hay transferencias en curso"), ("Set one-time password length", "Establecer contraseña de un solo uso"), - ("idd_driver_tip", ""), - ("confirm_idd_driver_tip", ""), - ("RDP Settings", ""), + ("idd_driver_tip", "Instalar controlador virtual de pantalla a usar cuando no hay pantalla física."), + ("confirm_idd_driver_tip", "La opción de instalar el controlador de pantalla virtual está marcada. Hay que tener en cuenta que se instalará un certificado de prueba para confirar en el controlador de pantalla. Este certificado solo se usará para confiar en controladores Rustdesk."), + ("RDP Settings", "Ajustes RDP"), ("Sort by", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index ca4ac9e63..dc714ec72 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -461,9 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Resolution", "Разрешение"), ("No transfers in progress", "Передача не осуществляется"), ("Set one-time password length", "Установить длину одноразового пароля"), - ("idd_driver_tip", ""), - ("confirm_idd_driver_tip", ""), - ("RDP Settings", ""), + ("idd_driver_tip", "Установите драйвер виртуального дисплея, который используется при отсутствии физических дисплеев."), + ("confirm_idd_driver_tip", "Включена функция установки драйвера виртуального дисплея. Обратите внимание, что для доверия к драйверу будет установлен тестовый сертификат. Этот сертификат будет использоваться только для подтверждения доверия драйверам Rustdesk."), + ("RDP Settings", "Настройки RDP"), ("Sort by", ""), ].iter().cloned().collect(); } diff --git a/src/license.rs b/src/license.rs index f8f5d27d5..8875d2b64 100644 --- a/src/license.rs +++ b/src/license.rs @@ -1,3 +1,4 @@ +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _}; use hbb_common::{bail, sodiumoxide::crypto::sign, ResultType}; use serde_derive::{Deserialize, Serialize}; @@ -18,7 +19,7 @@ fn get_license_from_string_(s: &str) -> ResultType<License> { 12, 46, 129, 83, 17, 84, 193, 119, 197, 130, 103, ]; let pk = sign::PublicKey(*PK); - let data = base64::decode_config(tmp, base64::URL_SAFE_NO_PAD)?; + let data = URL_SAFE_NO_PAD.decode(tmp)?; if let Ok(lic) = serde_json::from_slice::<License>(&data) { return Ok(lic); } diff --git a/src/naming.rs b/src/naming.rs index 38b514f86..53e675d92 100644 --- a/src/naming.rs +++ b/src/naming.rs @@ -1,10 +1,11 @@ mod license; +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _}; use hbb_common::ResultType; use license::*; fn gen_name(lic: &License) -> ResultType<String> { let tmp = serde_json::to_vec::<License>(lic)?; - let tmp = base64::encode_config(tmp, base64::URL_SAFE_NO_PAD); + let tmp = URL_SAFE_NO_PAD.encode(&tmp); let tmp: String = tmp.chars().rev().collect(); Ok(tmp) } diff --git a/src/platform/macos.mm b/src/platform/macos.mm index 3c90981c4..a252a9a8f 100644 --- a/src/platform/macos.mm +++ b/src/platform/macos.mm @@ -8,6 +8,9 @@ // https://github.com/codebytere/node-mac-permissions/blob/main/permissions.mm extern "C" bool InputMonitoringAuthStatus(bool prompt) { + #ifdef NO_InputMonitoringAuthStatus + return true; + #else if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_15) { IOHIDAccessType theType = IOHIDCheckAccess(kIOHIDRequestTypeListenEvent); NSLog(@"IOHIDCheckAccess = %d, kIOHIDAccessTypeGranted = %d", theType, kIOHIDAccessTypeGranted); @@ -36,6 +39,7 @@ extern "C" bool InputMonitoringAuthStatus(bool prompt) { return true; } return false; + #endif } extern "C" bool MacCheckAdminAuthorization() { diff --git a/src/server/connection.rs b/src/server/connection.rs index 898939b62..3d419ef08 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -735,7 +735,7 @@ impl Connection { let url = self.server_audit_conn.clone(); let mut v = v; v["id"] = json!(Config::get_id()); - v["uuid"] = json!(base64::encode(hbb_common::get_uuid())); + v["uuid"] = json!(crate::encode64(hbb_common::get_uuid())); v["conn_id"] = json!(self.inner.id); tokio::spawn(async move { allow_err!(Self::post_audit_async(url, v).await); @@ -765,7 +765,7 @@ impl Connection { info["files"] = json!(files); let v = json!({ "id":json!(Config::get_id()), - "uuid":json!(base64::encode(hbb_common::get_uuid())), + "uuid":json!(crate::encode64(hbb_common::get_uuid())), "peer_id":json!(self.lr.my_id), "type": r#type as i8, "path":path, @@ -788,7 +788,7 @@ impl Connection { } let mut v = Value::default(); v["id"] = json!(Config::get_id()); - v["uuid"] = json!(base64::encode(hbb_common::get_uuid())); + v["uuid"] = json!(crate::encode64(hbb_common::get_uuid())); v["typ"] = json!(typ as i8); v["from_remote"] = json!(from_remote); v["info"] = serde_json::Value::String(info.to_string()); diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index f5c575d43..bd6eab3bf 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -848,7 +848,7 @@ pub fn elevate_portable(_id: i32) { #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn handle_incoming_voice_call(id: i32, accept: bool) { - if let Some(client) = CLIENTS.write().unwrap().get_mut(&id) { + if let Some(client) = CLIENTS.read().unwrap().get(&id) { allow_err!(client.tx.send(Data::VoiceCallResponse(accept))); }; } @@ -856,7 +856,7 @@ pub fn handle_incoming_voice_call(id: i32, accept: bool) { #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] #[inline] pub fn close_voice_call(id: i32) { - if let Some(client) = CLIENTS.write().unwrap().get_mut(&id) { + if let Some(client) = CLIENTS.read().unwrap().get(&id) { allow_err!(client.tx.send(Data::CloseVoiceCall("".to_owned()))); }; } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index ec570b42c..fd97f41b0 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -605,7 +605,7 @@ pub fn remove_discovered(id: String) { #[inline] pub fn get_uuid() -> String { - base64::encode(hbb_common::get_uuid()) + crate::encode64(hbb_common::get_uuid()) } #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] @@ -876,7 +876,7 @@ pub async fn change_id_shared(id: String, old_id: String) -> &'static str { #[cfg(not(any(target_os = "android", target_os = "ios")))] let uuid = machine_uid::get().unwrap_or("".to_owned()); #[cfg(any(target_os = "android", target_os = "ios"))] - let uuid = base64::encode(hbb_common::get_uuid()); + let uuid = crate::encode64(hbb_common::get_uuid()); if uuid.is_empty() { log::error!("Failed to change id, uuid is_empty");