From efc50a01be8f54aef278cbdaf682705fce18b562 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 10 Apr 2026 12:26:18 +0200 Subject: [PATCH 1/4] Bump iced v14.0 --- Cargo.lock | 1766 ++++++++++------- Cargo.toml | 8 +- flake.nix | 2 +- liana-business/Cargo.toml | 2 +- liana-business/UI_GUIDELINES.md | 6 +- liana-business/business-installer/Cargo.toml | 2 +- .../business-installer/src/views/keys/mod.rs | 6 +- .../src/views/keys/modal.rs | 2 +- .../business-installer/src/views/loading.rs | 2 +- .../src/views/login/account_select.rs | 20 +- .../src/views/login/code.rs | 10 +- .../src/views/login/email.rs | 10 +- .../business-installer/src/views/mod.rs | 32 +- .../src/views/modals/conflict.rs | 4 +- .../src/views/modals/warning.rs | 2 +- .../src/views/org_select.rs | 16 +- .../src/views/paths/modal.rs | 11 +- .../src/views/registration/mod.rs | 16 +- .../template_visualization.rs | 4 +- .../src/views/wallet_select.rs | 22 +- .../src/views/xpub/modal.rs | 26 +- .../business-installer/src/views/xpub/view.rs | 18 +- liana-business/src/main.rs | 11 +- liana-business/src/settings/views/mod.rs | 20 +- liana-gui/Cargo.toml | 2 +- liana-gui/src/app/state/export.rs | 2 +- liana-gui/src/app/view/coins.rs | 8 +- liana-gui/src/app/view/export.rs | 22 +- liana-gui/src/app/view/home.rs | 8 +- liana-gui/src/app/view/label.rs | 8 +- liana-gui/src/app/view/mod.rs | 22 +- liana-gui/src/app/view/psbt.rs | 18 +- liana-gui/src/app/view/psbts.rs | 4 +- liana-gui/src/app/view/receive.rs | 16 +- liana-gui/src/app/view/recovery.rs | 8 +- liana-gui/src/app/view/settings/general.rs | 8 +- liana-gui/src/app/view/settings/mod.rs | 56 +- liana-gui/src/app/view/spend/mod.rs | 39 +- liana-gui/src/app/view/transactions.rs | 4 +- liana-gui/src/download.rs | 48 +- liana-gui/src/export.rs | 101 +- liana-gui/src/gui/mod.rs | 10 +- liana-gui/src/hw.rs | 534 ++--- liana-gui/src/installer/decrypt.rs | 31 +- .../installer/step/descriptor/editor/key.rs | 24 +- liana-gui/src/installer/view/editor/mod.rs | 4 +- .../installer/view/editor/template/custom.rs | 10 +- .../view/editor/template/inheritance.rs | 10 +- .../template/multisig_security_wallet.rs | 12 +- liana-gui/src/installer/view/mod.rs | 115 +- liana-gui/src/launcher.rs | 14 +- liana-gui/src/loader.rs | 114 +- liana-gui/src/main.rs | 23 +- liana-gui/src/node/electrum.rs | 4 +- liana-gui/src/services/connect/login.rs | 2 +- liana-gui/src/utils/mod.rs | 1 + liana-gui/src/utils/subscription.rs | 42 + liana-gui/src/window.rs | 1 + liana-ui/src/component/amount.rs | 14 +- liana-ui/src/component/button.rs | 18 +- liana-ui/src/component/card.rs | 2 +- liana-ui/src/component/form.rs | 4 +- liana-ui/src/component/hw.rs | 20 +- liana-ui/src/component/modal.rs | 32 +- liana-ui/src/component/spinner.rs | 19 +- liana-ui/src/component/text.rs | 16 +- liana-ui/src/component/toast.rs | 76 +- liana-ui/src/icon.rs | 6 +- liana-ui/src/theme/button.rs | 4 + liana-ui/src/theme/card.rs | 1 + liana-ui/src/theme/mod.rs | 22 +- liana-ui/src/theme/overlay.rs | 3 +- liana-ui/src/theme/pick_list.rs | 5 +- liana-ui/src/theme/rule.rs | 4 +- liana-ui/src/theme/scrollable.rs | 13 +- liana-ui/src/theme/toggler.rs | 15 +- liana-ui/src/widget/menu.rs | 66 +- liana-ui/src/widget/mod.rs | 30 + liana-ui/src/widget/modal.rs | 44 +- liana-ui/src/widget/text_input.rs | 117 +- rust-toolchain.toml | 2 +- 81 files changed, 2215 insertions(+), 1661 deletions(-) create mode 100644 liana-gui/src/utils/subscription.rs diff --git a/Cargo.lock b/Cargo.lock index a393375b6..b69f648b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "addr2line" @@ -78,7 +78,7 @@ dependencies = [ "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -96,6 +96,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -109,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.8.0", + "bitflags 2.11.0", "cc", "cesu8", "jni", @@ -118,7 +127,7 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "thiserror 1.0.69", ] @@ -129,12 +138,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -151,21 +154,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] -name = "approx" -version = "0.5.1" +name = "arbitrary" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ - "num-traits", + "derive_arbitrary", ] [[package]] -name = "arbitrary" -version = "1.4.1" +name = "arg_enum_proc_macro" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ - "derive_arbitrary", + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -188,11 +193,11 @@ checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] name = "ash" -version = "0.37.3+1.3.251" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading 0.7.4", + "libloading", ] [[package]] @@ -263,7 +268,7 @@ dependencies = [ "async-trait", "cfg-if", "pin-project", - "rustix", + "rustix 0.38.44", "thiserror 1.0.69", "tokio", "windows-sys 0.52.0", @@ -321,7 +326,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix", + "rustix 0.38.44", "slab", "tracing", "windows-sys 0.59.0", @@ -364,7 +369,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix", + "rustix 0.38.44", "tracing", ] @@ -391,7 +396,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix", + "rustix 0.38.44", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -426,6 +431,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +dependencies = [ + "arrayvec", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -548,18 +576,18 @@ dependencies = [ [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit_field" @@ -700,9 +728,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitstream-io" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "blake2" @@ -734,7 +768,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", ] [[package]] @@ -750,6 +784,12 @@ dependencies = [ "piper", ] +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.17.0" @@ -786,26 +826,20 @@ dependencies = [ "uuid", ] -[[package]] -name = "by_address" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" - [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", @@ -818,6 +852,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.0" @@ -851,10 +891,10 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "log", "polling", - "rustix", + "rustix 0.38.44", "slab", "thiserror 1.0.69", ] @@ -866,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ "calloop", - "rustix", + "rustix 0.38.44", "wayland-backend", "wayland-client", ] @@ -890,16 +930,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cfg-expr" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] [[package]] -name = "cfg_aliases" -version = "0.1.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" @@ -933,16 +977,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -971,9 +1014,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f" dependencies = [ - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -987,20 +1030,21 @@ dependencies = [ [[package]] name = "clipboard_x11" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c" +checksum = "bd63e33452ffdafd39924c4f05a5dd1e94db646c779c6bd59148a3d95fff5ad4" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.17", "x11rb", ] [[package]] name = "codespan-reporting" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ + "serde", "termcolor", "unicode-width", ] @@ -1026,37 +1070,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" -[[package]] -name = "com" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" -dependencies = [ - "com_macros", -] - -[[package]] -name = "com_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" -dependencies = [ - "com_macros_support", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "com_macros_support" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "combine" version = "4.6.7" @@ -1141,19 +1154,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "foreign-types", - "libc", -] - [[package]] name = "core-graphics-types" version = "0.1.3" @@ -1171,28 +1171,38 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "core-foundation 0.10.0", "libc", ] +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + [[package]] name = "cosmic-text" -version = "0.12.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2" +checksum = "173852283a9a57a3cbe365d86e74dc428a09c50421477d5ad6fe9d9509e37737" dependencies = [ - "bitflags 2.8.0", - "fontdb 0.16.2", + "bitflags 2.11.0", + "fontdb", + "harfrust", + "linebender_resource_handle", "log", "rangemap", - "rayon", "rustc-hash 1.1.0", - "rustybuzz", "self_cell", + "skrifa 0.37.0", + "smol_str", "swash", "sys-locale", - "ttf-parser 0.21.1", "unicode-bidi", "unicode-linebreak", "unicode-script", @@ -1279,6 +1289,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +[[package]] +name = "cryoglyph" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc795bdbccdbd461736fb163930a009da6597b226d6f6fce33e7a8eb6ec519" +dependencies = [ + "cosmic-text", + "etagere", + "lru", + "rustc-hash 2.1.1", + "wgpu", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1348,17 +1371,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "d3d12" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" -dependencies = [ - "bitflags 2.8.0", - "libloading 0.8.6", - "winapi", -] - [[package]] name = "data-encoding" version = "2.10.0" @@ -1431,6 +1443,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1448,7 +1470,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.6", + "libloading", ] [[package]] @@ -1466,6 +1488,15 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1478,45 +1509,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -[[package]] -name = "drm" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" -dependencies = [ - "bitflags 2.8.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "rustix", -] - -[[package]] -name = "drm-ffi" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" -dependencies = [ - "drm-sys", - "rustix", -] - -[[package]] -name = "drm-fourcc" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" - -[[package]] -name = "drm-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" -dependencies = [ - "libc", - "linux-raw-sys 0.6.5", -] - [[package]] name = "ecdsa" version = "0.16.9" @@ -1618,6 +1610,26 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1631,7 +1643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1687,7 +1699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" dependencies = [ "bit_field", - "half 2.4.1", + "half 2.7.1", "lebe", "miniz_oxide", "rayon-core", @@ -1707,12 +1719,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" version = "2.3.0" @@ -1805,50 +1811,57 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "font-types" -version = "0.7.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" dependencies = [ "bytemuck", ] [[package]] -name = "fontconfig-parser" -version = "0.5.7" +name = "font-types" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +checksum = "2d9237c6d82152100c691fb77ea18037b402bcc7257d2c876a4ffac81bc22a1c" dependencies = [ - "roxmltree", + "bytemuck", ] [[package]] -name = "fontdb" -version = "0.16.2" +name = "fontconfig-parser" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" dependencies = [ - "fontconfig-parser", - "log", - "memmap2", - "slotmap", - "tinyvec", - "ttf-parser 0.20.0", + "roxmltree", ] [[package]] name = "fontdb" -version = "0.18.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32eac81c1135c1df01d4e6d4233c47ba11f6a6d07f33e0bba09d18797077770" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", "memmap2", "slotmap", "tinyvec", - "ttf-parser 0.21.1", + "ttf-parser", ] [[package]] @@ -1937,7 +1950,6 @@ dependencies = [ "futures-core", "futures-task", "futures-util", - "num_cpus", ] [[package]] @@ -2019,12 +2031,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.4.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "libc", - "windows-targets 0.48.5", + "rustix 1.1.4", + "windows-link", ] [[package]] @@ -2095,9 +2107,9 @@ checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" [[package]] name = "glow" -version = "0.13.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" dependencies = [ "js-sys", "slotmap", @@ -2107,9 +2119,9 @@ dependencies = [ [[package]] name = "glutin_wgl_sys" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" dependencies = [ "gl_generator", ] @@ -2120,7 +2132,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "gpu-alloc-types", ] @@ -2130,40 +2142,39 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", ] [[package]] name = "gpu-allocator" -version = "0.25.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ "log", "presser", "thiserror 1.0.69", - "winapi", "windows", ] [[package]] name = "gpu-descriptor" -version = "0.2.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "gpu-descriptor-types", - "hashbrown 0.14.5", + "hashbrown 0.15.5", ] [[package]] name = "gpu-descriptor-types" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", ] [[package]] @@ -2214,12 +2225,27 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "half" -version = "2.4.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "num-traits", + "zerocopy 0.8.27", +] + +[[package]] +name = "harfrust" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c020db12c71d8a12a3fe7607873cade3a01a6287e29d540c8723276221b9d8" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "core_maths", + "read-fonts 0.35.0", + "smallvec", ] [[package]] @@ -2240,32 +2266,29 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] [[package]] -name = "hashlink" -version = "0.8.4" +name = "hashbrown" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" dependencies = [ - "hashbrown 0.14.5", + "foldhash 0.2.0", ] [[package]] -name = "hassle-rs" -version = "0.11.0" +name = "hashlink" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "bitflags 2.8.0", - "com", - "libc", - "libloading 0.8.6", - "thiserror 1.0.69", - "widestring", - "winapi", + "hashbrown 0.14.5", ] [[package]] @@ -2275,10 +2298,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -2443,7 +2466,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -2457,31 +2480,32 @@ dependencies = [ [[package]] name = "iced" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88acfabc84ec077eaf9ede3457ffa3a104626d79022a9bf7f296093b1d60c73f" +checksum = "000e01026c93ba643f8357a3db3ada0e6555265a377f6f9291c472f6dd701fb3" dependencies = [ "iced_core", + "iced_debug", "iced_futures", "iced_renderer", + "iced_runtime", "iced_widget", "iced_winit", "image", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "iced_aw" -version = "0.12.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "582c517a94ce3205da98e9c10b26bb71aa36b7d7d084441d826dc912711d1bac" +checksum = "3e676b8d322a419c7eef29cac1aa78e8afda6a9d2d4597483d42de3e90378fe2" dependencies = [ "cfg-if", "chrono", - "getrandom 0.3.1", - "iced", + "iced_core", "iced_fonts", - "itertools 0.14.0", + "iced_widget", "num-format", "num-traits", "web-time", @@ -2489,37 +2513,61 @@ dependencies = [ [[package]] name = "iced_core" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0013a238275494641bf8f1732a23a808196540dc67b22ff97099c044ae4c8a1c" +checksum = "91ab1937d699403e7e69252ae743a902bcee9f4ab2052cc4c9a46fcf34729d85" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "bytes", "glam", + "lilt", "log", "num-traits", - "once_cell", - "palette", "rustc-hash 2.1.1", "smol_str", - "thiserror 1.0.69", + "thiserror 2.0.17", "web-time", ] +[[package]] +name = "iced_debug" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25035ab0215a620e53f4103e36fc4e59a1fb2817e4bfc38a30ad27b4202ea0be" +dependencies = [ + "iced_core", + "iced_futures", + "log", +] + [[package]] name = "iced_fonts" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7deb0800a850ee25c8a42559f72c0f249e577feb3aad37b9b65dc1e517e52a" +checksum = "214cff7c8499e328774216690e58e315a1a5f8f6fdd1035aed6298e62ffc4c1d" dependencies = [ "iced_core", + "iced_fonts_macros", + "iced_widget", +] + +[[package]] +name = "iced_fonts_macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef5125e110cb19cd1910a28298661c98c5d9ab02eef43594968352940e8752e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "ttf-parser", ] [[package]] name = "iced_futures" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c04a6745ba2e80f32cf01e034fd00d853aa4f4cd8b91888099cb7aaee0d5d7c" +checksum = "8c0c85ccad42dfbec7293c36c018af0ea0dbcc52d137a4a9a0b0f6822a3fdf0a" dependencies = [ "futures", "iced_core", @@ -2527,79 +2575,76 @@ dependencies = [ "rustc-hash 2.1.1", "tokio", "wasm-bindgen-futures", - "wasm-timer", -] - -[[package]] -name = "iced_glyphon" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c3bb56f1820ca252bc1d0994ece33d233a55657c0c263ea7cb16895adbde82" -dependencies = [ - "cosmic-text", - "etagere", - "lru", - "rustc-hash 2.1.1", - "wgpu", + "wasmtimer", ] [[package]] name = "iced_graphics" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba25a18cfa6d5cc160aca7e1b34f73ccdff21680fa8702168c09739767b6c66f" +checksum = "234ca1c2cec4155055f68fa5fad1b5242c496ac8238d80a259bca382fb44a102" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "bytemuck", "cosmic-text", - "half 2.4.1", + "half 2.7.1", "iced_core", "iced_futures", "image", "kamadak-exif", "log", "lyon_path", - "once_cell", "raw-window-handle", "rustc-hash 2.1.1", - "thiserror 1.0.69", + "thiserror 2.0.17", "unicode-segmentation", ] +[[package]] +name = "iced_program" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dfafec2947cda688d8eb00dac337ba11aa60f9ef6335aed343e189d26e4a673" +dependencies = [ + "iced_graphics", + "iced_runtime", +] + [[package]] name = "iced_renderer" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73558208059f9e622df2bf434e044ee2f838ce75201a023cf0ca3e1244f46c2a" +checksum = "250cc0802408e8c077986ec56c7d07c65f423ee658a4b9fd795a1f2aae5dac05" dependencies = [ "iced_graphics", "iced_tiny_skia", "iced_wgpu", "log", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "iced_runtime" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348b5b2c61c934d88ca3b0ed1ed913291e923d086a66fa288ce9669da9ef62b5" +checksum = "d1889b819ce4c06674183242e336c8d49465665441396914dc07cc86f44fa8d4" dependencies = [ "bytes", "iced_core", "iced_futures", "raw-window-handle", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "iced_tiny_skia" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c625d368284fcc43b0b36b176f76eff1abebe7959dd58bd8ce6897d641962a50" +checksum = "fe0acf8b75a3bc914aff5f2329fdffc1b36eeaea29dda0e4bd232f1c62e9cc3d" dependencies = [ "bytemuck", "cosmic-text", + "iced_debug", "iced_graphics", "kurbo 0.10.4", "log", @@ -2611,59 +2656,56 @@ dependencies = [ [[package]] name = "iced_wgpu" -version = "0.13.5" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15708887133671d2bcc6c1d01d1f176f43a64d6cdc3b2bf893396c3ee498295f" +checksum = "ff144a999b0ca0f8a10257934500060240825c42e950ec0ebee9c8ae30561c13" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "bytemuck", + "cryoglyph", "futures", "glam", "guillotiere", - "iced_glyphon", + "iced_debug", "iced_graphics", "log", "lyon", - "once_cell", "resvg", "rustc-hash 2.1.1", - "thiserror 1.0.69", + "thiserror 2.0.17", "wgpu", ] [[package]] name = "iced_widget" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81429e1b950b0e4bca65be4c4278fea6678ea782030a411778f26fa9f8983e1d" +checksum = "b1596afa0d3109c2618e8bc12bae6c11d3064df8f95c42dfce570397dbe957ab" dependencies = [ "iced_renderer", - "iced_runtime", + "log", "num-traits", - "once_cell", "ouroboros", "qrcode", "rustc-hash 2.1.1", - "thiserror 1.0.69", + "thiserror 2.0.17", "unicode-segmentation", ] [[package]] name = "iced_winit" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44cd4e1c594b6334f409282937bf972ba14d31fedf03c23aa595d982a2fda28" +checksum = "8b7dbedc47562d1de3b9707d939f678b88c382004b7ab5a18f7a7dd723162d75" dependencies = [ - "iced_futures", - "iced_graphics", - "iced_runtime", + "iced_debug", + "iced_program", "log", "rustc-hash 2.1.1", - "thiserror 1.0.69", + "thiserror 2.0.17", "tracing", "wasm-bindgen-futures", "web-sys", - "winapi", "window_clipboard", "winit", ] @@ -2809,27 +2851,48 @@ dependencies = [ [[package]] name = "image" -version = "0.24.9" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", - "byteorder", + "byteorder-lite", "color_quant", "exr", "gif", - "jpeg-decoder", + "image-webp", "num-traits", "png", "qoi", + "ravif", + "rayon", + "rgb", "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", ] [[package]] name = "imagesize" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" [[package]] name = "indexmap" @@ -2851,12 +2914,14 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.13" +name = "interpolate_name" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ - "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -2903,6 +2968,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2954,9 +3028,6 @@ name = "jpeg-decoder" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -dependencies = [ - "rayon", -] [[package]] name = "js-sys" @@ -2996,9 +3067,9 @@ dependencies = [ [[package]] name = "kamadak-exif" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" dependencies = [ "mutate_once", ] @@ -3010,7 +3081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.6", + "libloading", "pkg-config", ] @@ -3238,9 +3309,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libfuzzer-sys" @@ -3252,16 +3323,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.6" @@ -3269,7 +3330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3284,7 +3345,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "libc", "redox_syscall 0.5.8", ] @@ -3320,6 +3381,21 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "lilt" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67562e5eff6b20553fa9be1c503356768420994e28f67e3eafe6f41910e57ad" +dependencies = [ + "web-time", +] + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3328,9 +3404,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.6.5" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -3338,6 +3414,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.12" @@ -3354,11 +3436,20 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru" -version = "0.12.5" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" [[package]] name = "lyon" @@ -3430,6 +3521,16 @@ dependencies = [ "libc", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.4" @@ -3456,13 +3557,13 @@ dependencies = [ [[package]] name = "metal" -version = "0.27.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" +checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block", - "core-graphics-types 0.1.3", + "core-graphics-types 0.2.0", "foreign-types", "log", "objc", @@ -3546,22 +3647,28 @@ checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" [[package]] name = "naga" -version = "0.19.2" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" +checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ + "arrayvec", "bit-set", - "bitflags 2.8.0", + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", "codespan-reporting", + "half 2.7.1", + "hashbrown 0.16.0", "hexf-parse", "indexmap", + "libm", "log", "num-traits", + "once_cell", "rustc-hash 1.1.0", "spirv", - "termcolor", - "thiserror 1.0.69", - "unicode-xid", + "thiserror 2.0.17", + "unicode-ident", ] [[package]] @@ -3570,10 +3677,10 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "jni-sys", "log", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -3587,21 +3694,18 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] [[package]] -name = "ndk-sys" -version = "0.6.0+11769913" +name = "new_debug_unreachable" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" @@ -3620,9 +3724,9 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", "memoffset", ] @@ -3657,6 +3761,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3677,6 +3796,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "num-format" version = "0.4.4" @@ -3697,23 +3827,24 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "num-rational" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", - "libm", + "num-bigint", + "num-integer", + "num-traits", ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "hermit-abi 0.3.9", - "libc", + "autocfg", + "libm", ] [[package]] @@ -3744,7 +3875,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", ] [[package]] @@ -3763,20 +3893,29 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", ] [[package]] @@ -3785,11 +3924,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3799,8 +3938,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3809,10 +3948,34 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.4", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-io-surface", ] [[package]] @@ -3822,8 +3985,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] @@ -3834,9 +3997,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3851,11 +4014,33 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", "dispatch", "libc", - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", ] [[package]] @@ -3865,9 +4050,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3876,10 +4061,10 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3888,21 +4073,33 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-symbols" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3911,16 +4108,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -3933,8 +4130,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3943,20 +4140,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", + "objc2-foundation 0.2.2", ] [[package]] @@ -3970,9 +4158,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "opaque-debug" @@ -4006,6 +4194,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-multimap" version = "0.6.0" @@ -4043,7 +4240,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -4058,35 +4255,11 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owned_ttf_parser" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" -dependencies = [ - "ttf-parser 0.25.1", -] - -[[package]] -name = "palette" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" -dependencies = [ - "approx", - "fast-srgb8", - "palette_derive", - "phf", -] - -[[package]] -name = "palette_derive" -version = "0.7.6" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" dependencies = [ - "by_address", - "proc-macro2", - "quote", - "syn 2.0.98", + "ttf-parser", ] [[package]] @@ -4095,17 +4268,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -4113,21 +4275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -4171,48 +4319,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn 2.0.98", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - [[package]] name = "pico-args" version = "0.5.0" @@ -4299,9 +4405,9 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi", "pin-project-lite", - "rustix", + "rustix 0.38.44", "tracing", "windows-sys 0.59.0", ] @@ -4335,13 +4441,28 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +dependencies = [ + "portable-atomic", +] + [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -4396,6 +4517,19 @@ name = "profiling" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.98", +] [[package]] name = "prost" @@ -4424,7 +4558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools 0.10.5", "lazy_static", "log", @@ -4489,6 +4623,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "166f136dfdb199f98186f3649cf7a0536534a61417a1a30221b492b4fb60ce3f" +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.37.2" @@ -4558,26 +4698,76 @@ dependencies = [ ] [[package]] -name = "rand_core" -version = "0.9.3" +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + +[[package]] +name = "range-alloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" dependencies = [ - "getrandom 0.3.1", + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", ] -[[package]] -name = "range-alloc" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" - -[[package]] -name = "rangemap" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -4615,21 +4805,23 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.22.7" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69aacb76b5c29acfb7f90155d39759a29496aebb49395830e928a9703d2eec2f" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" dependencies = [ "bytemuck", - "font-types", + "core_maths", + "font-types 0.10.1", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "read-fonts" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ - "bitflags 1.3.2", + "bytemuck", + "font-types 0.11.2", ] [[package]] @@ -4647,7 +4839,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", ] [[package]] @@ -4741,18 +4933,19 @@ dependencies = [ [[package]] name = "resvg" -version = "0.42.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944d052815156ac8fa77eaac055220e95ba0b01fa8887108ca710c03805d9051" +checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43" dependencies = [ "gif", - "jpeg-decoder", + "image-webp", "log", "pico-args", "rgb", "svgtypes", "tiny-skia", "usvg", + "zune-jpeg", ] [[package]] @@ -4777,9 +4970,9 @@ dependencies = [ "core-foundation-sys", "js-sys", "log", - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", "pollster", "raw-window-handle", "urlencoding", @@ -4825,7 +5018,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a78046161564f5e7cd9008aff3b2990b3850dc8e0349119b98e8f251e099f24d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -4876,11 +5069,24 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.52.0", ] [[package]] @@ -4957,15 +5163,16 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rustybuzz" -version = "0.14.1" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "bytemuck", - "libm", + "core_maths", + "log", "smallvec", - "ttf-parser 0.21.1", + "ttf-parser", "unicode-bidi-mirroring", "unicode-ccc", "unicode-properties", @@ -5141,6 +5348,15 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "1.0.3" @@ -5168,7 +5384,7 @@ version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4d91116f97173694f1642263b2ff837f80d933aa837e2314969f6728f661df3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "cfg-if", "core-foundation 0.10.0", "core-foundation-sys", @@ -5243,6 +5459,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simplecss" version = "0.2.2" @@ -5260,12 +5485,22 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skrifa" -version = "0.22.3" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts 0.35.0", +] + +[[package]] +name = "skrifa" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe" +checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts", + "read-fonts 0.37.0", ] [[package]] @@ -5288,9 +5523,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -5298,14 +5533,14 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", "memmap2", - "rustix", + "rustix 0.38.44", "thiserror 1.0.69", "wayland-backend", "wayland-client", @@ -5353,7 +5588,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.109", @@ -5371,33 +5606,32 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "as-raw-xcb-connection", "bytemuck", - "cfg_aliases 0.2.1", - "core-graphics 0.24.0", - "drm", "fastrand", - "foreign-types", "js-sys", - "log", "memmap2", - "objc2", - "objc2-foundation", - "objc2-quartz-core", + "ndk", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", "raw-window-handle", "redox_syscall 0.5.8", - "rustix", + "rustix 1.1.4", "tiny-xlib", + "tracing", "wasm-bindgen", "wayland-backend", "wayland-client", "wayland-sys", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "x11rb", ] @@ -5413,7 +5647,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", ] [[package]] @@ -5471,11 +5705,11 @@ dependencies = [ [[package]] name = "swash" -version = "0.1.19" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2" +checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" dependencies = [ - "skrifa", + "skrifa 0.40.0", "yazi", "zeno", ] @@ -5549,6 +5783,19 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.20", + "version-compare", +] + [[package]] name = "tar" version = "0.4.43" @@ -5559,6 +5806,12 @@ dependencies = [ "libc", ] +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempfile" version = "3.16.0" @@ -5569,8 +5822,8 @@ dependencies = [ "fastrand", "getrandom 0.3.1", "once_cell", - "rustix", - "windows-sys 0.59.0", + "rustix 0.38.44", + "windows-sys 0.52.0", ] [[package]] @@ -5686,7 +5939,7 @@ checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e" dependencies = [ "as-raw-xcb-connection", "ctor-lite", - "libloading 0.8.6", + "libloading", "pkg-config", "tracing", ] @@ -5790,6 +6043,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.8", + "toml_edit", +] + [[package]] name = "toml" version = "0.9.8" @@ -5798,7 +6063,7 @@ checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", "serde_core", - "serde_spanned", + "serde_spanned 1.0.3", "toml_datetime 0.7.3", "toml_parser", "toml_writer", @@ -5810,6 +6075,9 @@ name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_datetime" @@ -5827,6 +6095,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ "indexmap", + "serde", + "serde_spanned 0.6.9", "toml_datetime 0.6.8", "winnow", ] @@ -5915,23 +6185,14 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ttf-parser" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" - -[[package]] -name = "ttf-parser" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" - [[package]] name = "ttf-parser" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] [[package]] name = "tungstenite" @@ -5988,15 +6249,15 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-bidi-mirroring" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" [[package]] name = "unicode-ccc" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" [[package]] name = "unicode-ident" @@ -6049,12 +6310,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "universal-hash" version = "0.5.1" @@ -6091,14 +6346,14 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "usvg" -version = "0.42.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84ea542ae85c715f07b082438a4231c3760539d902e11d093847a0b22963032" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" dependencies = [ "base64 0.22.1", "data-url", "flate2", - "fontdb 0.18.0", + "fontdb", "imagesize", "kurbo 0.11.1", "log", @@ -6146,6 +6401,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -6158,6 +6424,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + [[package]] name = "version_check" version = "0.9.5" @@ -6283,18 +6555,17 @@ dependencies = [ ] [[package]] -name = "wasm-timer" -version = "0.2.5" +name = "wasmtimer" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" dependencies = [ "futures", "js-sys", - "parking_lot 0.11.2", + "parking_lot", "pin-utils", + "slab", "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] @@ -6305,7 +6576,7 @@ checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" dependencies = [ "cc", "downcast-rs", - "rustix", + "rustix 0.38.44", "scoped-tls", "smallvec", "wayland-sys", @@ -6317,8 +6588,8 @@ version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" dependencies = [ - "bitflags 2.8.0", - "rustix", + "bitflags 2.11.0", + "rustix 0.38.44", "wayland-backend", "wayland-scanner", ] @@ -6329,7 +6600,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "cursor-icon", "wayland-backend", ] @@ -6340,7 +6611,7 @@ version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" dependencies = [ - "rustix", + "rustix 0.38.44", "wayland-client", "xcursor", ] @@ -6351,7 +6622,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6363,7 +6634,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6376,7 +6647,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6458,17 +6729,21 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "0.19.4" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01" +checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" dependencies = [ "arrayvec", + "bitflags 2.11.0", "cfg-if", - "cfg_aliases 0.1.1", + "cfg_aliases", + "document-features", + "hashbrown 0.16.0", "js-sys", "log", "naga", - "parking_lot 0.12.3", + "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "smallvec", @@ -6483,83 +6758,123 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.19.4" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a" +checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" dependencies = [ "arrayvec", + "bit-set", "bit-vec", - "bitflags 2.8.0", - "cfg_aliases 0.1.1", - "codespan-reporting", + "bitflags 2.11.0", + "bytemuck", + "cfg_aliases", + "document-features", + "hashbrown 0.16.0", "indexmap", "log", "naga", "once_cell", - "parking_lot 0.12.3", + "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", - "web-sys", + "thiserror 2.0.17", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", ] +[[package]] +name = "wgpu-core-deps-apple" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" +dependencies = [ + "wgpu-hal", +] + [[package]] name = "wgpu-hal" -version = "0.19.5" +version = "27.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703" +checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.8.0", + "bitflags 2.11.0", "block", - "cfg_aliases 0.1.1", - "core-graphics-types 0.1.3", - "d3d12", + "bytemuck", + "cfg-if", + "cfg_aliases", + "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hassle-rs", + "hashbrown 0.16.0", "js-sys", "khronos-egl", "libc", - "libloading 0.8.6", + "libloading", "log", "metal", "naga", - "ndk-sys 0.5.0+25.2.9519653", + "ndk-sys", "objc", "once_cell", - "parking_lot 0.12.3", + "ordered-float", + "parking_lot", + "portable-atomic", + "portable-atomic-util", "profiling", "range-alloc", "raw-window-handle", "renderdoc-sys", - "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.17", "wasm-bindgen", "web-sys", "wgpu-types", - "winapi", + "windows", + "windows-core 0.58.0", ] [[package]] name = "wgpu-types" -version = "0.19.2" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" +checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", + "bytemuck", "js-sys", + "log", + "thiserror 2.0.17", "web-sys", ] @@ -6572,15 +6887,9 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.44", ] -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - [[package]] name = "winapi" version = "0.3.9" @@ -6603,7 +6912,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -6614,25 +6923,25 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d" +checksum = "d5654226305eaf2dde8853fb482861d28e5dcecbbd40cb88e8393d94bb80d733" dependencies = [ "clipboard-win", "clipboard_macos", "clipboard_wayland", "clipboard_x11", "raw-window-handle", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "windows" -version = "0.52.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -6645,12 +6954,66 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -6883,30 +7246,30 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.8.0", + "bitflags 2.11.0", "block2", "bytemuck", "calloop", - "cfg_aliases 0.2.1", + "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", - "core-graphics 0.23.2", + "core-graphics", "cursor-icon", "dpi", "js-sys", "libc", "memmap2", "ndk", - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", "percent-encoding", "pin-project", "raw-window-handle", "redox_syscall 0.4.1", - "rustix", + "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit", "smol_str", @@ -6961,7 +7324,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", ] [[package]] @@ -6989,24 +7352,24 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.6", + "libloading", "once_cell", - "rustix", + "rustix 1.1.4", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "x25519-dalek" @@ -7021,9 +7384,9 @@ dependencies = [ [[package]] name = "xcursor" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" [[package]] name = "xdg-home" @@ -7041,7 +7404,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.11.0", "dlib", "log", "once_cell", @@ -7074,9 +7437,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yazi" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" [[package]] name = "yoke" @@ -7167,9 +7530,9 @@ dependencies = [ [[package]] name = "zeno" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" @@ -7178,7 +7541,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive 0.8.27", ] [[package]] @@ -7192,6 +7564,17 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "zerofrom" version = "0.1.5" @@ -7268,6 +7651,12 @@ dependencies = [ "flate2", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + [[package]] name = "zune-inflate" version = "0.2.54" @@ -7277,6 +7666,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core", +] + [[package]] name = "zvariant" version = "5.3.0" diff --git a/Cargo.toml b/Cargo.toml index ce3cb8726..4b0c05a6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ log = "0.4" toml = "0.5" serde_json = "1.0" backtrace = "0.3" -iced = { version = "0.13.1", default-features = false } -iced_aw = "0.12.2" -iced_runtime = "0.13.2" -iced_core = "0.13.2" +iced = { version = "0.14.0", default-features = false } +iced_aw = "0.13.0" +iced_runtime = "0.14.0" +iced_core = "0.14.0" chrono = "0.4.38" dirs = "5.0" jsonrpc = { version = "0.17", default-features = false } diff --git a/flake.nix b/flake.nix index db04d1ac3..a895e0a28 100644 --- a/flake.nix +++ b/flake.nix @@ -21,7 +21,7 @@ toolchain = fenix.packages.${system}.fromToolchainFile { file = ./rust-toolchain.toml; - sha256 = "sha256-Hn2uaQzRLidAWpfmRwSRdImifGUCAb9HeAqTYFXWeQk="; + sha256 = "sha256-Qxt8XAuaUR2OMdKbN4u8dBJOhSHxS+uS06Wl9+flVEk="; }; craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; diff --git a/liana-business/Cargo.toml b/liana-business/Cargo.toml index 57f1ea78f..bc07b05b3 100644 --- a/liana-business/Cargo.toml +++ b/liana-business/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] business-installer = { path = "./business-installer" } async-hwi = { workspace = true } -iced = { workspace = true, default-features = false, features = ["tokio", "svg", "image", "wgpu", "tiny-skia"] } +iced = { workspace = true, default-features = false, features = ["tokio", "svg", "image", "wgpu", "tiny-skia", "x11", "wayland"] } iced_runtime = { workspace = true } liana = { path = "../liana" } liana-gui = { path = "../liana-gui", features = ["skip-windows-icon"] } diff --git a/liana-business/UI_GUIDELINES.md b/liana-business/UI_GUIDELINES.md index c1300e97c..d597eb33e 100644 --- a/liana-business/UI_GUIDELINES.md +++ b/liana-business/UI_GUIDELINES.md @@ -379,9 +379,9 @@ if form_is_valid { ### Common Spacing ```rust -Space::with_height(Length::Fixed(100.0)) // Large gap -Space::with_width(Length::Fill) // Flexible fill -Space::with_width(Length::FillPortion(2)) // Proportional +Space::new().height(Length::Fixed(100.0)) // Large gap +Space::new().width(Length::Fill) // Flexible fill +Space::new().width(Length::FillPortion(2)) // Proportional ``` ### Column Layout diff --git a/liana-business/business-installer/Cargo.toml b/liana-business/business-installer/Cargo.toml index 8dd530216..56e9fdd29 100644 --- a/liana-business/business-installer/Cargo.toml +++ b/liana-business/business-installer/Cargo.toml @@ -12,7 +12,7 @@ crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] } email_address = { workspace = true } reqwest = { workspace = true, features = ["json", "blocking"] } tokio = { workspace = true, features = ["rt"] } -iced = { workspace = true, default-features = false, features = ["tokio", "svg", "image", "wgpu", "tiny-skia"] } +iced = { workspace = true, default-features = false, features = ["tokio", "svg", "image", "wgpu", "tiny-skia", "x11", "wayland"] } liana = { workspace = true } liana-connect = { workspace = true } liana-gui = { workspace = true, features = ["skip-windows-icon"] } diff --git a/liana-business/business-installer/src/views/keys/mod.rs b/liana-business/business-installer/src/views/keys/mod.rs index b355e1157..a81922211 100644 --- a/liana-business/business-installer/src/views/keys/mod.rs +++ b/liana-business/business-installer/src/views/keys/mod.rs @@ -56,7 +56,7 @@ fn key_card( .push(icon::key_icon()) .push(text::h3(&key.alias).style(theme::text::primary)) .push_maybe(identity_display) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(badge); // Description (optional) @@ -172,9 +172,9 @@ fn keys_visualization(state: &State) -> Element<'static, Msg> { // Build the column with all elements let mut column = Column::new() - .push(Space::with_height(50)) + .push(Space::new().height(50)) .push(instruction) - .push(Space::with_height(20)) + .push(Space::new().height(20)) .spacing(10) .padding(20.0); diff --git a/liana-business/business-installer/src/views/keys/modal.rs b/liana-business/business-installer/src/views/keys/modal.rs index 9a66ea167..a4822ee29 100644 --- a/liana-business/business-installer/src/views/keys/modal.rs +++ b/liana-business/business-installer/src/views/keys/modal.rs @@ -164,7 +164,7 @@ pub fn edit_key_modal_view<'a>( let save_button = btn_save(can_save.then_some(Message::KeySave)); let footer = Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(btn_cancel(Some(Message::KeyCancelModal))) .push(save_button); diff --git a/liana-business/business-installer/src/views/loading.rs b/liana-business/business-installer/src/views/loading.rs index 6e89cfd32..64e04e771 100644 --- a/liana-business/business-installer/src/views/loading.rs +++ b/liana-business/business-installer/src/views/loading.rs @@ -28,7 +28,7 @@ pub fn loading_view(has_error: bool) -> Element<'static, Msg> { .align_x(Alignment::Center) .width(Length::Fill) .push(text::h2("Liana Business")) - .push(Space::with_height(30)) + .push(Space::new().height(30)) .push(text::p1_bold(status_text).style(theme::text::secondary)) .push_maybe( status_detail diff --git a/liana-business/business-installer/src/views/login/account_select.rs b/liana-business/business-installer/src/views/login/account_select.rs index 2976bdb93..753fc6b5c 100644 --- a/liana-business/business-installer/src/views/login/account_select.rs +++ b/liana-business/business-installer/src/views/login/account_select.rs @@ -21,22 +21,22 @@ pub fn account_select_view(state: &State) -> Element<'_, Msg> { // Header content let liana_business = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), text::h2("Liana Business"), - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; let select_account_text = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), text::h3("Select an account to continue"), - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; let header_content = Column::new() .push(liana_business) - .push(Space::with_height(30)) + .push(Space::new().height(30)) .push(select_account_text) - .push(Space::with_height(30)); + .push(Space::new().height(30)); // Scrollable list of accounts let mut list_content = Column::new().spacing(15).align_x(iced::Alignment::Center); @@ -51,9 +51,9 @@ pub fn account_select_view(state: &State) -> Element<'_, Msg> { let card_content = if processing && is_selected { // Show loading state for selected account Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(text::p2_medium("Connecting...")) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) } else { row![text::p1_medium(&account.email)] } @@ -86,7 +86,7 @@ pub fn account_select_view(state: &State) -> Element<'_, Msg> { } // Separator - list_content = list_content.push(Space::with_height(20)); + list_content = list_content.push(Space::new().height(20)); // "Connect with another email" button let new_email = btn_tertiary( @@ -101,7 +101,7 @@ pub fn account_select_view(state: &State) -> Element<'_, Msg> { .spacing(15) .align_y(Alignment::Center) .push(new_email) - .push(Space::with_width(Length::Fixed(50.0))); // Match delete button width + .push(Space::new().width(Length::Fixed(50.0))); // Match delete button width list_content = list_content.push(new_email_row); diff --git a/liana-business/business-installer/src/views/login/code.rs b/liana-business/business-installer/src/views/login/code.rs index a95a094c4..b53d50865 100644 --- a/liana-business/business-installer/src/views/login/code.rs +++ b/liana-business/business-installer/src/views/login/code.rs @@ -22,8 +22,8 @@ pub fn login_code_view(state: &State) -> Element<'_, Msg> { form::Form::new_disabled("Token", &state.views.login.code.form) } .id("login_code") - .size(16) - .padding(10); + .size(16.0) + .padding(10.0); let form = Container::new(form).width(Length::Fill); let btn_previous = btn_secondary( @@ -48,14 +48,14 @@ pub fn login_code_view(state: &State) -> Element<'_, Msg> { let btn_row = row![btn_previous, btn_resend_token].spacing(10); let liana_business = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), text::h2("Liana Business"), - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; let content = Column::new() .push(liana_business) - .push(Space::with_height(20)) + .push(Space::new().height(20)) .push(row![ text::p1_medium("An authentication token has been emailed to ") .style(theme::text::primary), diff --git a/liana-business/business-installer/src/views/login/email.rs b/liana-business/business-installer/src/views/login/email.rs index 776165345..545c408da 100644 --- a/liana-business/business-installer/src/views/login/email.rs +++ b/liana-business/business-installer/src/views/login/email.rs @@ -28,8 +28,8 @@ pub fn login_email_view(state: &State) -> Element<'_, Msg> { form::Form::new_disabled("Email", &state.views.login.email.form) } .id("login_email") - .size(16) - .padding(10); + .size(16.0) + .padding(10.0); let form = Container::new(form).width(Length::Fill); let btn = btn_primary( @@ -40,14 +40,14 @@ pub fn login_email_view(state: &State) -> Element<'_, Msg> { ); let liana_business = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), text::h2("Liana Business"), - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; let content = Column::new() .push(liana_business) - .push(Space::with_height(20)) + .push(Space::new().height(20)) .push( text::p1_medium("Enter the email associated with your account") .style(theme::text::primary), diff --git a/liana-business/business-installer/src/views/mod.rs b/liana-business/business-installer/src/views/mod.rs index 4ae2f73cb..3234aa042 100644 --- a/liana-business/business-installer/src/views/mod.rs +++ b/liana-business/business-installer/src/views/mod.rs @@ -35,10 +35,10 @@ use liana_ui::{ use uuid::Uuid; pub const INSTALLER_STEPS: usize = 5; -pub const MENU_ENTRY_WIDTH: u16 = 600; -pub const ACCOUNT_ENTRY_WIDTH: u16 = MENU_ENTRY_WIDTH - 80; -pub const MENU_ENTRY_HEIGHT: u16 = 80; -const EMAIL_ROW_HEIGHT: u16 = 56; +pub const MENU_ENTRY_WIDTH: f32 = 600.0; +pub const ACCOUNT_ENTRY_WIDTH: f32 = MENU_ENTRY_WIDTH - 80.0; +pub const MENU_ENTRY_HEIGHT: f32 = 80.0; +const EMAIL_ROW_HEIGHT: f32 = 56.0; /// Format last edit information as "Edited by [You|email] [relative_time]". /// Returns None if `last_edited` is None. @@ -64,7 +64,7 @@ pub fn format_last_edit_info( }) } -const EMAIL_HEADER_SPACER: u16 = 30; +const EMAIL_HEADER_SPACER: f32 = 30.0; /// Create a breadcrumb element from path segments. /// Renders as "Segment1 > Segment2 > Segment3" with styled separators. @@ -115,7 +115,7 @@ fn layout_inner<'a>( // Build the top-right row with optional role badge and email let mut email_row = Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .spacing(10) .align_y(Alignment::Center); @@ -131,7 +131,7 @@ fn layout_inner<'a>( email_row = email_row .push(Container::new(text::p1_medium(e).style(theme::text::accent)).padding(20)); } else { - email_row = email_row.push(Space::with_height(EMAIL_ROW_HEIGHT)); + email_row = email_row.push(Space::new().height(EMAIL_ROW_HEIGHT)); } let header = Row::new() @@ -142,7 +142,7 @@ fn layout_inner<'a>( .center_x(Length::FillPortion(2)) .into() } else { - Element::from(Space::with_width(Length::FillPortion(2))) + Element::from(Space::new().width(Length::FillPortion(2))) }) .push(Container::new(breadcrumb_header(breadcrumb)).width(Length::FillPortion(8))) .push_maybe(if progress.1 > 0 { @@ -157,7 +157,7 @@ fn layout_inner<'a>( let fill_portion = if padding_left { 8 } else { 10 }; let right_spacer = || -> Option { if padding_left { - Some(Space::with_width(Length::FillPortion(2))) + Some(Space::new().width(Length::FillPortion(2))) } else { None } @@ -166,11 +166,11 @@ fn layout_inner<'a>( match content { LayoutContent::Scrollable(inner) => { let content_row = Row::new() - .push(Space::with_width(Length::FillPortion(2))) + .push(Space::new().width(Length::FillPortion(2))) .push( Container::new( Column::new() - .push(Space::with_height(Length::Fixed(100.0))) + .push(Space::new().height(Length::Fixed(100.0))) .push(inner), ) .width(Length::FillPortion(fill_portion)), @@ -181,7 +181,7 @@ fn layout_inner<'a>( Column::new() .width(Length::Fill) .push(email_row) - .push(Space::with_height(EMAIL_HEADER_SPACER)) + .push(Space::new().height(EMAIL_HEADER_SPACER)) .push(header) .push(content_row), )) @@ -197,12 +197,12 @@ fn layout_inner<'a>( footer, } => { let header_area = Row::new() - .push(Space::with_width(Length::FillPortion(2))) + .push(Space::new().width(Length::FillPortion(2))) .push(Container::new(header_content).width(Length::FillPortion(fill_portion))) .push_maybe(right_spacer()); let list_area = Row::new() - .push(Space::with_width(Length::FillPortion(2))) + .push(Space::new().width(Length::FillPortion(2))) .push( Container::new(scrollable(list).height(Length::Fill)) .width(Length::FillPortion(fill_portion)) @@ -213,7 +213,7 @@ fn layout_inner<'a>( let footer_area: Option> = footer.map(|f| { Row::new() - .push(Space::with_width(Length::FillPortion(2))) + .push(Space::new().width(Length::FillPortion(2))) .push(Container::new(f).width(Length::FillPortion(fill_portion))) .push_maybe(right_spacer()) }); @@ -223,7 +223,7 @@ fn layout_inner<'a>( .width(Length::Fill) .height(Length::Fill) .push(email_row) - .push(Space::with_height(EMAIL_HEADER_SPACER)) + .push(Space::new().height(EMAIL_HEADER_SPACER)) .push(header) .push(header_area) .push(list_area) diff --git a/liana-business/business-installer/src/views/modals/conflict.rs b/liana-business/business-installer/src/views/modals/conflict.rs index fa0972f6f..ba6596159 100644 --- a/liana-business/business-installer/src/views/modals/conflict.rs +++ b/liana-business/business-installer/src/views/modals/conflict.rs @@ -18,7 +18,7 @@ pub fn conflict_modal_view(modal_state: &ConflictModalState) -> Element<'_, Msg> // Two-button choice: "Keep my changes" and "Reload" Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(btn_secondary( None, "Keep my changes", @@ -35,7 +35,7 @@ pub fn conflict_modal_view(modal_state: &ConflictModalState) -> Element<'_, Msg> // Single dismiss button for info-only conflicts Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(btn_ok(Some(Msg::ConflictDismiss))) }; diff --git a/liana-business/business-installer/src/views/modals/warning.rs b/liana-business/business-installer/src/views/modals/warning.rs index 0303bf61a..1c4967e05 100644 --- a/liana-business/business-installer/src/views/modals/warning.rs +++ b/liana-business/business-installer/src/views/modals/warning.rs @@ -15,7 +15,7 @@ pub fn warning_modal_view(modal_state: &WarningModalState) -> Element<'_, Msg> { let footer = Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(btn_ok(Some(Msg::WarningCloseModal))); let body = Column::new().push(message).push(footer).spacing(15); diff --git a/liana-business/business-installer/src/views/org_select.rs b/liana-business/business-installer/src/views/org_select.rs index 980c955f2..01f68e44e 100644 --- a/liana-business/business-installer/src/views/org_select.rs +++ b/liana-business/business-installer/src/views/org_select.rs @@ -103,7 +103,7 @@ pub fn org_card<'a>( let message = Some(Msg::OrgSelected(id)); - let content = row![content, Space::with_width(Length::Fill)] + let content = row![content, Space::new().width(Length::Fill)] .width(Length::Fill) .width(Length::Fill); menu_entry(content, message) @@ -123,15 +123,15 @@ pub fn org_select_view(state: &State) -> Element<'_, Msg> { let title = text::h2("Select an Organization"); let title = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), title, - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; // Fixed header content: title and search bar let mut header_content = Column::new() .push(title) - .push(Space::with_height(30)) + .push(Space::new().height(30)) .spacing(10) .align_x(Alignment::Center) .padding(20); @@ -156,13 +156,13 @@ pub fn org_select_view(state: &State) -> Element<'_, Msg> { &search_value, Msg::OrgSelectUpdateSearchFilter, ) - .size(16) - .padding(10); + .size(16.0) + .padding(10.0); let search_container = Container::new(search_form) .width(Length::Fixed(500.0)) .align_x(Alignment::Center); header_content = header_content.push(search_container); - header_content = header_content.push(Space::with_height(10)); + header_content = header_content.push(Space::new().height(10)); } // Scrollable list content: organization cards @@ -243,7 +243,7 @@ pub fn org_select_view(state: &State) -> Element<'_, Msg> { list_content = list_content.push(card); } } - list_content = list_content.push(Space::with_height(50)); + list_content = list_content.push(Space::new().height(50)); let role_badge = if is_ws_manager { Some("WS Admin") diff --git a/liana-business/business-installer/src/views/paths/modal.rs b/liana-business/business-installer/src/views/paths/modal.rs index a7c3dbd17..c5a0ea4e6 100644 --- a/liana-business/business-installer/src/views/paths/modal.rs +++ b/liana-business/business-installer/src/views/paths/modal.rs @@ -95,7 +95,8 @@ pub fn edit_path_modal_view<'a>( format!("{} ({})", name, identity_str) }; col = col.push( - checkbox(label, is_selected) + checkbox(is_selected) + .label(label) .on_toggle(move |_| Msg::TemplateToggleKeyInPath(*key_id)), ); } @@ -149,7 +150,7 @@ pub fn edit_path_modal_view<'a>( // Threshold warning (optional) let threshold_warning_row = threshold_warning.map(|warning| { Row::new() - .push(Space::with_width(Length::Fixed(LABEL_WIDTH + 10.0))) + .push(Space::new().width(Length::Fixed(LABEL_WIDTH + 10.0))) .push(text::p2_medium(warning).style(theme::text::warning)) }); @@ -228,7 +229,7 @@ pub fn edit_path_modal_view<'a>( let timelock_warning_row = warning.map(|w| { Row::new() - .push(Space::with_width(Length::Fixed(LABEL_WIDTH + 10.0))) + .push(Space::new().width(Length::Fixed(LABEL_WIDTH + 10.0))) .push(text::p2_medium(w).style(theme::text::warning)) }); @@ -240,7 +241,7 @@ pub fn edit_path_modal_view<'a>( .style(theme::text::secondary); let max_hint_row = Row::new() - .push(Space::with_width(Length::Fixed(LABEL_WIDTH + 10.0))) + .push(Space::new().width(Length::Fixed(LABEL_WIDTH + 10.0))) .push(max_hint); let section = Column::new() @@ -262,7 +263,7 @@ pub fn edit_path_modal_view<'a>( let footer = Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(btn_cancel(Some(Msg::TemplateCancelPathModal))) .push(save_button); diff --git a/liana-business/business-installer/src/views/registration/mod.rs b/liana-business/business-installer/src/views/registration/mod.rs index ab239eae9..8e25812f4 100644 --- a/liana-business/business-installer/src/views/registration/mod.rs +++ b/liana-business/business-installer/src/views/registration/mod.rs @@ -58,9 +58,9 @@ pub fn registration_view(state: &State) -> Element<'_, Msg> { .style(theme::text::secondary), ); let header_content = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), header_content, - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]; // List content: device cards or info message @@ -74,13 +74,13 @@ pub fn registration_view(state: &State) -> Element<'_, Msg> { let footer_content = if reg_state.user_devices.is_empty() { None } else { - let spacer = MENU_ENTRY_WIDTH - BtnWidth::XL as u16; + let spacer = MENU_ENTRY_WIDTH - BtnWidth::XL as u32 as f32; let skip_btn = btn_secondary(None, "Skip", BtnWidth::XL, Some(Msg::RegistrationSkipAll)); let footer = row![ - Space::with_width(Length::Fill), - Space::with_width(spacer), + Space::new().width(Length::Fill), + Space::new().width(spacer), skip_btn, - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ] .align_y(Alignment::Center); @@ -213,9 +213,9 @@ fn key_card( let content = Row::new() .push(left) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(right) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .align_y(Alignment::Center) .height(Length::Fill); menu_entry(content, message) diff --git a/liana-business/business-installer/src/views/template_builder/template_visualization.rs b/liana-business/business-installer/src/views/template_builder/template_visualization.rs index b53ea8897..5586a2784 100644 --- a/liana-business/business-installer/src/views/template_builder/template_visualization.rs +++ b/liana-business/business-installer/src/views/template_builder/template_visualization.rs @@ -250,7 +250,7 @@ pub fn template_visualization(state: &State) -> Element<'static, Msg> { let mut column = Column::new() .spacing(10) .padding(20.0) - .push(Space::with_height(50)); + .push(Space::new().height(50)); // Primary path row: [r_shape] [path_card] let primary_last_edit = format_last_edit_info( @@ -319,7 +319,7 @@ pub fn template_visualization(state: &State) -> Element<'static, Msg> { let add_path_row = Row::new() .spacing(15) .align_y(Alignment::Center) - .push(Space::with_width(Length::Fixed(R_SHAPE_WIDTH))) + .push(Space::new().width(Length::Fixed(R_SHAPE_WIDTH))) .push(add_path_card); column = column.push(add_path_row); diff --git a/liana-business/business-installer/src/views/wallet_select.rs b/liana-business/business-installer/src/views/wallet_select.rs index 478dab7e6..66a97a2b3 100644 --- a/liana-business/business-installer/src/views/wallet_select.rs +++ b/liana-business/business-installer/src/views/wallet_select.rs @@ -159,7 +159,7 @@ pub fn wallet_card<'a>( let content = Row::new() .push(left_col) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(right_col) .align_y(Alignment::Center) .height(Length::Fill); @@ -189,9 +189,9 @@ pub fn wallet_select_view(state: &State) -> Element<'_, Msg> { }; let title = text::h2(title_text); let title = row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), title, - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ]; // Get current user email for role derivation @@ -207,7 +207,7 @@ pub fn wallet_select_view(state: &State) -> Element<'_, Msg> { // Fixed header content: title, filter checkbox, and search bar let mut header_content = Column::new() .push(title) - .push(Space::with_height(30)) + .push(Space::new().height(30)) .spacing(10) .align_x(Alignment::Center) .padding(20); @@ -215,11 +215,11 @@ pub fn wallet_select_view(state: &State) -> Element<'_, Msg> { // Add filter checkbox for WS Admin users (centered) if is_ws_admin && has_wallets { let filter_checkbox = Row::new() - .push(Space::with_width(Length::Fill)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .width(Length::Fill); header_content = header_content.push(filter_checkbox); - header_content = header_content.push(Space::with_height(10)); + header_content = header_content.push(Space::new().height(10)); } // Add search bar for all users when there are wallets @@ -234,13 +234,13 @@ pub fn wallet_select_view(state: &State) -> Element<'_, Msg> { &search_value, Msg::WalletSelectUpdateSearchFilter, ) - .size(16) - .padding(10); + .size(16.0) + .padding(10.0); let search_container = Container::new(search_form) .width(Length::Fixed(500.0)) .align_x(Alignment::Center); header_content = header_content.push(search_container); - header_content = header_content.push(Space::with_height(10)); + header_content = header_content.push(Space::new().height(10)); } // Scrollable list content: wallet cards @@ -336,7 +336,7 @@ pub fn wallet_select_view(state: &State) -> Element<'_, Msg> { // FIXME: doe we display something if no wallet? } - list_content = list_content.push(Space::with_height(50)); + list_content = list_content.push(Space::new().height(50)); let role_badge = if is_ws_admin { Some("WS Admin") } else { None }; diff --git a/liana-business/business-installer/src/views/xpub/modal.rs b/liana-business/business-installer/src/views/xpub/modal.rs index 6ca119455..2a991df11 100644 --- a/liana-business/business-installer/src/views/xpub/modal.rs +++ b/liana-business/business-installer/src/views/xpub/modal.rs @@ -49,7 +49,7 @@ fn select_view<'a>(state: &'a State, modal_state: &'a XpubEntryModalState) -> El Container::new( Row::new() .spacing(10) - .push(icon::tooltip_icon().size(16)) + .push(icon::tooltip_icon().size(16.0)) .push( text::p2_medium( "This key already has an xpub. You can replace it by fetching from a device, \ @@ -58,7 +58,7 @@ fn select_view<'a>(state: &'a State, modal_state: &'a XpubEntryModalState) -> El .style(theme::text::primary), ), ) - .padding(10) + .padding(10.0) .style(theme::card::simple) .width(Length::Fill), ); @@ -80,16 +80,16 @@ fn select_view<'a>(state: &'a State, modal_state: &'a XpubEntryModalState) -> El .spacing(10) .align_y(Alignment::Center) .push(text::p2_medium("Current xpub:").style(theme::text::primary)) - .push(Space::with_width(Length::Fill)); + .push(Space::new().width(Length::Fill)); let input_value = Container::new(text::p2_medium(&modal_state.xpub_input).style(theme::text::secondary)) - .padding(10) + .padding(10.0) .style(theme::card::simple) .width(Length::Fill); Column::new() - .push(Space::with_height(5)) + .push(Space::new().height(5)) .push(input_header) .push(input_value) }); @@ -152,9 +152,9 @@ fn details_view(modal_state: &XpubEntryModalState) -> Element<'_, Msg> { let fetching_label = modal_state.processing.then_some( Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(text::p1_medium("Fetching from device...").style(theme::text::primary)) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ); let error = modal_state.fetch_error.as_ref().map(|error| { @@ -172,7 +172,7 @@ fn details_view(modal_state: &XpubEntryModalState) -> Element<'_, Msg> { btn_row = btn_row.push(btn_retry(Some(Msg::XpubRetry))); } - btn_row = btn_row.push(Space::with_width(Length::Fill)); + btn_row = btn_row.push(Space::new().width(Length::Fill)); // Save button (enabled only if we have a valid xpub) let can_save = @@ -199,7 +199,7 @@ fn details_view(modal_state: &XpubEntryModalState) -> Element<'_, Msg> { && validation_error.is_none()) .then_some({ Container::new(text::p2_medium(&modal_state.xpub_input).style(theme::text::secondary)) - .padding(10) + .padding(10.0) .style(theme::card::simple) .width(Length::Fill) }); @@ -238,13 +238,13 @@ fn hw_section(state: &State) -> Element<'_, Msg> { Column::new() .spacing(10) .align_x(Alignment::Center) - .push(Space::with_height(20)) + .push(Space::new().height(20)) .push(icon::usb_icon().size(60)) .push( text::p1_medium("No hardware wallets detected. Connect a device and unlock it.") .style(theme::text::primary), ) - .push(Space::with_height(20)) + .push(Space::new().height(20)) .width(Length::Fill) .into() } else { @@ -262,7 +262,7 @@ fn hw_section(state: &State) -> Element<'_, Msg> { Column::new() .push(device_list) .spacing(10) - .padding(10) + .padding(10.0) .into() } @@ -489,7 +489,7 @@ fn footer_buttons(modal_state: &XpubEntryModalState) -> Element<'_, Msg> { .push(save_button); Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(buttons) .into() } diff --git a/liana-business/business-installer/src/views/xpub/view.rs b/liana-business/business-installer/src/views/xpub/view.rs index 13b1492d6..db52513fe 100644 --- a/liana-business/business-installer/src/views/xpub/view.rs +++ b/liana-business/business-installer/src/views/xpub/view.rs @@ -51,7 +51,7 @@ fn xpub_key_card( .push(icon::key_icon()) .push(text::h3(&key.alias).style(theme::text::primary)) .push(text::p2_medium(identity_str).style(theme::text::accent)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(xpub_status_badge(key.xpub.is_some())); // Second row: Description @@ -153,7 +153,7 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { .align_x(Alignment::Center) .padding(20) .push(text::h2(format!("{} - Set Keys", wallet_name))) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push(instruction); // Build scrollable key list @@ -161,7 +161,7 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { .spacing(10) .padding(20) .align_x(Alignment::Center) - .push(Space::with_height(20)); + .push(Space::new().height(20)); if owned_keys.is_empty() { // Empty state: no keys match filter @@ -174,9 +174,9 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { } else { list_content = list_content.push( row![ - Space::with_width(10), + Space::new().width(10), text::h3("Your keys:").style(theme::text::primary), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ] .width(MENU_ENTRY_WIDTH), ); @@ -194,11 +194,11 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { } if is_wallet_manager { - list_content = list_content.push(Space::with_height(20)).push( + list_content = list_content.push(Space::new().height(20)).push( row![ - Space::with_width(10), + Space::new().width(10), text::h3("Other participants' keys:").style(theme::text::primary), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ] .width(MENU_ENTRY_WIDTH), ); @@ -215,7 +215,7 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { } } - list_content = list_content.push(Space::with_height(50)); + list_content = list_content.push(Space::new().height(50)); let role_badge = if is_ws_admin { Some("WS Admin") } else { None }; diff --git a/liana-business/src/main.rs b/liana-business/src/main.rs index 3558f08a7..c848daa1f 100644 --- a/liana-business/src/main.rs +++ b/liana-business/src/main.rs @@ -63,17 +63,22 @@ fn main() -> Result<(), Box> { // Use business-specific app icon (blue instead of green) window_settings.icon = Some(image::liana_business_app_icon()); + let boot_args = std::sync::Mutex::new(Some((config, log_level, VERSION))); if let Err(e) = iced::application( - LianaBusiness::title, + move || { + let args = boot_args.lock().unwrap().take().expect("boot called twice"); + LianaBusiness::new(args) + }, LianaBusiness::update, LianaBusiness::view, ) - .theme(|_| theme::Theme::business()) + .title(LianaBusiness::title) + .theme(|_: &_| theme::Theme::business()) .scale_factor(LianaBusiness::scale_factor) .subscription(LianaBusiness::subscription) .settings(settings) .window(window_settings) - .run_with(move || LianaBusiness::new((config, log_level, VERSION))) + .run() { log::error!("{}", e); Err(format!("Failed to launch UI: {}", e).into()) diff --git a/liana-business/src/settings/views/mod.rs b/liana-business/src/settings/views/mod.rs index 7aeae7b84..2bbff7a22 100644 --- a/liana-business/src/settings/views/mod.rs +++ b/liana-business/src/settings/views/mod.rs @@ -5,7 +5,7 @@ use iced::{Alignment, Length}; use liana_ui::{ component::{badge, button, card, pick_list, separation, text::*}, icon, theme, - widget::Element, + widget::{ColumnExt, Element}, }; use crate::settings::message::{Msg, Section}; @@ -56,7 +56,7 @@ pub fn wallet_view(state: &BusinessSettingsUI) -> Element<'_, Msg> { scrollable( Column::new() .push(text(&descriptor).small()) - .push(Space::with_height(Length::Fixed(5.0))), + .push(Space::new().height(Length::Fixed(5.0))), ) .direction(scrollable::Direction::Horizontal( scrollable::Scrollbar::new().width(5).scroller_width(5), @@ -65,7 +65,7 @@ pub fn wallet_view(state: &BusinessSettingsUI) -> Element<'_, Msg> { .push( Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(Some(icon::chip_icon()), "Register on device") .on_press(Msg::RegisterWallet), @@ -98,7 +98,7 @@ pub fn general_view( .spacing(10) .align_y(Alignment::Center) .push(text("Fiat price:").bold()) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( Toggler::new(fiat_enabled) .on_toggle(Msg::FiatEnable) @@ -111,14 +111,14 @@ pub fn general_view( .spacing(20) .align_y(Alignment::Center) .push(text("Currency:").bold()) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( pick_list::pick_list( crate::settings::ALL_BACKEND_CURRENCIES, Some(currency), Msg::FiatCurrencyEdited, ) - .padding(10), + .padding(10.0), ), ), ), @@ -143,16 +143,16 @@ pub fn about_view() -> Element<'static, Msg> { Row::new() .push(badge::badge(icon::tooltip_icon())) .push(text("Version").bold()) - .padding(10) + .padding(10.0) .spacing(20) .align_y(Alignment::Center) .width(Length::Fill), ) .push(separation().width(Length::Fill)) - .push(Space::with_height(Length::Fixed(10.0))) + .push(Space::new().height(Length::Fixed(10.0))) .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(text(format!("liana-business v{}", VERSION))), ), ); @@ -177,7 +177,7 @@ fn menu_entry( Row::new() .push(badge::badge(entry_icon)) .push(text(title).bold()) - .padding(10) + .padding(10.0) .spacing(20) .align_y(Alignment::Center) .width(Length::Fill), diff --git a/liana-gui/Cargo.toml b/liana-gui/Cargo.toml index 8667f56d0..2c9a94243 100644 --- a/liana-gui/Cargo.toml +++ b/liana-gui/Cargo.toml @@ -26,7 +26,7 @@ liana-ui = { path = "../liana-ui" } backtrace = { workspace = true } hex = { workspace = true } -iced = { workspace = true, default-features = false, features = ["tokio", "svg", "qr_code", "image", "lazy", "wgpu", "advanced", "tiny-skia"] } +iced = { workspace = true, default-features = false, features = ["tokio", "svg", "qr_code", "image", "lazy", "wgpu", "advanced", "tiny-skia", "x11", "wayland"] } iced_aw = { workspace = true, features = ["context_menu"] } iced_runtime = { workspace = true } diff --git a/liana-gui/src/app/state/export.rs b/liana-gui/src/app/state/export.rs index d76f98842..840faa9b1 100644 --- a/liana-gui/src/app/state/export.rs +++ b/liana-gui/src/app/state/export.rs @@ -316,7 +316,7 @@ impl ExportModal { if let Some(path) = &self.path { match &self.state { ImportExportState::Started | ImportExportState::Progress(_) => { - Some(iced::Subscription::run_with_id( + Some(crate::utils::subscription::run_with_id( self.modal_title(), export::export_subscription( self.daemon.clone(), diff --git a/liana-gui/src/app/view/coins.rs b/liana-gui/src/app/view/coins.rs index d8e58065e..5ca02c3d3 100644 --- a/liana-gui/src/app/view/coins.rs +++ b/liana-gui/src/app/view/coins.rs @@ -91,7 +91,7 @@ fn coin_list_view<'a>( ) .width(Length::Fill) } else { - Container::new(Space::with_width(Length::Fill)) + Container::new(Space::new().width(Length::Fill)) .width(Length::Fill) } } else if let Some(label) = labels.get(&txid) { @@ -109,11 +109,11 @@ fn coin_list_view<'a>( ) .width(Length::Fill) } else { - Container::new(Space::with_width(Length::Fill)) + Container::new(Space::new().width(Length::Fill)) .width(Length::Fill) } } else { - Container::new(Space::with_width(Length::Fill)) + Container::new(Space::new().width(Length::Fill)) .width(Length::Fill) }) .push(if coin.spend_info.is_some() { @@ -298,7 +298,7 @@ fn coin_list_view<'a>( .spacing(5) } else { Column::new().push( - Row::new().push(Space::with_width(Length::Fill)).push({ + Row::new().push(Space::new().width(Length::Fill)).push({ let (icon, label) = (Some(icon::arrow_repeat()), "Refresh coin"); let refresh_btn = if seq == 0 { diff --git a/liana-gui/src/app/view/export.rs b/liana-gui/src/app/view/export.rs index 0eb8eea50..71b3eb911 100644 --- a/liana-gui/src/app/view/export.rs +++ b/liana-gui/src/app/view/export.rs @@ -9,7 +9,7 @@ use liana_ui::{ text::{h4_bold, text}, }, icon, - widget::Element, + widget::{ColumnExt, Element, RowExt}, }; use crate::export::ImportExportState; @@ -65,7 +65,7 @@ pub fn export_modal<'a, Message: From + Clone + 'static>( button::secondary(None, "Overwrite") .on_press(ImportExportMessage::Overwrite.into()), ) - .push(Space::with_width(30)) + .push(Space::new().width(30)) .push( button::secondary(None, "Ignore").on_press(ImportExportMessage::Ignore.into()), ), @@ -79,7 +79,7 @@ pub fn export_modal<'a, Message: From + Clone + 'static>( button::secondary(None, "Overwrite") .on_press(ImportExportMessage::Overwrite.into()), ) - .push(Space::with_width(30)) + .push(Space::new().width(30)) .push( button::secondary(None, "Ignore").on_press(ImportExportMessage::Ignore.into()), ), @@ -120,27 +120,27 @@ pub fn export_modal<'a, Message: From + Clone + 'static>( p += 2.5; } let progress_bar_row = Row::new() - .push(Space::with_width(30)) + .push(Space::new().width(30)) .push(progress_bar(0.0..=100.0, p)) - .push(Space::with_width(30)); + .push(Space::new().width(30)); card::simple( Column::new() .spacing(10) .push( Row::new() - .push(Space::with_width(20)) + .push(Space::new().width(20)) .push(h4_bold(title)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(cross) .align_y(alignment::Vertical::Center), ) - .push(Space::with_height(Length::Fill)) + .push(Space::new().height(Length::Fill)) .push(progress_bar_row) - .push(Space::with_height(Length::Fill)) + .push(Space::new().height(Length::Fill)) .push(Row::new().push(text(msg))) - .push(Space::with_height(Length::Fill)) + .push(Space::new().height(Length::Fill)) .push_maybe(button) - .push(Space::with_height(5)), + .push(Space::new().height(5)), ) .width(Length::Fixed(500.0)) .height(Length::Fixed(300.0)) diff --git a/liana-gui/src/app/view/home.rs b/liana-gui/src/app/view/home.rs index c01910ed9..f4bdabd44 100644 --- a/liana-gui/src/app/view/home.rs +++ b/liana-gui/src/app/view/home.rs @@ -51,7 +51,7 @@ fn rescan_warning<'a>() -> Element<'a, Message> { .push( Row::new() .spacing(5) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(None, "Go to rescan").on_press(Message::Menu( Menu::SettingsPreSelected(menu::SettingsOption::Node), @@ -92,7 +92,7 @@ pub fn home_view<'a>( .push_maybe(fiat_balance.map(|fiat| { Row::new() .align_y(Alignment::Center) - .push(Space::with_width(20)) + .push(Space::new().width(20)) .push( fiat.to_text() .font(MANROPE_MEDIUM) @@ -155,7 +155,7 @@ pub fn home_view<'a>( .push_maybe(fiat_unconfirmed.map(|fiat| { Row::new() .align_y(Alignment::Center) - .push(Space::with_width(10)) // total spacing = 20 including row spacing + .push(Space::new().width(10)) // total spacing = 20 including row spacing .push(fiat.to_text().size(H4_SIZE).color(color::GREY_3)) })) .wrap(), @@ -345,7 +345,7 @@ pub fn payment_view<'a>( &tx.tx.output[output_index].value, H3_SIZE, ))) - .push(Space::with_height(H3_SIZE)) + .push(Space::new().height(H3_SIZE)) .push(Container::new(h3("Transaction")).width(Length::Fill)) .push_maybe(if tx.is_batch() { if let Some(label) = labels_editing.get(&txid) { diff --git a/liana-gui/src/app/view/label.rs b/liana-gui/src/app/view/label.rs index e70fdcf05..cc8f7057d 100644 --- a/liana-gui/src/app/view/label.rs +++ b/liana-gui/src/app/view/label.rs @@ -12,7 +12,7 @@ use crate::app::view; pub fn label_editable( labelled: Vec, label: Option<&String>, - size: u16, + size: f32, ) -> Element<'_, view::Message> { if let Some(label) = label { if !label.is_empty() { @@ -46,14 +46,14 @@ pub fn label_editable( pub fn label_editing( labelled: Vec, label: &form::Value, - size: u16, + size: f32, ) -> Element { let e: Element = Container::new( row!( form::Form::new("Label", label, view::LabelMessage::Edited) .warning("Invalid label length, cannot be superior to 100") .size(size) - .padding(10), + .padding(10.0), if label.valid { button::secondary(None, "Save").on_press(view::message::LabelMessage::Confirm) } else { @@ -71,7 +71,7 @@ pub fn label_editing( pub fn label_non_editable( labelled: Vec, label: Option<&String>, - size: u16, + size: f32, ) -> Element { let label_text = label.map(|s| s.as_str()).unwrap_or("(External Output)"); diff --git a/liana-gui/src/app/view/mod.rs b/liana-gui/src/app/view/mod.rs index d1a4e5427..25aab631c 100644 --- a/liana-gui/src/app/view/mod.rs +++ b/liana-gui/src/app/view/mod.rs @@ -57,7 +57,7 @@ pub fn sidebar<'a>( } .height(120); let upper_buttons = Column::new() - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push(Container::new(logo)) .push(Menu::Home.entry(active, menu_width)) .push(Menu::CreateSpendTx.entry(active, menu_width)) @@ -78,7 +78,7 @@ pub fn sidebar<'a>( .push(Menu::Transactions.entry(active, menu_width)) .push(Menu::Coins.entry(active, menu_width)) .push(Menu::Settings.entry(active, menu_width)) - .push(Space::with_height(10)), + .push(Space::new().height(10)), ) .height(Length::Shrink); @@ -96,10 +96,12 @@ pub fn dashboard<'a, T: Into>>( let content_cell = RefCell::new(Some(content.into())); responsive(move |size| { let sidebar_width = MenuWidth::from_pane_width(size.width); - let content = content_cell - .borrow_mut() - .take() - .unwrap_or_else(|| Space::new(Length::Fill, Length::Shrink).into()); + let content = content_cell.borrow_mut().take().unwrap_or_else(|| { + Space::new() + .width(Length::Fill) + .height(Length::Shrink) + .into() + }); Row::new() .push( sidebar(menu, cache, sidebar_width) @@ -111,14 +113,14 @@ pub fn dashboard<'a, T: Into>>( .push(warn(warning)) .push( Container::new(column![ - Space::with_height(25), + Space::new().height(25), Container::new( scrollable(row!( - Space::with_width(Length::FillPortion(1)), - column!(Space::with_height(Length::Fixed(150.0)), content) + Space::new().width(Length::FillPortion(1)), + column!(Space::new().height(Length::Fixed(150.0)), content) .width(Length::FillPortion(8)) .max_width(1500), - Space::with_width(Length::FillPortion(1)), + Space::new().width(Length::FillPortion(1)), )) .on_scroll(|w| Message::Scroll(w.absolute_offset().y)), ) diff --git a/liana-gui/src/app/view/psbt.rs b/liana-gui/src/app/view/psbt.rs index 34a1f57a5..53d19996e 100644 --- a/liana-gui/src/app/view/psbt.rs +++ b/liana-gui/src/app/view/psbt.rs @@ -113,7 +113,7 @@ pub fn psbt_view<'a>( .width(Length::Fill) } else { Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(None, "Save") .width(Length::Fixed(150.0)) @@ -125,7 +125,7 @@ pub fn psbt_view<'a>( ) .width(Length::Fill) }) - .push(Space::with_height(10)), + .push(Space::new().height(10)), ) } @@ -144,7 +144,7 @@ pub fn save_action<'a>(warning: Option<&Error>, saved: bool) -> Element<'a, Mess .push( Row::new() .spacing(10) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(button::secondary(None, "Ignore").on_press(Message::Close)) .push( button::primary(None, "Save") @@ -407,14 +407,14 @@ pub fn spend_overview_view<'a>( ), ) .push(signatures(tx, desc_info, key_aliases)) - .push(Space::with_height(5)) + .push(Space::new().height(5)) ) .style(theme::card::simple), ) .push_maybe(if tx.status == SpendStatus::Pending { Some( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(if tx.path_ready().is_none() { Some( button::primary(None, "Sign") @@ -607,7 +607,7 @@ pub fn path_view<'a>( } else { icon::circle_cross_icon().style(theme::text::secondary) }) - .push(Space::with_width(Length::Fixed(20.0))), + .push(Space::new().width(Length::Fixed(20.0))), ) .push( p1_regular(format!( @@ -1012,7 +1012,7 @@ fn change_view(output: &TxOut, network: Network) -> Element { .spacing(5) .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(amount(&output.value)), ) .push( @@ -1183,9 +1183,9 @@ pub fn update_spend_view<'a>( }) .warning("Please enter the correct base64 encoded PSBT") .size(P1_SIZE) - .padding(10), + .padding(10.0), ) - .push(Row::new().push(Space::with_width(Length::Fill)).push( + .push(Row::new().push(Space::new().width(Length::Fill)).push( if updated.valid && !updated.value.is_empty() && !processing { button::secondary(None, "Update") .on_press(Message::ImportSpend(ImportSpendMessage::Confirm)) diff --git a/liana-gui/src/app/view/psbts.rs b/liana-gui/src/app/view/psbts.rs index d6d9738a0..a1a664e3d 100644 --- a/liana-gui/src/app/view/psbts.rs +++ b/liana-gui/src/app/view/psbts.rs @@ -30,9 +30,9 @@ pub fn import_psbt_view<'a>( }) .warning("Please enter a base64 encoded PSBT") .size(P1_SIZE) - .padding(10), + .padding(10.0), ) - .push(Row::new().push(Space::with_width(Length::Fill)).push( + .push(Row::new().push(Space::new().width(Length::Fill)).push( if imported.valid && !imported.value.is_empty() && !processing { button::secondary(None, "Import") .on_press(Message::ImportSpend(ImportSpendMessage::Confirm)) diff --git a/liana-gui/src/app/view/receive.rs b/liana-gui/src/app/view/receive.rs index 5ae401056..3aa27c2d2 100644 --- a/liana-gui/src/app/view/receive.rs +++ b/liana-gui/src/app/view/receive.rs @@ -55,10 +55,10 @@ fn address_card<'a>( Container::new( scrollable( Column::new() - .push(Space::with_height(Length::Fixed(10.0))) + .push(Space::new().height(Length::Fixed(10.0))) .push(p2_regular(address).small().style(theme::text::secondary)) // Space between the address and the scrollbar - .push(Space::with_height(Length::Fixed(10.0))), + .push(Space::new().height(Length::Fixed(10.0))), ) .direction( scrollable::Direction::Horizontal( @@ -81,7 +81,7 @@ fn address_card<'a>( button::secondary(None, "Verify on hardware device") .on_press(Message::Select(row_index)), ) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(None, "Show QR Code") .on_press(Message::ShowQrCode(row_index)), @@ -196,7 +196,7 @@ pub fn receive<'a>( Container::new( scrollable( Column::new() - .push(Space::with_height(Length::Fixed(10.0))) + .push(Space::new().height(Length::Fixed(10.0))) .push( text( prev_labels @@ -208,7 +208,7 @@ pub fn receive<'a>( .style(theme::text::secondary), ) // Space between the label and the scrollbar - .push(Space::with_height(Length::Fixed(10.0))), + .push(Space::new().height(Length::Fixed(10.0))), ) .direction( scrollable::Direction::Horizontal( @@ -352,14 +352,14 @@ pub fn qr_modal<'a>(qr: &'a qr_code::Data, address: &'a String) -> Element<'a, M Column::new() .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( Container::new(QRCode::::new(qr).cell_size(8)) .padding(10), ) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ) - .push(Space::with_height(Length::Fixed(15.0))) + .push(Space::new().height(Length::Fixed(15.0))) .push(Container::new(text(address).size(15)).center_x(Length::Fill)) .width(Length::Fill) .max_width(400) diff --git a/liana-gui/src/app/view/recovery.rs b/liana-gui/src/app/view/recovery.rs index 532abba8f..12df2d5ac 100644 --- a/liana-gui/src/app/view/recovery.rs +++ b/liana-gui/src/app/view/recovery.rs @@ -42,7 +42,7 @@ pub fn recovery<'a>( Column::new() .push(Container::new(panel_title(Menu::Recovery.title())).width(Length::Fill)) .push(Container::new(text(INFO_TEXT))) - .push(Space::with_height(Length::Fixed(20.0))) + .push(Space::new().height(Length::Fixed(20.0))) .push( Container::new( Column::new() @@ -62,7 +62,7 @@ pub fn recovery<'a>( }) .width(Length::Fill), ) - .push_maybe((!no_recovery_paths).then_some(Space::with_height(20))) + .push_maybe((!no_recovery_paths).then_some(Space::new().height(20))) .push(Column::with_children(recovery_paths).spacing(20)), ) .style(theme::card::simple) @@ -73,7 +73,7 @@ pub fn recovery<'a>( } else { Some( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::primary(None, "Next") .on_press_maybe(selected_path.map(|_| Message::Next)) @@ -98,7 +98,7 @@ pub fn recovery_path_view<'a>( ) -> Element<'a, Message> { Row::new() .push( - checkbox("", selected) + checkbox(selected) .on_toggle(move |_| Message::CreateSpend(CreateSpendMessage::SelectPath(index))), ) .push( diff --git a/liana-gui/src/app/view/settings/general.rs b/liana-gui/src/app/view/settings/general.rs index 79fd0aec8..fe25b7aae 100644 --- a/liana-gui/src/app/view/settings/general.rs +++ b/liana-gui/src/app/view/settings/general.rs @@ -57,7 +57,7 @@ pub fn fiat_price<'a>( icon::warning_icon().color(color::ORANGE), tooltip::Position::Bottom, )) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( Toggler::new(new_price_setting.is_enabled) .on_toggle(|new_selection| FiatMessage::Enable(new_selection).into()) @@ -70,7 +70,7 @@ pub fn fiat_price<'a>( .spacing(20) .align_y(Alignment::Center) .push(text("Exchange rate source:").bold()) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( pick_list::pick_list( &ALL_PRICE_SOURCES[..], @@ -87,7 +87,7 @@ pub fn fiat_price<'a>( .spacing(20) .align_y(Alignment::Center) .push(text("Currency:").bold()) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( pick_list::pick_list( currencies_list, @@ -107,7 +107,7 @@ pub fn fiat_price<'a>( Row::new() .spacing(20) .align_y(Alignment::Center) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(text(s)) }), ), diff --git a/liana-gui/src/app/view/settings/mod.rs b/liana-gui/src/app/view/settings/mod.rs index 5565c476b..8df1400f9 100644 --- a/liana-gui/src/app/view/settings/mod.rs +++ b/liana-gui/src/app/view/settings/mod.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; use std::str::FromStr; use iced::alignment::{Horizontal, Vertical}; -use iced::widget::{container, Column, Rule}; +use iced::widget::{container, rule, Column}; use iced::{ alignment, widget::{radio, scrollable, tooltip as iced_tooltip, Space}, @@ -210,11 +210,11 @@ pub fn import_export<'a>(cache: &'a Cache, warning: Option<&'a Error>) -> Elemen let header = header("Import/Export", SettingsMessage::ImportExportSection); let description = Row::new() - .push(Space::with_width(15)) + .push(Space::new().width(15)) .push(text( "A collection of the export and import functions present in Liana.", )) - .push(Space::with_width(Length::Fill)); + .push(Space::new().width(Length::Fill)); let export_encrypted_descriptor = export_section( "Encrypted descriptor", @@ -259,11 +259,11 @@ pub fn import_export<'a>(cache: &'a Cache, warning: Option<&'a Error>) -> Elemen ); let separator = Row::new() - .push(Space::with_width(30)) + .push(Space::new().width(30)) .push(text("Other formats")) - .push(Space::with_width(15)) - .push(Rule::horizontal(2)) - .push(Space::with_width(30)) + .push(Space::new().width(15)) + .push(rule::horizontal(1)) + .push(Space::new().width(30)) .align_y(Vertical::Center); dashboard( @@ -304,9 +304,9 @@ pub fn about_section<'a>( .width(Length::Fill), ) .push(separation().width(Length::Fill)) - .push(Space::with_height(Length::Fixed(10.0))) + .push(Space::new().height(Length::Fixed(10.0))) .push( - Row::new().push(Space::with_width(Length::Fill)).push( + Row::new().push(Space::new().width(Length::Fill)).push( Column::new() .push(text(format!("liana-gui v{}", crate::VERSION))) .push_maybe( @@ -349,7 +349,7 @@ pub fn remote_backend_section<'a>( }) .warning("Email is invalid") .size(P1_SIZE) - .padding(10), + .padding(10.0), ) .push( Row::new() @@ -358,7 +358,7 @@ pub fn remote_backend_section<'a>( } else { None }) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(button::secondary(None, "Send invitation").on_press_maybe( if !processing && email_form.valid { Some(Message::Settings(SettingsMessage::RemoteBackendSettings( @@ -457,7 +457,7 @@ pub fn bitcoind_edit<'a>( ) .warning("Please enter a valid filesystem path") .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .spacing(5), RpcAuthType::UserPass => Column::new() @@ -469,7 +469,7 @@ pub fn bitcoind_edit<'a>( }) .warning("Please enter a valid user") .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .push( form::Form::new_trimmed("Password", &rpc_auth_vals.password, |value| { @@ -477,7 +477,7 @@ pub fn bitcoind_edit<'a>( }) .warning("Please enter a valid password") .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .spacing(10), ) @@ -492,7 +492,7 @@ pub fn bitcoind_edit<'a>( }) .warning("Please enter a valid address") .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .spacing(5), ); @@ -601,10 +601,10 @@ pub fn bitcoind<'a>( Container::new( scrollable( Column::new() - .push(Space::with_height(Length::Fixed(10.0))) + .push(Space::new().height(Length::Fixed(10.0))) .push(text(t).small()) // Space between the text and the scrollbar - .push(Space::with_height(Length::Fixed(10.0))), + .push(Space::new().height(Length::Fixed(10.0))), ) .direction(scrollable::Direction::Horizontal( scrollable::Scrollbar::new().width(2).scroller_width(2), @@ -614,7 +614,7 @@ pub fn bitcoind<'a>( .padding(10) .width(Length::FillPortion(3)), ) - .push(Space::with_width(10)) + .push(Space::new().width(10)) .push( Button::new(icon::clipboard_icon()) .style(theme::button::transparent_border) @@ -709,7 +709,7 @@ pub fn electrum_edit<'a>( }) .warning("Please enter a valid address") .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .push_maybe(checkbox) .push(text(electrum::ADDRESS_NOTES).size(P2_SIZE)) @@ -804,7 +804,7 @@ pub fn electrum<'a>( Row::new() .push(Container::new(text(k).bold().small()).width(Length::Fill)) .push(text(v.clone()).small()) - .push(Space::with_width(10)) + .push(Space::new().width(10)) .push( Button::new(icon::clipboard_icon()) .style(theme::button::transparent_border) @@ -906,7 +906,7 @@ pub fn rescan<'a>( Container::new( Column::new() .width(Length::Fill) - .push(ProgressBar::new(0.0..=1.0, p as f32).width(Length::Fill)) + .push(ProgressBar::new(0.0..=1.0, p as f32).length(Length::Fill)) .push(text(format!("Rescanning...{:.2}%", p * 100.0))), ) } else { @@ -921,7 +921,7 @@ pub fn rescan<'a>( SettingsEditMessage::FieldEdited("rescan_year", value) }) .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .push(text("Month:").bold().small()) .push( @@ -929,7 +929,7 @@ pub fn rescan<'a>( SettingsEditMessage::FieldEdited("rescan_month", value) }) .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .push(text("Day:").bold().small()) .push( @@ -937,7 +937,7 @@ pub fn rescan<'a>( SettingsEditMessage::FieldEdited("rescan_day", value) }) .size(P1_SIZE) - .padding(5), + .padding(5.0), ) .align_y(Alignment::Center) .spacing(10), @@ -1045,7 +1045,7 @@ pub fn wallet_settings<'a>( scrollable( Column::new() .push(text(descriptor.to_string()).small()) - .push(Space::with_height(Length::Fixed(5.0))), + .push(Space::new().height(Length::Fixed(5.0))), ) .direction(scrollable::Direction::Horizontal( scrollable::Scrollbar::new().width(5).scroller_width(5), @@ -1078,7 +1078,7 @@ pub fn wallet_settings<'a>( }) .warning("Please enter alias that is not too long") .size(P1_SIZE) - .padding(10), + .padding(10.0), ) .push(text("Fingerprint aliases:").bold()) .push(keys_aliases.iter().fold( @@ -1098,7 +1098,7 @@ pub fn wallet_settings<'a>( }) .warning("Please enter correct alias") .size(P1_SIZE) - .padding(10), + .padding(10.0), ), ) }, @@ -1106,7 +1106,7 @@ pub fn wallet_settings<'a>( .push( Row::new() .align_y(Alignment::Center) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(if updated { Some( Row::new() diff --git a/liana-gui/src/app/view/spend/mod.rs b/liana-gui/src/app/view/spend/mod.rs index 68912de8a..2dd96e26d 100644 --- a/liana-gui/src/app/view/spend/mod.rs +++ b/liana-gui/src/app/view/spend/mod.rs @@ -104,7 +104,7 @@ pub fn spend_view<'a>( .width(150) .on_press_maybe((!currently_signing).then_some(Message::Previous)), ) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(button::secondary(None, "Save").width(150).on_press_maybe( (!currently_signing).then_some(Message::Spend(SpendTxMessage::Save)), )) @@ -169,8 +169,8 @@ pub fn create_spend_tx<'a>( Message::CreateSpend(CreateSpendMessage::BatchLabelEdited(s)) }) .warning("Invalid label length, cannot be superior to 100") - .size(30) - .padding(10), + .size(30.0) + .padding(10.0), ); // Recipients @@ -189,7 +189,7 @@ pub fn create_spend_tx<'a>( ); let add_payment_row = Row::new() .push_maybe(duplicates_warning) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(add_payment_btn); // Fee-rate row @@ -199,7 +199,7 @@ pub fn create_spend_tx<'a>( }) .warning("Feerate must be an integer less than or equal to 1000 sats/vbyte") .size(P1_SIZE) - .padding(10), + .padding(10.0), ) .width(150); let fee_amount = fee_amount.map(|fee| { @@ -335,7 +335,7 @@ pub fn create_spend_tx<'a>( .spacing(20) .align_y(Alignment::Center) .push_maybe(previous) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(clear) .push(next); let content = Column::new() @@ -346,7 +346,7 @@ pub fn create_spend_tx<'a>( .push(fee_rate_row) .push(coin_selection) .push(bottom_row) - .push(Space::with_height(Length::Fixed(20.0))) + .push(Space::new().height(Length::Fixed(20.0))) .spacing(20); dashboard( @@ -382,7 +382,7 @@ pub fn recipient_view<'a>( // Recipient for recovery cannot be deleted. let header = (!is_recovery).then_some( - Row::new().push(Space::with_width(Length::Fill)).push( + Row::new().push(Space::new().width(Length::Fill)).push( Button::new(icon::cross_icon()) .style(theme::button::transparent) .on_press(CreateSpendMessage::DeleteRecipient(index)) @@ -405,7 +405,7 @@ pub fn recipient_view<'a>( }) .warning("Invalid address (maybe it is for another network?)") .size(P1_SIZE) - .padding(10), + .padding(10.0), ); let label_row = Row::new() @@ -423,7 +423,7 @@ pub fn recipient_view<'a>( }) .warning("Label length is too long (> 100 char)") .size(P1_SIZE) - .padding(10), + .padding(10.0), ); // Amount row @@ -443,7 +443,7 @@ pub fn recipient_view<'a>( }) .warning("Invalid amount. (Note amounts lower than 0.000005 BTC are invalid.)") .size(P1_SIZE) - .padding(10) + .padding(10.0) .into_container() }; @@ -451,12 +451,12 @@ pub fn recipient_view<'a>( Row::new() .align_y(Alignment::Center) .spacing(5) - .push(Space::with_width(20)) // add some space between BTC and fiat amounts + .push(Space::new().width(20)) // add some space between BTC and fiat amounts .push_maybe( (!is_max_selected || btc_amt.is_some()) .then_some(p1_bold(format!("~{}", conv.currency()))), ) - .push(Space::with_width(5)) + .push(Space::new().width(5)) .push_maybe(if is_max_selected { // fiat is processed from btc btc_amt.map(|a| { @@ -487,7 +487,7 @@ pub fn recipient_view<'a>( move |msg| CreateSpendMessage::RecipientFiatAmountEdited(index, msg, conv), ) .size(P1_SIZE) - .padding(10) + .padding(10.0) .into_container(), ) }) @@ -498,12 +498,13 @@ pub fn recipient_view<'a>( tooltip::Position::Bottom, )), ) - .push(Space::with_width(10)) + .push(Space::new().width(10)) }); // The MAX option cannot be edited for recovery recipients. let max = (!is_recovery).then_some(tooltip::Tooltip::new( - checkbox("MAX", is_max_selected) + checkbox(is_max_selected) + .label("MAX") .on_toggle(move |_| CreateSpendMessage::SendMaxToRecipient(index)), // Add spaces at end so that text is padded at screen edge. "Total amount remaining after paying fee and any other recipients ", @@ -519,7 +520,7 @@ pub fn recipient_view<'a>( .push_maybe(max) .width(Length::Fill); // Show dust warning, if any, or otherwise any amount warning. - let amount_warning_row = Row::new().push(Space::with_width(20)).push_maybe( + let amount_warning_row = Row::new().push(Space::new().width(20)).push_maybe( dust_warning .as_ref() .map(|w| caption(w).color(color::RED)) @@ -557,7 +558,7 @@ fn coin_list_view<'a>( .push( Row::new() .push( - checkbox("", selected).on_toggle(move |_| { + checkbox(selected).on_toggle(move |_| { Message::CreateSpend(CreateSpendMessage::SelectCoin(i)) }), ) @@ -595,7 +596,7 @@ fn coin_list_view<'a>( ) .push(amount(&coin.amount)) // give some space for the scroll bar without using padding - .push(Space::with_width(Length::Fixed(0.0))) + .push(Space::new().width(Length::Fixed(0.0))) .align_y(Alignment::Center) .spacing(20) .into() diff --git a/liana-gui/src/app/view/transactions.rs b/liana-gui/src/app/view/transactions.rs index edc87cb24..d6e74eded 100644 --- a/liana-gui/src/app/view/transactions.rs +++ b/liana-gui/src/app/view/transactions.rs @@ -43,7 +43,7 @@ pub fn transactions_view<'a>( .push( Row::new() .push(Container::new(panel_title(Menu::Transactions.title()))) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(Some(icon::backup_icon()), "Export") .on_press(ImportExportMessage::Open.into()), @@ -269,7 +269,7 @@ pub fn create_rbf_modal<'a>( form::Form::new_disabled("", feerate) } .size(P1_SIZE) - .padding(10), + .padding(10.0), ) .width(Length::Fill), ) diff --git a/liana-gui/src/download.rs b/liana-gui/src/download.rs index e573dfd2a..293939338 100644 --- a/liana-gui/src/download.rs +++ b/liana-gui/src/download.rs @@ -3,7 +3,6 @@ // and to keep track of any download errors. use iced::futures::{SinkExt, Stream, StreamExt}; use iced::stream::try_channel; -use iced::Subscription; use std::hash::Hash; use std::sync::Arc; @@ -13,41 +12,44 @@ pub fn file( id: I, url: T, ) -> iced::Subscription<(I, Result)> { - Subscription::run_with_id( + crate::utils::subscription::run_with_id( id, download(url.to_string()).map(move |progress| (id, progress)), ) } fn download(url: String) -> impl Stream> { - try_channel(100, move |mut output| async move { - let response = reqwest::get(&url).await?; - let total = response.content_length(); + try_channel( + 100, + move |mut output: iced::futures::channel::mpsc::Sender| async move { + let response = reqwest::get(&url).await?; + let total = response.content_length(); - let _ = output.send(Progress::Downloading(0.0)).await; + let _ = output.send(Progress::Downloading(0.0)).await; - let mut byte_stream = response.bytes_stream(); - let mut downloaded = 0; - let mut bytes = Vec::new(); + let mut byte_stream = response.bytes_stream(); + let mut downloaded = 0; + let mut bytes = Vec::new(); - while let Some(next_bytes) = byte_stream.next().await { - let chunk = next_bytes?; - downloaded += chunk.len(); - bytes.append(&mut chunk.to_vec()); + while let Some(next_bytes) = byte_stream.next().await { + let chunk = next_bytes?; + downloaded += chunk.len(); + bytes.append(&mut chunk.to_vec()); - if let Some(total) = total { - let _ = output - .send(Progress::Downloading( - 100.0 * downloaded as f32 / total as f32, - )) - .await; + if let Some(total) = total { + let _ = output + .send(Progress::Downloading( + 100.0 * downloaded as f32 / total as f32, + )) + .await; + } } - } - let _ = output.send(Progress::Finished(bytes)).await; + let _ = output.send(Progress::Finished(bytes)).await; - Ok(()) - }) + Ok(()) + }, + ) } #[derive(Debug, Clone)] diff --git a/liana-gui/src/export.rs b/liana-gui/src/export.rs index 95fb7e366..5e04082a4 100644 --- a/liana-gui/src/export.rs +++ b/liana-gui/src/export.rs @@ -374,62 +374,65 @@ pub fn export_subscription( path: PathBuf, export_type: ImportExportType, ) -> impl Stream { - iced::stream::channel(100, move |mut output| async move { - let mut state = Export::new(daemon, Box::new(path), export_type); - loop { - match state.state() { - Status::Init => { - state.start().await; - } - Status::Stopped => { - break; - } - Status::Running => {} - } - let msg = state.receiver.try_recv(); - let disconnected = match msg { - Ok(m) => { - if let Err(e) = output.send(m).await { - tracing::error!("export_subscription() fail to send message: {}", e); + iced::stream::channel( + 100, + move |mut output: iced::futures::channel::mpsc::Sender| async move { + let mut state = Export::new(daemon, Box::new(path), export_type); + loop { + match state.state() { + Status::Init => { + state.start().await; } - continue; + Status::Stopped => { + break; + } + Status::Running => {} } - Err(e) => match e { - tokio::sync::mpsc::error::TryRecvError::Empty => false, - tokio::sync::mpsc::error::TryRecvError::Disconnected => true, - }, - }; - - let handle = match state.handle.take() { - Some(h) => h, - None => { - if let Err(e) = output.send(Progress::Error(Error::HandleLost)).await { + let msg = state.receiver.try_recv(); + let disconnected = match msg { + Ok(m) => { + if let Err(e) = output.send(m).await { + tracing::error!("export_subscription() fail to send message: {}", e); + } + continue; + } + Err(e) => match e { + tokio::sync::mpsc::error::TryRecvError::Empty => false, + tokio::sync::mpsc::error::TryRecvError::Disconnected => true, + }, + }; + + let handle = match state.handle.take() { + Some(h) => h, + None => { + if let Err(e) = output.send(Progress::Error(Error::HandleLost)).await { + tracing::error!("export_subscription() fail to send message: {}", e); + } + continue; + } + }; + let msg = { + let h = handle.lock().expect("should not fail"); + if h.is_finished() { + Some(Progress::Finished) + } else if disconnected { + Some(Progress::Error(Error::ChannelLost)) + } else { + None + } + }; + if let Some(msg) = msg { + if let Err(e) = output.send(msg).await { tracing::error!("export_subscription() fail to send message: {}", e); } continue; } - }; - let msg = { - let h = handle.lock().expect("should not fail"); - if h.is_finished() { - Some(Progress::Finished) - } else if disconnected { - Some(Progress::Error(Error::ChannelLost)) - } else { - None - } - }; - if let Some(msg) = msg { - if let Err(e) = output.send(msg).await { - tracing::error!("export_subscription() fail to send message: {}", e); - } - continue; - } - state.handle = Some(handle); + state.handle = Some(handle); - sleep(time::Duration::from_millis(100)).await; - } - }) + sleep(time::Duration::from_millis(100)).await; + } + }, + ) } pub async fn export_transactions( diff --git a/liana-gui/src/gui/mod.rs b/liana-gui/src/gui/mod.rs index dfe4c96ac..a2098c9ce 100644 --- a/liana-gui/src/gui/mod.rs +++ b/liana-gui/src/gui/mod.rs @@ -1,7 +1,7 @@ use iced::{ event::{self, Event}, keyboard, - widget::{focus_next, focus_previous, pane_grid}, + widget::{operation::focus_next, operation::focus_previous, pane_grid}, Length, Size, Subscription, Task, }; use iced_runtime::window; @@ -145,7 +145,7 @@ where tracing::warn!("Error while setting error: {}", e); } let mut cmds = vec![ - window::get_oldest().map(Message::Window), + window::oldest().map(Message::Window), Task::perform(ctrl_c(), |_| Message::CtrlC), ]; let (pane, cmd) = pane::Pane::::new(&config); @@ -247,7 +247,7 @@ where tracing::error!("Failed to update the window config: {e}"); } } - iced::window::get_latest().and_then(iced::window::close) + iced::window::latest().and_then(iced::window::close) } Message::KeyPressed(Key::Tab(shift)) => { log::debug!("Tab pressed!"); @@ -349,7 +349,7 @@ where } } if !self.panes.iter().any(|(_, p)| !p.tabs.is_empty()) { - return iced::window::get_latest().and_then(iced::window::close); + return iced::window::latest().and_then(iced::window::close); } Task::none() } @@ -651,7 +651,7 @@ where .into() } - pub fn scale_factor(&self) -> f64 { + pub fn scale_factor(&self) -> f32 { 1.0 } } diff --git a/liana-gui/src/hw.rs b/liana-gui/src/hw.rs index a633c10c3..98545af7b 100644 --- a/liana-gui/src/hw.rs +++ b/liana-gui/src/hw.rs @@ -314,7 +314,7 @@ impl HardwareWallets { } pub fn refresh(&self) -> iced::Subscription { - iced::Subscription::run_with_id( + crate::utils::subscription::run_with_id( format!("refresh-{}", self.network), refresh(State { network: self.network, @@ -384,85 +384,130 @@ struct State { } fn refresh(mut state: State) -> impl Stream { - iced::stream::channel(100, move |mut output| async move { - loop { - let api = if let Some(api) = &mut state.api { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - if let Err(e) = api.refresh_devices() { - let _ = output - .send(HardwareWalletMessage::Error(e.to_string())) - .await; - continue; - }; - api - } else { - match ledger::HidApi::new() { - Ok(api) => { - state.api = Some(api); - state.api.as_mut().unwrap() - } - Err(e) => { + iced::stream::channel( + 100, + move |mut output: iced::futures::channel::mpsc::Sender| async move { + loop { + let api = if let Some(api) = &mut state.api { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + if let Err(e) = api.refresh_devices() { let _ = output .send(HardwareWalletMessage::Error(e.to_string())) .await; continue; + }; + api + } else { + match ledger::HidApi::new() { + Ok(api) => { + state.api = Some(api); + state.api.as_mut().unwrap() + } + Err(e) => { + let _ = output + .send(HardwareWalletMessage::Error(e.to_string())) + .await; + continue; + } } - } - }; + }; - let mut hws: Vec = Vec::new(); - let mut still: Vec = Vec::new(); - match specter::SpecterSimulator::try_connect().await { - Ok(device) => { - let id = "specter-simulator".to_string(); - if state.connected_supported_hws.contains(&id) { - still.push(id); - } else { - match HardwareWallet::new(id, Arc::new(device), Some(&state.keys_aliases)) + let mut hws: Vec = Vec::new(); + let mut still: Vec = Vec::new(); + match specter::SpecterSimulator::try_connect().await { + Ok(device) => { + let id = "specter-simulator".to_string(); + if state.connected_supported_hws.contains(&id) { + still.push(id); + } else { + match HardwareWallet::new( + id, + Arc::new(device), + Some(&state.keys_aliases), + ) .await - { - Ok(hw) => hws.push(hw), - Err(e) => { - debug!("{}", e); + { + Ok(hw) => hws.push(hw), + Err(e) => { + debug!("{}", e); + } } } } + Err(HWIError::DeviceNotFound) => {} + Err(e) => { + debug!("{}", e); + } } - Err(HWIError::DeviceNotFound) => {} - Err(e) => { - debug!("{}", e); - } - } - match specter::SerialTransport::enumerate_potential_ports() { - Ok(ports) => { - for port in ports { - let id = format!("specter-{}", port); - if state.connected_supported_hws.contains(&id) { - still.push(id); - } else { - match specter::Specter::::new(port.clone()) { - Err(e) => { - warn!("{}", e); + match specter::SerialTransport::enumerate_potential_ports() { + Ok(ports) => { + for port in ports { + let id = format!("specter-{}", port); + if state.connected_supported_hws.contains(&id) { + still.push(id); + } else { + match specter::Specter::::new( + port.clone(), + ) { + Err(e) => { + warn!("{}", e); + } + Ok(device) => { + if tokio::time::timeout( + std::time::Duration::from_millis(500), + device.fingerprint(), + ) + .await + .is_ok() + { + match HardwareWallet::new( + id, + Arc::new(device), + Some(&state.keys_aliases), + ) + .await + { + Ok(hw) => hws.push(hw), + Err(e) => { + debug!("{}", e); + } + } + } + } } - Ok(device) => { - if tokio::time::timeout( - std::time::Duration::from_millis(500), - device.fingerprint(), - ) - .await - .is_ok() - { - match HardwareWallet::new( + } + } + } + Err(e) => warn!("Error while listing specter wallets: {}", e), + } + + match jade::SerialTransport::enumerate_potential_ports() { + Ok(ports) => { + for port in ports { + let id = format!("jade-{}", port); + if state.connected_supported_hws.contains(&id) { + still.push(id); + } else { + match jade::SerialTransport::new(port) { + Err(e) => { + warn!("{:?}", e); + } + Ok(device) => { + match handle_jade_device( id, - Arc::new(device), + state.network, + Jade::new(device).with_network(state.network), + state.wallet.as_ref().map(|w| w.as_ref()), Some(&state.keys_aliases), ) .await { - Ok(hw) => hws.push(hw), + Ok(hw) => { + hws.push(hw); + } Err(e) => { - debug!("{}", e); + warn!("{:?}", e); } } } @@ -470,53 +515,154 @@ fn refresh(mut state: State) -> impl Stream { } } } + Err(e) => warn!("Error while listing jade devices: {}", e), } - Err(e) => warn!("Error while listing specter wallets: {}", e), - } - match jade::SerialTransport::enumerate_potential_ports() { - Ok(ports) => { - for port in ports { - let id = format!("jade-{}", port); + match ledger::LedgerSimulator::try_connect().await { + Ok(device) => { + let id = "ledger-simulator".to_string(); if state.connected_supported_hws.contains(&id) { still.push(id); } else { - match jade::SerialTransport::new(port) { + match handle_ledger_device( + id, + device, + state.wallet.as_ref().map(|w| w.as_ref()), + &state.keys_aliases, + ) + .await + { + Ok(hw) => { + hws.push(hw); + } Err(e) => { warn!("{:?}", e); } - Ok(device) => { - match handle_jade_device( - id, - state.network, - Jade::new(device).with_network(state.network), - state.wallet.as_ref().map(|w| w.as_ref()), - Some(&state.keys_aliases), - ) - .await - { - Ok(hw) => { - hws.push(hw); - } - Err(e) => { - warn!("{:?}", e); + } + } + } + Err(HWIError::DeviceNotFound) => {} + Err(e) => { + debug!("{}", e); + } + } + + for device_info in api.device_list() { + if async_hwi::bitbox::is_bitbox02(device_info) { + let id = format!( + "bitbox-{:?}-{}-{}", + device_info.path(), + device_info.vendor_id(), + device_info.product_id() + ); + if state.connected_supported_hws.contains(&id) { + still.push(id); + continue; + } + if let Ok(device) = device_info.open_device(api) { + if let Ok(device) = PairingBitbox02::connect( + device, + Some(Box::new(settings::global::PersistedBitboxNoiseConfig::new( + &state.datadir_path, + ))), + ) + .await + { + hws.push(HardwareWallet::Locked { + id, + kind: DeviceKind::BitBox02, + pairing_code: device + .pairing_code() + .map(|s| s.replace('\n', " ")), + device: Arc::new(Mutex::new(Some(LockedDevice::BitBox02( + Box::new(device), + )))), + }); + } + } + } + if device_info.vendor_id() == coldcard::api::COINKITE_VID + && device_info.product_id() == coldcard::api::CKCC_PID + { + let id = format!( + "coldcard-{:?}-{}-{}", + device_info.path(), + device_info.vendor_id(), + device_info.product_id() + ); + if state.connected_supported_hws.contains(&id) { + still.push(id); + continue; + } + if let Some(sn) = device_info.serial_number() { + if let Ok((cc, _)) = + coldcard::api::Coldcard::open(AsRefWrap { inner: api }, sn, None) + { + let device: Arc = + if let Some(wallet) = &state.wallet { + coldcard::Coldcard::from(cc) + .with_wallet_name(wallet.name.clone()) + .into() + } else { + coldcard::Coldcard::from(cc).into() + }; + match ( + device.get_master_fingerprint().await, + device.get_version().await, + ) { + (Ok(fingerprint), Ok(version)) => { + if version + >= (Version { + major: 6, + minor: 2, + patch: 1, + prerelease: None, + }) + { + hws.push(HardwareWallet::Supported { + id, + device, + kind: DeviceKind::Coldcard, + fingerprint, + version: Some(version), + registered: None, + alias: state + .keys_aliases + .get(&fingerprint) + .cloned(), + }); + } else { + hws.push(HardwareWallet::Unsupported { + id, + kind: device.device_kind(), + version: Some(version), + reason: UnsupportedReason::Version { + minimal_supported_version: + "Edge firmware v6.2.1".to_string(), + }, + }); } } + _ => tracing::error!("Failed to connect to coldcard"), } } } } } - Err(e) => warn!("Error while listing jade devices: {}", e), - } - - match ledger::LedgerSimulator::try_connect().await { - Ok(device) => { - let id = "ledger-simulator".to_string(); + for detected in ledger::Ledger::::enumerate(api) { + let id = format!( + "ledger-{:?}-{}-{}", + detected.path(), + detected.vendor_id(), + detected.product_id() + ); if state.connected_supported_hws.contains(&id) { still.push(id); - } else { - match handle_ledger_device( + continue; + } + + match ledger::Ledger::::connect(api, detected) { + Ok(device) => match handle_ledger_device( id, device, state.wallet.as_ref().map(|w| w.as_ref()), @@ -530,187 +676,55 @@ fn refresh(mut state: State) -> impl Stream { Err(e) => { warn!("{:?}", e); } + }, + Err(HWIError::DeviceNotFound) => {} + Err(e) => { + debug!("{}", e); } } } - Err(HWIError::DeviceNotFound) => {} - Err(e) => { - debug!("{}", e); - } - } - for device_info in api.device_list() { - if async_hwi::bitbox::is_bitbox02(device_info) { - let id = format!( - "bitbox-{:?}-{}-{}", - device_info.path(), - device_info.vendor_id(), - device_info.product_id() - ); - if state.connected_supported_hws.contains(&id) { - still.push(id); - continue; - } - if let Ok(device) = device_info.open_device(api) { - if let Ok(device) = PairingBitbox02::connect( - device, - Some(Box::new(settings::global::PersistedBitboxNoiseConfig::new( - &state.datadir_path, - ))), - ) - .await - { - hws.push(HardwareWallet::Locked { - id, - kind: DeviceKind::BitBox02, - pairing_code: device.pairing_code().map(|s| s.replace('\n', " ")), - device: Arc::new(Mutex::new(Some(LockedDevice::BitBox02( - Box::new(device), - )))), - }); - } - } - } - if device_info.vendor_id() == coldcard::api::COINKITE_VID - && device_info.product_id() == coldcard::api::CKCC_PID - { - let id = format!( - "coldcard-{:?}-{}-{}", - device_info.path(), - device_info.vendor_id(), - device_info.product_id() - ); - if state.connected_supported_hws.contains(&id) { - still.push(id); - continue; - } - if let Some(sn) = device_info.serial_number() { - if let Ok((cc, _)) = - coldcard::api::Coldcard::open(AsRefWrap { inner: api }, sn, None) + if let Some(wallet) = &state.wallet { + let wallet_keys = wallet.descriptor_keys(); + for hw in &mut hws { + if let HardwareWallet::Supported { + fingerprint, + id, + kind, + version, + .. + } = &hw { - let device: Arc = - if let Some(wallet) = &state.wallet { - coldcard::Coldcard::from(cc) - .with_wallet_name(wallet.name.clone()) - .into() - } else { - coldcard::Coldcard::from(cc).into() + if !wallet_keys.contains(fingerprint) { + *hw = HardwareWallet::Unsupported { + id: id.clone(), + kind: *kind, + version: version.clone(), + reason: UnsupportedReason::NotPartOfWallet(*fingerprint), }; - match ( - device.get_master_fingerprint().await, - device.get_version().await, - ) { - (Ok(fingerprint), Ok(version)) => { - if version - >= (Version { - major: 6, - minor: 2, - patch: 1, - prerelease: None, - }) - { - hws.push(HardwareWallet::Supported { - id, - device, - kind: DeviceKind::Coldcard, - fingerprint, - version: Some(version), - registered: None, - alias: state.keys_aliases.get(&fingerprint).cloned(), - }); - } else { - hws.push(HardwareWallet::Unsupported { - id, - kind: device.device_kind(), - version: Some(version), - reason: UnsupportedReason::Version { - minimal_supported_version: "Edge firmware v6.2.1" - .to_string(), - }, - }); - } - } - _ => tracing::error!("Failed to connect to coldcard"), } } } } - } - for detected in ledger::Ledger::::enumerate(api) { - let id = format!( - "ledger-{:?}-{}-{}", - detected.path(), - detected.vendor_id(), - detected.product_id() - ); - if state.connected_supported_hws.contains(&id) { - still.push(id); - continue; - } - - match ledger::Ledger::::connect(api, detected) { - Ok(device) => match handle_ledger_device( - id, - device, - state.wallet.as_ref().map(|w| w.as_ref()), - &state.keys_aliases, - ) - .await - { - Ok(hw) => { - hws.push(hw); - } - Err(e) => { - warn!("{:?}", e); - } - }, - Err(HWIError::DeviceNotFound) => {} - Err(e) => { - debug!("{}", e); - } - } - } - if let Some(wallet) = &state.wallet { - let wallet_keys = wallet.descriptor_keys(); - for hw in &mut hws { - if let HardwareWallet::Supported { - fingerprint, - id, - kind, - version, - .. - } = &hw - { - if !wallet_keys.contains(fingerprint) { - *hw = HardwareWallet::Unsupported { - id: id.clone(), - kind: *kind, - version: version.clone(), - reason: UnsupportedReason::NotPartOfWallet(*fingerprint), - }; - } - } - } + state.connected_supported_hws = still + .iter() + .chain(hws.iter().filter_map(|hw| match hw { + HardwareWallet::Locked { id, .. } => Some(id), + HardwareWallet::Supported { id, .. } => Some(id), + HardwareWallet::Unsupported { .. } => None, + })) + .cloned() + .collect(); + let _ = output + .send(HardwareWalletMessage::List(ConnectedList { + new: hws, + still, + })) + .await; } - - state.connected_supported_hws = still - .iter() - .chain(hws.iter().filter_map(|hw| match hw { - HardwareWallet::Locked { id, .. } => Some(id), - HardwareWallet::Supported { id, .. } => Some(id), - HardwareWallet::Unsupported { .. } => None, - })) - .cloned() - .collect(); - let _ = output - .send(HardwareWalletMessage::List(ConnectedList { - new: hws, - still, - })) - .await; - } - }) + }, + ) } async fn handle_ledger_device<'a, T: async_hwi::ledger::Transport + Sync + Send + 'static>( diff --git a/liana-gui/src/installer/decrypt.rs b/liana-gui/src/installer/decrypt.rs index 31a5e9758..6b1a96476 100644 --- a/liana-gui/src/installer/decrypt.rs +++ b/liana-gui/src/installer/decrypt.rs @@ -505,17 +505,17 @@ fn invalid_content(hint: &str) -> Container<'_, installer::Message> { Container::new( Column::new() .spacing(5) - .push(Space::with_height(Length::Fill)) + .push(Space::new().height(Length::Fill)) .push( row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), icon::warning_icon().size(250), - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), ] .align_y(alignment::Vertical::Center), ) .push(text::text(hint)) - .push(Space::with_height(Length::Fill)), + .push(Space::new().height(Length::Fill)), ) } @@ -542,10 +542,10 @@ fn widget_signing_device( let designation = column![text::p1_bold(name), text::p1_regular(fg)].align_x(alignment::Horizontal::Center); let row = row![ - Space::with_width(5), + Space::new().width(5), designation, message, - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ] .align_y(alignment::Vertical::Center) .spacing(10); @@ -595,7 +595,7 @@ fn valid_content(state: &DecryptModal) -> Container<'static, installer::Message> for d in devices { col = col.push(d); } - col = col.push(Space::with_height(10)).push(options_btn); + col = col.push(Space::new().height(10)).push(options_btn); if state.show_options { col = col.push(optional_content(state)); } @@ -649,13 +649,13 @@ fn optional_content(state: &DecryptModal) -> Container<'static, installer::Messa let col = column![ airgap_hint, - Space::with_height(modal::V_SPACING), + Space::new().height(modal::V_SPACING), import, - Space::with_height(modal::V_SPACING), + Space::new().height(modal::V_SPACING), xpub, - Space::with_height(modal::V_SPACING), + Space::new().height(modal::V_SPACING), mnemonic, - Space::with_height(modal::V_SPACING), + Space::new().height(modal::V_SPACING), ]; Container::new(col) @@ -681,17 +681,18 @@ pub fn mnemonic_input_button<'a>( } else { form::Form::new_disabled(input_placeholder, input_value) } - .padding(10); + .padding(10.0); let paste = Button::new(icon::paste_icon().color(color::BLACK)).on_press(paste_message); if collapsed { let line = Row::new().push(form).push(paste).spacing(V_SPACING); - let check_box = - CheckBox::new(disclaimer, ack).on_toggle(|ack| Decrypt::MnemonicAck(ack).into()); + let check_box = CheckBox::new(ack) + .label(disclaimer) + .on_toggle(|ack| Decrypt::MnemonicAck(ack).into()); let col = Column::new() .push(row![ text::p1_regular(label).color(color::WHITE), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]) .push(line); let content = if ack { diff --git a/liana-gui/src/installer/step/descriptor/editor/key.rs b/liana-gui/src/installer/step/descriptor/editor/key.rs index d2685748d..1535e0b75 100644 --- a/liana-gui/src/installer/step/descriptor/editor/key.rs +++ b/liana-gui/src/installer/step/descriptor/editor/key.rs @@ -31,7 +31,7 @@ use liana_ui::{ tooltip, }, icon, theme, - widget::{Container, Element}, + widget::{ColumnExt, Container, Element, RowExt}, }; use crate::{ @@ -1017,9 +1017,9 @@ impl SelectKeySource { } if hws.is_empty() { col = col.push(row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), p1_regular("- No other sources detected -"), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]) } col.into() @@ -1356,12 +1356,12 @@ where Alias: 'static + Fn(String) -> Message, { let pick_account = pick_account - .map(|pick_account| row![pick_account, Space::with_width(Length::Fill)].spacing(5)); + .map(|pick_account| row![pick_account, Space::new().width(Length::Fill)].spacing(5)); let info = "Switch account if you already uses the same hardware in other configurations"; let error = error.clone().map(|e| p1_regular(e).color(color::ORANGE)); - let spacer = replace_message.is_some().then(|| Space::with_width(10)); + let spacer = replace_message.is_some().then(|| Space::new().width(10)); let replace_btn = replace_message.map(|m| { let mut btn = button::secondary(None, "Replace"); if alias.valid { @@ -1372,13 +1372,13 @@ where let btn_row = if error.is_none() { Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(replace_btn) .push_maybe(spacer) .push(button::primary(None, "Apply").on_press_maybe(apply_msg)) } else if let Some(retry_msg) = retry_msg { row![ - Space::with_width(Length::Fill), + Space::new().width(Length::Fill), button::primary(None, "Retry").on_press(retry_msg), button::secondary(None, "Apply") ] @@ -1386,7 +1386,7 @@ where .align_y(Vertical::Center) } else { Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(replace_btn) .push_maybe(spacer) .push(button::primary(None, "Apply")) @@ -1396,17 +1396,17 @@ where .push(header) .push(row![ p1_bold("Key name (alias):"), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]) .push(row![ p1_regular("Give this key a friendly name. It will help you identify it later:"), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]) .push( - container(form::Form::new("E.g. My Hardware Wallet", alias, alias_msg).padding(10)) + container(form::Form::new("E.g. My Hardware Wallet", alias, alias_msg).padding(10.0)) .width(300), ) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push_maybe(if pick_account.is_some() { Some(row![p1_bold("Key path account:"), tooltip(info)].align_y(Vertical::Center)) } else { diff --git a/liana-gui/src/installer/view/editor/mod.rs b/liana-gui/src/installer/view/editor/mod.rs index a7ae40eb4..2d989654d 100644 --- a/liana-gui/src/installer/view/editor/mod.rs +++ b/liana-gui/src/installer/view/editor/mod.rs @@ -65,7 +65,7 @@ pub fn define_descriptor_advanced_settings<'a>(use_taproot: bool) -> Element<'a, container( Column::new() .spacing(20) - .push(Space::with_height(0)) + .push(Space::new().height(0)) .push(separation().width(500)) .push(Row::new().push(col_wallet)) .push_maybe(if use_taproot { @@ -93,7 +93,7 @@ pub fn path( Container::new( Column::new() .spacing(10) - .push_maybe(title.map(|t| Row::new().push(Space::with_width(10)).push(p1_bold(t)))) + .push_maybe(title.map(|t| Row::new().push(Space::new().width(10)).push(p1_bold(t)))) .push(defined_sequence(sequence, warning)) .push( Column::new() diff --git a/liana-gui/src/installer/view/editor/template/custom.rs b/liana-gui/src/installer/view/editor/template/custom.rs index af34b6243..bdb5c904a 100644 --- a/liana-gui/src/installer/view/editor/template/custom.rs +++ b/liana-gui/src/installer/view/editor/template/custom.rs @@ -45,8 +45,8 @@ pub fn custom_template_description(progress: (usize, usize)) -> Element<'static, .align_x(alignment::Horizontal::Left) ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push(image::custom_template_description().width(Length::Fill)) - .push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) - .push(Space::with_height(50.0)) + .push(Row::new().push(Space::new().width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) + .push(Space::new().height(50.0)) .spacing(20), true, Some(Message::Previous), @@ -253,7 +253,7 @@ pub fn custom_template<'a>( Message::DefineDescriptor(message::DefineDescriptor::Path(sn_index + 1, msg)) }) })) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push( Row::new() .push( @@ -261,14 +261,14 @@ pub fn custom_template<'a>( .width(Length::Fixed(200.0)) .on_press(Message::DefineDescriptor(message::DefineDescriptor::Reset)), ) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::primary(None, "Continue") .width(Length::Fixed(200.0)) .on_press_maybe(if valid { Some(Message::Next) } else { None }), ), ) - .push(Space::with_height(100.0)) + .push(Space::new().height(100.0)) .spacing(20), true, Some(Message::Previous), diff --git a/liana-gui/src/installer/view/editor/template/inheritance.rs b/liana-gui/src/installer/view/editor/template/inheritance.rs index 34a3c6390..7b2bba6f1 100644 --- a/liana-gui/src/installer/view/editor/template/inheritance.rs +++ b/liana-gui/src/installer/view/editor/template/inheritance.rs @@ -56,8 +56,8 @@ After a period of inactivity (but not before that) your Inheritance Key will bec .align_x(alignment::Horizontal::Left) ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push(image::inheritance_template_description().width(Length::Fill)) - .push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) - .push(Space::with_height(50.0)) + .push(Row::new().push(Space::new().width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) + .push(Space::new().height(50.0)) .spacing(20), true, Some(Message::Previous), @@ -160,7 +160,7 @@ pub fn inheritance_template<'a>( ) .map(|msg| Message::DefineDescriptor(message::DefineDescriptor::Path(1, msg))), ) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push( Row::new() .push( @@ -168,7 +168,7 @@ pub fn inheritance_template<'a>( .width(Length::Fixed(120.0)) .on_press(Message::DefineDescriptor(message::DefineDescriptor::Reset)), ) - .push(Space::with_width(40)) + .push(Space::new().width(40)) .push( button::secondary(None, "Customize") .width(Length::Fixed(120.0)) @@ -178,7 +178,7 @@ pub fn inheritance_template<'a>( ), )), ) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::primary(None, "Continue") .width(Length::Fixed(200.0)) diff --git a/liana-gui/src/installer/view/editor/template/multisig_security_wallet.rs b/liana-gui/src/installer/view/editor/template/multisig_security_wallet.rs index ba49b1637..33f3f9d55 100644 --- a/liana-gui/src/installer/view/editor/template/multisig_security_wallet.rs +++ b/liana-gui/src/installer/view/editor/template/multisig_security_wallet.rs @@ -66,8 +66,8 @@ pub fn multisig_security_template_description( .align_x(alignment::Horizontal::Left) ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push(image::multisig_security_template_description().width(Length::Fill)) - .push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) - .push(Space::with_height(50.0)) + .push(Row::new().push(Space::new().width(Length::Fill)).push(button::primary(None, "Next").width(Length::Fixed(200.0)).on_press(Message::Next))) + .push(Space::new().height(50.0)) .spacing(20), true, Some(Message::Previous), @@ -230,7 +230,7 @@ pub fn multisig_security_template<'a>( } }), ) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push( Row::new() .push( @@ -238,7 +238,7 @@ pub fn multisig_security_template<'a>( .width(Length::Fixed(120.0)) .on_press(Message::DefineDescriptor(message::DefineDescriptor::Reset)), ) - .push(Space::with_width(40)) + .push(Space::new().width(40)) .push( button::secondary(None, "Customize") .width(Length::Fixed(120.0)) @@ -248,14 +248,14 @@ pub fn multisig_security_template<'a>( ), )), ) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::primary(None, "Continue") .width(Length::Fixed(200.0)) .on_press_maybe(if valid { Some(Message::Next) } else { None }), ), ) - .push(Space::with_height(100.0)) + .push(Space::new().height(100.0)) .spacing(20), true, Some(Message::Previous), diff --git a/liana-gui/src/installer/view/mod.rs b/liana-gui/src/installer/view/mod.rs index de41949bb..caf740774 100644 --- a/liana-gui/src/installer/view/mod.rs +++ b/liana-gui/src/installer/view/mod.rs @@ -115,17 +115,17 @@ pub fn import_wallet_or_descriptor<'a>( if let Some(wallet) = invitation_wallet { Element::<'a, Message>::from( Column::new() - .push(Space::with_height(0)) + .push(Space::new().height(0)) .push( Row::new() .spacing(5) - .push(Space::with_width(15)) + .push(Space::new().width(15)) .push(text("Accept invitation for wallet:")) .push(text(wallet).bold()), ) .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push( button::secondary(None, "Accept") .width(Length::Fixed(200.0)) @@ -133,16 +133,16 @@ pub fn import_wallet_or_descriptor<'a>( message::ImportRemoteWallet::AcceptInvitation, )), ) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ) - .push(Space::with_width(5)) + .push(Space::new().width(5)) .spacing(20), ) } else { Element::<'a, Message>::from( Container::new( Column::new() - .push(Space::with_height(0)) + .push(Space::new().height(0)) .push( Column::new() .push(text("Paste invitation:").bold()) @@ -156,12 +156,12 @@ pub fn import_wallet_or_descriptor<'a>( }) .warning("Invitation token is invalid or expired") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .spacing(10), ) .push( - Row::new().push(Space::with_width(Length::Fill)).push( + Row::new().push(Space::new().width(Length::Fill)).push( button::secondary(None, "Next") .width(Length::Fixed(200.0)) .on_press_maybe(if !invitation.value.is_empty() { @@ -214,7 +214,7 @@ pub fn import_wallet_or_descriptor<'a>( Element::<'a, Message>::from( Container::new( Column::new() - .push(Space::with_height(0)) + .push(Space::new().height(0)) .push( Column::new() .push(text("Descriptor:").bold()) @@ -232,7 +232,7 @@ pub fn import_wallet_or_descriptor<'a>( "Either descriptor is invalid or incompatible with network", ) .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .push(text("or").bold()) .push(button::primary(None, "Import descriptor").on_press( @@ -243,7 +243,7 @@ pub fn import_wallet_or_descriptor<'a>( .spacing(10), ) .push( - Row::new().push(Space::with_width(Length::Fill)).push( + Row::new().push(Space::new().width(Length::Fill)).push( button::secondary(None, "Next") .width(Length::Fixed(200.0)) .on_press_maybe( @@ -276,7 +276,7 @@ pub fn import_wallet_or_descriptor<'a>( .push(card_wallets) .push(card::simple(col_invitation_token).padding(0)) .push(card::simple(col_descriptor).padding(0)) - .push(Space::with_height(10)), + .push(Space::new().height(10)), true, Some(Message::Previous), ) @@ -294,7 +294,7 @@ pub fn import_descriptor<'a>( let col_descriptor = Column::new() .push(text("Descriptor:").bold()) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .push( form::Form::new_trimmed("Descriptor", imported_descriptor, |msg| { Message::DefineDescriptor(message::DefineDescriptor::ImportDescriptor(msg)) @@ -305,7 +305,7 @@ pub fn import_descriptor<'a>( "Failed to read the descriptor" }) .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ); let descriptor = if imported_backup { @@ -318,7 +318,7 @@ pub fn import_descriptor<'a>( Some( Row::new() .push(text("or").bold()) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ) } else { None @@ -328,7 +328,7 @@ pub fn import_descriptor<'a>( Some( Row::new() .push(button::primary(None, "Import backup").on_press(Message::ImportBackup)) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ) } else { None @@ -338,7 +338,7 @@ pub fn import_descriptor<'a>( Some( Row::new() .push(text("Backup successfully imported!").bold()) - .push(Space::with_width(Length::Fill)), + .push(Space::new().width(Length::Fill)), ) } else { None @@ -435,11 +435,9 @@ pub fn signer_xpubs<'a>( .push_maybe(if !xpubs.is_empty() { Some( Container::new( - checkbox( - "I have backed up the mnemonic, show the extended public key", - did_backup, - ) - .on_toggle(Message::UserActionDone), + checkbox(did_backup) + .label("I have backed up the mnemonic, show the extended public key") + .on_toggle(Message::UserActionDone), ) .padding(10), ) @@ -584,7 +582,7 @@ pub fn share_xpubs<'a>( signer: Element<'a, Message>, ) -> Element<'a, Message> { let info = Column::new() - .push(Space::with_height(5)) + .push(Space::new().height(5)) .push(tooltip::Tooltip::new( icon::tooltip_icon(), "Switch account if you already use the same hardware in other configurations", @@ -592,9 +590,9 @@ pub fn share_xpubs<'a>( )); let title = Row::new() .push(text("Import an extended public key by selecting a signing device:").bold()) - .push(Space::with_width(10)) + .push(Space::new().width(10)) .push(info) - .push(Space::with_width(Length::Fill)); + .push(Space::new().width(Length::Fill)); layout( (0, 0), email, @@ -610,7 +608,7 @@ pub fn share_xpubs<'a>( .push(Column::with_children(hws).spacing(10)) .push(Container::new(text("Or create a new random key:").bold()).width(Length::Fill)) .push(signer) - .push(Space::with_height(10)) + .push(Space::new().height(10)) .width(Length::Fill), true, Some(Message::Previous), @@ -619,7 +617,7 @@ pub fn share_xpubs<'a>( pub fn policy_entry_card(title: String, content: String) -> Container<'static, Message> { let title = text(title).small().bold(); - let scroll = scrollable(column![text(content).small(), Space::with_height(5)]).direction( + let scroll = scrollable(column![text(content).small(), Space::new().height(5)]).direction( scrollable::Direction::Horizontal(scrollable::Scrollbar::new().width(5).scroller_width(5)), ); card::simple(column![title, scroll].spacing(10)).width(Length::Fill) @@ -694,7 +692,8 @@ pub fn register_descriptor<'a>( .width(Length::Fill); let registered_checkbox = created_desc.then_some( - checkbox("I have registered the descriptor on my device(s)", done) + checkbox(done) + .label("I have registered the descriptor on my device(s)") .on_toggle(Message::UserActionDone), ); @@ -714,7 +713,7 @@ pub fn register_descriptor<'a>( .push(signing_devices) .push_maybe(registered_checkbox) .push(next_button) - .push(Space::with_height(5)) + .push(Space::new().height(5)) .spacing(50); let previous = (!processing).then_some(Message::Previous); @@ -787,7 +786,7 @@ pub fn backup_descriptor<'a>( scrollable( Column::new() .push(text(descriptor.to_string()).small()) - .push(Space::with_height(Length::Fixed(5.0))), + .push(Space::new().height(Length::Fixed(5.0))), ) .direction( scrollable::Direction::Horizontal( @@ -797,9 +796,9 @@ pub fn backup_descriptor<'a>( ) .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(backup_button) - .push(Space::with_width(10)) + .push(Space::new().width(10)) .push( button::secondary(Some(icon::clipboard_icon()), "Copy") .on_press(Message::Clipboard(descriptor.to_string())), @@ -815,7 +814,9 @@ pub fn backup_descriptor<'a>( .max_width(1500), ) .push( - checkbox("I have backed up my descriptor", done).on_toggle(Message::UserActionDone), + checkbox(done) + .label("I have backed up my descriptor") + .on_toggle(Message::UserActionDone), ) .push(if done { button::primary(None, "Next") @@ -824,7 +825,7 @@ pub fn backup_descriptor<'a>( } else { button::secondary(None, "Next").width(Length::Fixed(200.0)) }) - .push(Space::with_height(20.0)) + .push(Space::new().height(20.0)) .spacing(50), true, Some(Message::Previous), @@ -1066,7 +1067,7 @@ pub fn define_bitcoin_node<'a>( } }) } else { - Some(Container::new(Space::with_height(Length::Fixed(21.0)))) + Some(Container::new(Space::new().height(Length::Fixed(21.0)))) }) .push( Row::new() @@ -1126,7 +1127,7 @@ pub fn define_bitcoind<'a>( }) .warning("Please enter correct address") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .push_maybe(if !is_loopback && address.valid { Some( @@ -1176,7 +1177,7 @@ pub fn define_bitcoind<'a>( }) .warning("Please enter correct path") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ), RpcAuthType::UserPass => Row::new() .push( @@ -1187,7 +1188,7 @@ pub fn define_bitcoind<'a>( }) .warning("Please enter correct user") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .push( form::Form::new_trimmed("Password", &rpc_auth_vals.password, |msg| { @@ -1197,7 +1198,7 @@ pub fn define_bitcoind<'a>( }) .warning("Please enter correct password") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .spacing(10), }) @@ -1232,7 +1233,7 @@ pub fn define_electrum<'a>( optionally prefixed with tcp:// or ssl://", ) .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .push_maybe(checkbox) .push(text(electrum::ADDRESS_NOTES)) @@ -1456,7 +1457,7 @@ pub fn start_internal_bitcoind<'a>( .align_y(Alignment::Center) .push(text("Starting...")), )), - _ => Some(Container::new(Space::with_height(Length::Fixed(25.0)))), + _ => Some(Container::new(Space::new().height(Length::Fixed(25.0)))), } }) .spacing(50) @@ -1508,7 +1509,7 @@ pub fn install<'a>( .push(text("Installed").style(theme::text::success)), ) } else { - Container::new(Space::with_height(Length::Fixed(25.0))) + Container::new(Space::new().height(Length::Fixed(25.0))) }) .spacing(10) .width(Length::Fill), @@ -1773,7 +1774,11 @@ pub fn backup_mnemonic<'a>( ) }), ) - .push(checkbox("I have backed up my mnemonic", done).on_toggle(Message::UserActionDone)) + .push( + checkbox(done) + .label("I have backed up my mnemonic") + .on_toggle(Message::UserActionDone), + ) .push(if done { button::secondary(None, "Next") .on_press(Message::Next) @@ -1781,7 +1786,7 @@ pub fn backup_mnemonic<'a>( } else { button::secondary(None, "Next").width(Length::Fixed(200.0)) }) - .push(Space::with_height(20.0)) + .push(Space::new().height(20.0)) .spacing(50), true, Some(Message::Previous), @@ -1853,7 +1858,7 @@ pub fn recover_mnemonic<'a>( ) }, )) - .push(Space::with_height(Length::Fixed(50.0))) + .push(Space::new().height(Length::Fixed(50.0))) .push_maybe( error.map(|e| card::invalid(text(e).style(theme::text::error))), ), @@ -1948,7 +1953,7 @@ pub fn choose_backend(progress: (usize, usize)) -> Element<'static, Message> { .width(Length::FillPortion(1)), ), ) - .push(Space::with_height(20)) // ensures mouse cursor is not already on link when arriving at this step + .push(Space::new().height(20)) // ensures mouse cursor is not already on link when arriving at this step .push(tooltip::Tooltip::new( button::link( Some(icon::link_icon()), @@ -2028,11 +2033,11 @@ pub fn connection_step_enter_email<'a>( Message::SelectBackend(message::SelectBackend::EmailEdited(msg)) }) .size(text::P1_SIZE) - .padding(10) + .padding(10.0) .warning("Email is not valid"), ) .push( - Row::new().push(Space::with_width(Length::Fill)).push( + Row::new().push(Space::new().width(Length::Fill)).push( button::secondary(None, "Send token") .on_press_maybe(if processing || !email.valid { None @@ -2063,7 +2068,7 @@ pub fn connection_step_enter_otp<'a>( Message::SelectBackend(message::SelectBackend::OTPEdited(msg)) }) .size(text::P1_SIZE) - .padding(10) + .padding(10.0) .warning("Token is not valid"), ) .push( @@ -2135,7 +2140,7 @@ pub fn wallet_alias<'a>( form::Form::new("Wallet alias", wallet_alias, Message::WalletAliasEdited) .warning("Wallet alias is too long.") .size(text::P1_SIZE) - .padding(10), + .padding(10.0), ) .push(p2_regular( "You will be able to change it later in Settings > Wallet", @@ -2173,12 +2178,12 @@ fn layout<'a>( .width(Length::Fill) .push( Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(email.map(|e| { Container::new(p1_regular(e).style(theme::text::success)).padding(20) })), ) - .push(Space::with_height(Length::Fixed(100.0))) + .push(Space::new().height(Length::Fixed(100.0))) .push( Row::new() .align_y(Alignment::Center) @@ -2195,11 +2200,11 @@ fn layout<'a>( ) .push( Row::new() - .push(Space::with_width(Length::FillPortion(2))) + .push(Space::new().width(Length::FillPortion(2))) .push( Container::new( Column::new() - .push(Space::with_height(Length::Fixed(100.0))) + .push(Space::new().height(Length::Fixed(100.0))) .push(content), ) .width(Length::FillPortion(if padding_left { @@ -2209,7 +2214,7 @@ fn layout<'a>( })), ) .push_maybe(if padding_left { - Some(Space::with_width(Length::FillPortion(2))) + Some(Space::new().width(Length::FillPortion(2))) } else { None }), diff --git a/liana-gui/src/launcher.rs b/liana-gui/src/launcher.rs index 14ecc46c8..c1610512a 100644 --- a/liana-gui/src/launcher.rs +++ b/liana-gui/src/launcher.rs @@ -8,7 +8,7 @@ use liana::miniscript::bitcoin::Network; use liana_ui::{ component::{button, card, network_banner, notification, pick_list, text::*}, icon, image, theme, - widget::{modal::Modal, Column, Container, Element, Row}, + widget::{modal::Modal, Column, ColumnExt, Container, Element, Row, RowExt}, }; use lianad::config::ConfigError; use tokio::runtime::Handle; @@ -300,7 +300,7 @@ impl Launcher { ) .center_x(Length::Fill), ) - .push(Space::with_height(Length::Fixed(100.0))), + .push(Space::new().height(Length::Fixed(100.0))), )) .map(Message::View); let content = if self.network != Network::Bitcoin { @@ -393,7 +393,7 @@ fn wallets_list_item( ) .push_maybe(settings.remote_backend_auth.as_ref().map(|auth| { Row::new() - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push(p1_regular(&auth.email).style(theme::text::secondary)) })), ) @@ -608,13 +608,11 @@ impl DeleteWalletModal { ) .push(Row::new()) .push_maybe(self.wallet_settings.remote_backend_auth.as_ref().map(|a| { - checkbox( - match self.user_role { + checkbox(self.delete_liana_connect) + .label(match self.user_role { Some(UserRole::Owner) | None => "Also permanently delete this wallet from Liana Connect (for all members).".to_string(), Some(UserRole::Member) => format!("Also disassociate {} from this Liana Connect wallet.", a.email), - }, - self.delete_liana_connect, - ) + }) .on_toggle_maybe(if !self.deleted { Some(|v| { ViewMessage::DeleteWallet(DeleteWalletMessage::DeleteLianaConnect(v)) diff --git a/liana-gui/src/loader.rs b/liana-gui/src/loader.rs index 133742d8a..a561c5f67 100644 --- a/liana-gui/src/loader.rs +++ b/liana-gui/src/loader.rs @@ -342,7 +342,7 @@ impl Loader { pub fn subscription(&self) -> Subscription { if self.internal_bitcoind.is_some() { let log_path = internal_bitcoind_debug_log_path(&self.datadir_path, self.network); - iced::Subscription::run_with_id("bitcoind_log", get_bitcoind_log(log_path)) + crate::utils::subscription::run_with_id("bitcoind_log", get_bitcoind_log(log_path)) .map(Message::BitcoindLog) } else { Subscription::none() @@ -355,62 +355,66 @@ impl Loader { } fn get_bitcoind_log(log_path: PathBuf) -> impl Stream> { - channel(5, move |mut output| async move { - loop { - // Reduce the io load. - tokio::time::sleep(Duration::from_millis(500)).await; - - // Open the log file and seek to its end, with some breathing room to make sure - // we don't skip all "UpdateTip" lines. This is to avoid making BufReader read - // the whole file every single time below. - let mut file = match File::open(&log_path) { - Ok(file) => file, - Err(e) => { - log::warn!("Opening bitcoind log file: {}", e); - continue; - } - }; - match file.metadata() { - Ok(m) => { - let file_len = m.len(); - let offset = 1024 * 1024; - if file_len > offset { - if let Err(e) = file.seek(SeekFrom::Start(file_len.saturating_sub(offset))) - { - log::error!("Seeking to end of bitcoind log file: {}", e); + channel( + 5, + move |mut output: iced::futures::channel::mpsc::Sender>| async move { + loop { + // Reduce the io load. + tokio::time::sleep(Duration::from_millis(500)).await; + + // Open the log file and seek to its end, with some breathing room to make sure + // we don't skip all "UpdateTip" lines. This is to avoid making BufReader read + // the whole file every single time below. + let mut file = match File::open(&log_path) { + Ok(file) => file, + Err(e) => { + log::warn!("Opening bitcoind log file: {}", e); + continue; + } + }; + match file.metadata() { + Ok(m) => { + let file_len = m.len(); + let offset = 1024 * 1024; + if file_len > offset { + if let Err(e) = + file.seek(SeekFrom::Start(file_len.saturating_sub(offset))) + { + log::error!("Seeking to end of bitcoind log file: {}", e); + } } } - } - Err(e) => { - log::error!("Getting bitcoind log file metadata: {}", e); - } - }; - - // Find the latest tip update line in bitcoind's debug.log. BufReader is only - // used to facilitates searching through the lines. - let reader = BufReader::new(file); - let last_update_tip = reader - .lines() - .filter(|l| { - l.as_ref() - .map(|l| l.contains("UpdateTip") || l.contains("blockheaders")) - .unwrap_or(false) - }) - .last(); - match last_update_tip { - Some(Ok(line)) => { - let _ = output.send(Some(line)).await; - } - res => { - if let Some(Err(e)) = res { - log::error!("Reading bitcoind log file: {}", e); - } else { - log::warn!("Couldn't find an UpdateTip line in bitcoind log file."); + Err(e) => { + log::error!("Getting bitcoind log file metadata: {}", e); + } + }; + + // Find the latest tip update line in bitcoind's debug.log. BufReader is only + // used to facilitates searching through the lines. + let reader = BufReader::new(file); + let last_update_tip = reader + .lines() + .filter(|l| { + l.as_ref() + .map(|l| l.contains("UpdateTip") || l.contains("blockheaders")) + .unwrap_or(false) + }) + .last(); + match last_update_tip { + Some(Ok(line)) => { + let _ = output.send(Some(line)).await; + } + res => { + if let Some(Err(e)) = res { + log::error!("Reading bitcoind log file: {}", e); + } else { + log::warn!("Couldn't find an UpdateTip line in bitcoind log file."); + } } } } - } - }) + }, + ) } pub async fn load_application( @@ -468,14 +472,14 @@ pub fn view(step: &Step) -> Element { None, Column::new() .width(Length::Fill) - .push(ProgressBar::new(0.0..=1.0, 0.0).width(Length::Fill)) + .push(ProgressBar::new(0.0..=1.0, 0.0).length(Length::Fill)) .push(text("Starting daemon...")), ), Step::Connecting => cover( None, Column::new() .width(Length::Fill) - .push(ProgressBar::new(0.0..=1.0, 0.0).width(Length::Fill)) + .push(ProgressBar::new(0.0..=1.0, 0.0).length(Length::Fill)) .push(text("Connecting to daemon...")), ), Step::Syncing { @@ -488,7 +492,7 @@ pub fn view(step: &Step) -> Element { .width(Length::Fill) .spacing(5) .push(text(format!("Progress {:.2}%", 100.0 * *progress))) - .push(ProgressBar::new(0.0..=1.0, *progress as f32).width(Length::Fill)) + .push(ProgressBar::new(0.0..=1.0, *progress as f32).length(Length::Fill)) .push(text(if *progress > 0.98 { SYNCING_PROGRESS_3 } else if *progress > 0.9 { diff --git a/liana-gui/src/main.rs b/liana-gui/src/main.rs index 863f19f65..3a3c0091c 100644 --- a/liana-gui/src/main.rs +++ b/liana-gui/src/main.rs @@ -41,13 +41,22 @@ fn main() -> Result<(), Box> { let initial_size = load_initial_size(&config.liana_directory, None); let window_settings = create_window_settings("Liana", initial_size); - if let Err(e) = iced::application(LianaGUI::title, LianaGUI::update, LianaGUI::view) - .theme(|_| theme::Theme::default()) - .scale_factor(LianaGUI::scale_factor) - .subscription(LianaGUI::subscription) - .settings(settings) - .window(window_settings) - .run_with(move || LianaGUI::new((config, log_level, VERSION))) + let boot_args = std::sync::Mutex::new(Some((config, log_level, VERSION))); + if let Err(e) = iced::application( + move || { + let args = boot_args.lock().unwrap().take().expect("boot called twice"); + LianaGUI::new(args) + }, + LianaGUI::update, + LianaGUI::view, + ) + .title(LianaGUI::title) + .theme(|_: &_| theme::Theme::default()) + .scale_factor(LianaGUI::scale_factor) + .subscription(LianaGUI::subscription) + .settings(settings) + .window(window_settings) + .run() { log::error!("{}", e); Err(format!("Failed to launch UI: {}", e).into()) diff --git a/liana-gui/src/node/electrum.rs b/liana-gui/src/node/electrum.rs index db55ee9f1..613d7ecd4 100644 --- a/liana-gui/src/node/electrum.rs +++ b/liana-gui/src/node/electrum.rs @@ -31,7 +31,9 @@ where F: 'a + Fn(bool) -> M, M: 'a, { - let checkbox = checkbox(VALID_SSL_DOMAIN_NOTES, !value).on_toggle(move |b| closure(!b)); + let checkbox = checkbox(!value) + .label(VALID_SSL_DOMAIN_NOTES) + .on_toggle(move |b| closure(!b)); if addr.valid && is_ssl(&addr.value) { Some(checkbox.into()) } else { diff --git a/liana-gui/src/services/connect/login.rs b/liana-gui/src/services/connect/login.rs index 307242cb0..385624c58 100644 --- a/liana-gui/src/services/connect/login.rs +++ b/liana-gui/src/services/connect/login.rs @@ -429,7 +429,7 @@ impl LianaLiteLogin { ViewMessage::OTPEdited(msg) }) .size(P1_SIZE) - .padding(10) + .padding(10.0) .warning("Token is not valid"), ) .push( diff --git a/liana-gui/src/utils/mod.rs b/liana-gui/src/utils/mod.rs index 72df12b9f..d20ec9295 100644 --- a/liana-gui/src/utils/mod.rs +++ b/liana-gui/src/utils/mod.rs @@ -6,6 +6,7 @@ use std::{ use liana::miniscript::bitcoin::{self, bip32::DerivationPath, Network}; pub mod serde; +pub mod subscription; #[cfg(test)] pub mod sandbox; diff --git a/liana-gui/src/utils/subscription.rs b/liana-gui/src/utils/subscription.rs new file mode 100644 index 000000000..2fda71ebc --- /dev/null +++ b/liana-gui/src/utils/subscription.rs @@ -0,0 +1,42 @@ +use iced::advanced::subscription::{from_recipe, EventStream, Hasher, Recipe}; +use iced::futures::stream::BoxStream; +use iced::futures::Stream; +use iced::Subscription; + +use std::hash::Hash; + +/// Replacement for `Subscription::run_with_id` which was removed in iced 0.14. +/// +/// Creates a [`Subscription`] that will asynchronously run the given [`Stream`], +/// using `id` to uniquely identify the subscription. +pub fn run_with_id(id: I, stream: S) -> Subscription +where + I: Hash + 'static, + S: Stream + Send + 'static, + T: 'static + Send, +{ + from_recipe(IdRunner { id, stream }) +} + +struct IdRunner { + id: I, + stream: S, +} + +impl Recipe for IdRunner +where + I: Hash + 'static, + S: Stream + Send + 'static, + S::Item: 'static + Send, +{ + type Output = S::Item; + + fn hash(&self, state: &mut Hasher) { + self.id.hash(state); + std::any::TypeId::of::().hash(state); + } + + fn stream(self: Box, _input: EventStream) -> BoxStream<'static, Self::Output> { + Box::pin(self.stream) + } +} diff --git a/liana-gui/src/window.rs b/liana-gui/src/window.rs index 5dca97720..85cf6ec8d 100644 --- a/liana-gui/src/window.rs +++ b/liana-gui/src/window.rs @@ -16,6 +16,7 @@ pub fn create_app_settings(app_id: &str) -> Settings { default_text_size: text::P1_SIZE.into(), default_font: font::REGULAR, fonts: font::load(), + vsync: true, } } diff --git a/liana-ui/src/component/amount.rs b/liana-ui/src/component/amount.rs index 52e18db39..40c7dfd06 100644 --- a/liana-ui/src/component/amount.rs +++ b/liana-ui/src/component/amount.rs @@ -19,7 +19,7 @@ pub fn amount<'a, T: 'a>(a: &Amount) -> Row<'a, T> { } /// Amount with default colors. -pub fn amount_with_size<'a, T: 'a>(a: &Amount, size: u16) -> Row<'a, T> { +pub fn amount_with_size<'a, T: 'a>(a: &Amount, size: f32) -> Row<'a, T> { amount_with_size_and_colors(a, size, color::GREY_3, None) } @@ -33,14 +33,14 @@ pub fn amount_with_size<'a, T: 'a>(a: &Amount, size: u16) -> Row<'a, T> { /// will be used. pub fn amount_with_size_and_colors<'a, T: 'a>( a: &Amount, - size: u16, + size: f32, color_before: Color, color_after: Option, ) -> Row<'a, T> { render_amount(a.to_formatted_string(), size, color_before, color_after) } -pub fn unconfirmed_amount_with_size<'a, T: 'a>(a: &Amount, size: u16) -> Row<'a, T> { +pub fn unconfirmed_amount_with_size<'a, T: 'a>(a: &Amount, size: f32) -> Row<'a, T> { render_unconfirmed_amount(a.to_formatted_string(), size) } @@ -116,11 +116,11 @@ fn split_at_first_non_zero(s: String) -> Option<(String, String)> { // The text should be bolded beginning where the BTC amount is non-zero. fn render_amount<'a, T: 'a>( amount: String, - size: u16, + size: f32, color_before: Color, color_after: Option, ) -> Row<'a, T> { - let spacing = if size > P1_SIZE { 10 } else { 5 }; + let spacing = if size > P1_SIZE { 10.0 } else { 5.0 }; let (before, after) = match split_at_first_non_zero(amount) { Some((b, a)) => (b, a), @@ -153,8 +153,8 @@ fn render_amount<'a, T: 'a>( } // Build the rendering elements for displaying a Bitcoin amount. -fn render_unconfirmed_amount<'a, T: 'a>(amount: String, size: u16) -> Row<'a, T> { - let spacing = if size > P1_SIZE { 10 } else { 5 }; +fn render_unconfirmed_amount<'a, T: 'a>(amount: String, size: f32) -> Row<'a, T> { + let spacing = if size > P1_SIZE { 10.0 } else { 5.0 }; Row::with_children(vec![ text(amount).size(size).color(color::GREY_3).into(), diff --git a/liana-ui/src/component/button.rs b/liana-ui/src/component/button.rs index 5e52a93cf..71b5dae1a 100644 --- a/liana-ui/src/component/button.rs +++ b/liana-ui/src/component/button.rs @@ -11,10 +11,10 @@ use iced::{ Length, }; -const MENU_BTN_PADDING: [u16; 2] = [4 /* Top/Bottom */, 12 /* Left/Right */]; -const MENU_TEXT_SIZE: u16 = 22; -const MENU_TEXT_COMPACT_SIZE: u16 = 18; -const MENU_ICON_SIZE: u16 = ICON_SIZE_L; +const MENU_BTN_PADDING: [f32; 2] = [4.0 /* Top/Bottom */, 12.0 /* Left/Right */]; +const MENU_TEXT_SIZE: f32 = 22.0; +const MENU_TEXT_COMPACT_SIZE: f32 = 18.0; +const MENU_ICON_SIZE: f32 = ICON_SIZE_L; const ICON_BTN_SIZE: f32 = 40.0; const ICON_BTN_PADDING: f32 = 10.0; @@ -153,7 +153,7 @@ pub fn btn_primary<'a, T: Clone + 'a>( width: BtnWidth, msg: Option, ) -> Button<'a, T> { - let mut btn = primary(icon, label).width(Length::Fixed(width as u16 as f32)); + let mut btn = primary(icon, label).width(Length::Fixed(width as u32 as f32)); if let Some(m) = msg { btn = btn.on_press(m); } @@ -167,7 +167,7 @@ pub fn btn_secondary<'a, T: Clone + 'a>( width: BtnWidth, msg: Option, ) -> Button<'a, T> { - let mut btn = secondary(icon, label).width(Length::Fixed(width as u16 as f32)); + let mut btn = secondary(icon, label).width(Length::Fixed(width as u32 as f32)); if let Some(m) = msg { btn = btn.on_press(m); } @@ -181,7 +181,7 @@ pub fn btn_tertiary<'a, T: Clone + 'a>( width: BtnWidth, msg: Option, ) -> Button<'a, T> { - let mut btn = tertiary(icon, label).width(Length::Fixed(width as u16 as f32)); + let mut btn = tertiary(icon, label).width(Length::Fixed(width as u32 as f32)); if let Some(m) = msg { btn = btn.on_press(m); } @@ -195,7 +195,7 @@ pub fn btn_destructive<'a, T: Clone + 'a>( width: BtnWidth, msg: Option, ) -> Button<'a, T> { - let mut btn = destructive(icon, label).width(Length::Fixed(width as u16 as f32)); + let mut btn = destructive(icon, label).width(Length::Fixed(width as u32 as f32)); if let Some(m) = msg { btn = btn.on_press(m); } @@ -209,7 +209,7 @@ pub fn btn_flat<'a, T: Clone + 'a>( width: BtnWidth, msg: Option, ) -> Button<'a, T> { - let mut btn = flat(icon, label).width(Length::Fixed(width as u16 as f32)); + let mut btn = flat(icon, label).width(Length::Fixed(width as u32 as f32)); if let Some(m) = msg { btn = btn.on_press(m); } diff --git a/liana-ui/src/component/card.rs b/liana-ui/src/component/card.rs index 5f95fb75e..ef2f4c65b 100644 --- a/liana-ui/src/component/card.rs +++ b/liana-ui/src/component/card.rs @@ -1,6 +1,6 @@ use crate::{color, component::text::text, icon, theme, widget::*}; use iced::{widget::button, Alignment}; -const CARD_PADDING: [u16; 2] = [15, 30]; +const CARD_PADDING: [f32; 2] = [15.0, 30.0]; pub fn modal<'a, T: 'a, C: Into>>(content: C) -> Container<'a, T> { Container::new(content) diff --git a/liana-ui/src/component/form.rs b/liana-ui/src/component/form.rs index 836d312c1..c5dffb9af 100644 --- a/liana-ui/src/component/form.rs +++ b/liana-ui/src/component/form.rs @@ -129,13 +129,13 @@ where } /// Sets the padding of the [`Form`]. - pub fn padding(mut self, units: u16) -> Self { + pub fn padding(mut self, units: f32) -> Self { self.input = self.input.padding(units); self } /// Sets the [`Form`] with a text size - pub fn size(mut self, size: u16) -> Self { + pub fn size(mut self, size: f32) -> Self { self.input = self.input.size(size); self } diff --git a/liana-ui/src/component/hw.rs b/liana-ui/src/component/hw.rs index e46eb824d..1d594eba4 100644 --- a/liana-ui/src/component/hw.rs +++ b/liana-ui/src/component/hw.rs @@ -134,9 +134,9 @@ pub fn supported_hardware_wallet_with_account< Container::new( Row::new() .push(key) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(pick_account) - .push_maybe(display_account.map(|a| column![Space::with_height(8), a])), + .push_maybe(display_account.map(|a| column![Space::new().height(8), a])), ) .align_y(Alignment::Center) .padding(10) @@ -226,10 +226,10 @@ pub fn disabled_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>( container( Row::new() .push(key) - .push(Space::with_width(15)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(15)) + .push(Space::new().width(Length::Fill)) .push(text::text(label)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .align_y(Vertical::Center), ) .width(Length::Fill) @@ -320,9 +320,9 @@ pub fn selected_hardware_wallet<'a, T: 'static, K: Display, V: Display, F: Displ container( Row::new() .push(key) - .push(Space::with_width(Length::Fill)) - .push_maybe(account.map(|a| column![Space::with_height(8), text::p1_bold(a)])) - .push(Space::with_width(10)) + .push(Space::new().width(Length::Fill)) + .push_maybe(account.map(|a| column![Space::new().height(8), text::p1_bold(a)])) + .push(Space::new().width(10)) .push_maybe(warning.map(|w| { tooltip::Tooltip::new( icon::warning_icon(), @@ -618,7 +618,7 @@ pub fn hot_signer<'a, T: 'a, F: Display>( .push(text::caption("This computer")) .into(), ])) - .push(Space::with_width(Length::Fixed(20.0))) + .push(Space::new().width(Length::Fixed(20.0))) .push_maybe(if !can_sign { Some(text::text( "This hot signer is not part of this spending path.", @@ -626,7 +626,7 @@ pub fn hot_signer<'a, T: 'a, F: Display>( } else { None }) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .align_y(Vertical::Center), ) .padding(10) diff --git a/liana-ui/src/component/modal.rs b/liana-ui/src/component/modal.rs index 48f365493..2e9a3436d 100644 --- a/liana-ui/src/component/modal.rs +++ b/liana-ui/src/component/modal.rs @@ -20,14 +20,14 @@ use crate::{ theme::{self, Theme}, }; -use crate::widget::{Button, Column, Element, Row, Text}; +use crate::widget::{Button, Column, ColumnExt, Element, Row, RowExt, Text}; -pub const BTN_W: u16 = 500; -pub const BTN_H: u16 = 40; -pub const V_SPACING: u16 = 10; -pub const H_SPACING: u16 = 5; +pub const BTN_W: f32 = 500.0; +pub const BTN_H: f32 = 40.0; +pub const V_SPACING: f32 = 10.0; +pub const H_SPACING: f32 = 5.0; const MODAL_PADDING: f32 = 20.0; -const MODAL_SPACING: u16 = 15; +const MODAL_SPACING: f32 = 15.0; /// Modal width presets. #[derive(Debug, Clone, Copy)] @@ -41,7 +41,7 @@ pub enum ModalWidth { } /// Keep backward compat for code referencing MODAL_WIDTH. -pub const MODAL_WIDTH: u16 = ModalWidth::L as u16; +pub const MODAL_WIDTH: f32 = ModalWidth::L as u32 as f32; /// Shorthand for `None:: T>` used in modal_view back/close params. pub fn none_fn() -> Option T> { @@ -96,7 +96,7 @@ where .push(content) .spacing(MODAL_SPACING) .padding(MODAL_PADDING) - .width(width as u16); + .width(width as u32 as f32); let padding = Padding { top: 0.0, @@ -133,7 +133,7 @@ where Row::new() .push_maybe(back) .push_maybe(title) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(close) .align_y(Vertical::Center) .into() @@ -192,7 +192,7 @@ where } else { form::Form::new_disabled(&input_placeholder, input_value) } - .padding(10); + .padding(10.0); let paste = paste_message.map(|m| Button::new(icon::paste_icon()).on_press(m())); if collapsed { @@ -201,7 +201,7 @@ where let col = Column::new() .push(row![ text::p1_regular(label).style(theme::text::primary), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ]) .push(line); let row = Row::new() @@ -253,13 +253,13 @@ where .align_x(Horizontal::Left) .width(200); let row = Row::new() - .push_maybe(icon.as_ref().map(|_| Space::with_width(H_SPACING))) + .push_maybe(icon.as_ref().map(|_| Space::new().width(H_SPACING))) .push_maybe(icon) - .push(Space::with_width(H_SPACING)) + .push(Space::new().width(H_SPACING)) .push(designation) .push_maybe(message) .push_maybe(error) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(tt) .align_y(Vertical::Center) .spacing(V_SPACING); @@ -284,7 +284,7 @@ where let error = error.map(|e| { row![ text::p1_regular(e).color(color::ORANGE), - Space::with_width(Length::Fill) + Space::new().width(Length::Fill) ] }); @@ -293,7 +293,7 @@ where let row = Row::new() .push_maybe(icon) .push(text::p1_regular(label)) - .push(Space::with_width(Length::Fill)) + .push(Space::new().width(Length::Fill)) .push_maybe(tt) .spacing(H_SPACING) .align_y(Vertical::Center) diff --git a/liana-ui/src/component/spinner.rs b/liana-ui/src/component/spinner.rs index c9d17d6ec..189e67cfc 100644 --- a/liana-ui/src/component/spinner.rs +++ b/liana-ui/src/component/spinner.rs @@ -6,7 +6,7 @@ use iced::{ widget::tree::{self, Tree}, Clipboard, Layout, Shell, Widget, }, - event, mouse, + mouse, time::Instant, window, Element, Event, Length, Rectangle, Renderer, Size, }; @@ -60,7 +60,7 @@ where } fn layout( - &self, + &mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, @@ -68,11 +68,11 @@ where let state = tree.state.downcast_mut::(); let child_nodes: Vec<_> = self .children - .iter() + .iter_mut() .enumerate() .map(|(i, child)| { child - .as_widget() + .as_widget_mut() .layout(&mut tree.children[i], renderer, limits) }) .collect(); @@ -96,26 +96,25 @@ where } } - fn on_event( + fn update( &mut self, tree: &mut Tree, - event: Event, + event: &Event, _layout: Layout<'_>, _cursor: mouse::Cursor, _renderer: &Renderer, _clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, _viewport: &Rectangle, - ) -> event::Status { + ) { let state = tree.state.downcast_mut::(); if let Event::Window(window::Event::RedrawRequested(now)) = event { if now.duration_since(state.last_transition) > self.interval { - state.last_transition = now; + state.last_transition = *now; state.current = (state.current + 1) % self.children.len(); } - shell.request_redraw(window::RedrawRequest::NextFrame); + shell.request_redraw(); } - event::Status::Ignored } fn draw( diff --git a/liana-ui/src/component/text.rs b/liana-ui/src/component/text.rs index ad6fe1334..4a540932c 100644 --- a/liana-ui/src/component/text.rs +++ b/liana-ui/src/component/text.rs @@ -2,14 +2,14 @@ use crate::{font, theme::Theme}; use iced::advanced::text::Shaping; use std::fmt::Display; -pub const H1_SIZE: u16 = 40; -pub const H2_SIZE: u16 = 29; -pub const H3_SIZE: u16 = 24; -pub const H4_SIZE: u16 = 20; -pub const H5_SIZE: u16 = 18; -pub const P1_SIZE: u16 = 16; -pub const P2_SIZE: u16 = 14; -pub const CAPTION_SIZE: u16 = 12; +pub const H1_SIZE: f32 = 40.0; +pub const H2_SIZE: f32 = 29.0; +pub const H3_SIZE: f32 = 24.0; +pub const H4_SIZE: f32 = 20.0; +pub const H5_SIZE: f32 = 18.0; +pub const P1_SIZE: f32 = 16.0; +pub const P2_SIZE: f32 = 14.0; +pub const CAPTION_SIZE: f32 = 12.0; pub fn panel_title<'a>(content: impl Display) -> iced::widget::Text<'a, Theme> { iced::widget::text!("{}", content) diff --git a/liana-ui/src/component/toast.rs b/liana-ui/src/component/toast.rs index 8a4d5ac87..bbf3d5366 100644 --- a/liana-ui/src/component/toast.rs +++ b/liana-ui/src/component/toast.rs @@ -3,7 +3,7 @@ use std::time::Instant; use iced::advanced::widget::{Operation, Tree}; use iced::advanced::{layout, mouse, overlay, renderer}; use iced::advanced::{Clipboard, Layout, Shell, Widget}; -use iced::event::{self, Event}; +use iced::event::Event; use iced::{Alignment, Element, Length, Point, Rectangle, Size, Vector}; pub trait Toast { @@ -41,13 +41,13 @@ where } fn layout( - &self, + &mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { self.content - .as_widget() + .as_widget_mut() .layout(&mut tree.children[0], renderer, limits) } @@ -92,31 +92,30 @@ where } fn operate( - &self, + &mut self, state: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn Operation, ) { - operation.container(None, layout.bounds(), &mut |operation| { - self.content - .as_widget() - .operate(&mut state.children[0], layout, renderer, operation); - }); + operation.container(None, layout.bounds()); + self.content + .as_widget_mut() + .operate(&mut state.children[0], layout, renderer, operation); } - fn on_event( + fn update( &mut self, state: &mut Tree, - event: Event, + event: &Event, layout: Layout<'_>, cursor_position: iced::mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, - ) -> event::Status { - self.content.as_widget_mut().on_event( + ) { + self.content.as_widget_mut().update( &mut state.children[0], event, layout, @@ -169,8 +168,9 @@ where fn overlay<'b>( &'b mut self, state: &'b mut Tree, - layout: Layout<'_>, + layout: Layout<'b>, renderer: &Renderer, + viewport: &Rectangle, translation: Vector, ) -> Option> { let instants = state.state.downcast_mut::>>(); @@ -181,6 +181,7 @@ where &mut content_state[0], layout, renderer, + viewport, translation, ); @@ -232,28 +233,28 @@ where .translate(Vector::new(self.position.x, self.position.y)) } - fn on_event( + fn update( &mut self, - event: Event, + event: &Event, layout: Layout<'_>, cursor_position: iced::mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, - ) -> event::Status { + ) { let viewport = layout.bounds(); self.toasts .iter_mut() .zip(self.state.iter_mut()) .zip(layout.children()) .zip(self.instants.iter_mut()) - .map(|(((child, state), layout), instant)| { + .for_each(|(((child, state), layout), instant)| { let mut local_messages = vec![]; let mut local_shell = Shell::new(&mut local_messages); - let status = child.as_widget_mut().on_event( + child.as_widget_mut().update( state, - event.clone(), + event, layout, cursor_position, renderer, @@ -267,10 +268,7 @@ where } shell.merge(local_shell, std::convert::identity); - - status - }) - .fold(event::Status::Ignored, event::Status::merge) + }); } fn draw( @@ -307,24 +305,22 @@ where renderer: &Renderer, operation: &mut dyn iced::advanced::widget::Operation, ) { - operation.container(None, layout.bounds(), &mut |operation| { - self.toasts - .iter() - .zip(self.state.iter_mut()) - .zip(layout.children()) - .for_each(|((child, state), layout)| { - child - .as_widget() - .operate(state, layout, renderer, operation); - }) - }); + operation.container(None, layout.bounds()); + self.toasts + .iter_mut() + .zip(self.state.iter_mut()) + .zip(layout.children()) + .for_each(|((child, state), layout)| { + child + .as_widget_mut() + .operate(state, layout, renderer, operation); + }); } fn mouse_interaction( &self, layout: Layout<'_>, cursor_position: iced::mouse::Cursor, - viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { self.toasts @@ -336,19 +332,13 @@ where state, layout, cursor_position, - viewport, + &layout.bounds(), renderer, ) }) .max() .unwrap_or_default() } - - fn is_over(&self, layout: Layout<'_>, _renderer: &Renderer, cursor_position: Point) -> bool { - layout - .children() - .any(|layout| layout.bounds().contains(cursor_position)) - } } impl<'a, Message, Theme, Renderer> From> diff --git a/liana-ui/src/icon.rs b/liana-ui/src/icon.rs index a07d61bea..5b797c40b 100644 --- a/liana-ui/src/icon.rs +++ b/liana-ui/src/icon.rs @@ -1,9 +1,9 @@ use crate::{component::text::P1_SIZE, widget::*}; use iced::{alignment, Font, Length}; -pub const ICON_SIZE_L: u16 = 32; -pub const ICON_SIZE_M: u16 = 24; -pub const ICON_SIZE_S: u16 = 16; +pub const ICON_SIZE_L: f32 = 32.0; +pub const ICON_SIZE_M: f32 = 24.0; +pub const ICON_SIZE_S: f32 = 16.0; const BOOTSTRAP_ICONS: Font = Font::with_name("bootstrap-icons"); diff --git a/liana-ui/src/theme/button.rs b/liana-ui/src/theme/button.rs index 5cd812c8c..93783d340 100644 --- a/liana-ui/src/theme/button.rs +++ b/liana-ui/src/theme/button.rs @@ -164,6 +164,7 @@ fn button(p: &Button, status: Status, width: f32) -> Style { } }, shadow: p.active.shadow, + snap: false, }, Status::Pressed => { if let Some(pressed) = p.pressed { @@ -182,6 +183,7 @@ fn button(p: &Button, status: Status, width: f32) -> Style { } }, shadow: pressed.shadow, + snap: false, } } else { button(p, Status::Active, width) @@ -202,6 +204,7 @@ fn button(p: &Button, status: Status, width: f32) -> Style { } }, shadow: p.hovered.shadow, + snap: false, }, Status::Disabled => { if let Some(disabled) = p.disabled { @@ -225,6 +228,7 @@ fn button(p: &Button, status: Status, width: f32) -> Style { } }, shadow: disabled.shadow, + snap: false, } } else { let active: Style = button(p, Status::Active, width); diff --git a/liana-ui/src/theme/card.rs b/liana-ui/src/theme/card.rs index d0615a8e0..a7f223033 100644 --- a/liana-ui/src/theme/card.rs +++ b/liana-ui/src/theme/card.rs @@ -50,6 +50,7 @@ fn card_with_shadow(palette: &ContainerPalette, btn: bool) -> Style { } }, shadow: CARD_SHADOW, + snap: false, } } diff --git a/liana-ui/src/theme/mod.rs b/liana-ui/src/theme/mod.rs index 3f7c0a715..cc745d0ee 100644 --- a/liana-ui/src/theme/mod.rs +++ b/liana-ui/src/theme/mod.rs @@ -47,11 +47,27 @@ impl Theme { } } -impl iced::application::DefaultStyle for Theme { - fn default_style(&self) -> iced::application::Appearance { - iced::application::Appearance { +impl iced::theme::Base for Theme { + fn default(_preference: iced::theme::Mode) -> Self { + ::default() + } + + fn mode(&self) -> iced::theme::Mode { + iced::theme::Mode::Light + } + + fn base(&self) -> iced::theme::Style { + iced::theme::Style { background_color: self.colors.general.background, text_color: self.colors.text.primary, } } + + fn palette(&self) -> Option { + None + } + + fn name(&self) -> &str { + "Liana" + } } diff --git a/liana-ui/src/theme/overlay.rs b/liana-ui/src/theme/overlay.rs index 610cd4e4a..d535de1f3 100644 --- a/liana-ui/src/theme/overlay.rs +++ b/liana-ui/src/theme/overlay.rs @@ -1,7 +1,7 @@ pub use iced::widget::overlay::menu::Catalog; use iced::{ widget::overlay::menu::{Style, StyleFn}, - Border, + Border, Shadow, }; use super::Theme; @@ -35,5 +35,6 @@ pub fn primary(theme: &Theme) -> Style { ..Default::default() } }, + shadow: Shadow::default(), } } diff --git a/liana-ui/src/theme/pick_list.rs b/liana-ui/src/theme/pick_list.rs index f5454b5a3..ac9e9de87 100644 --- a/liana-ui/src/theme/pick_list.rs +++ b/liana-ui/src/theme/pick_list.rs @@ -1,7 +1,7 @@ use iced::widget::overlay::menu::Style as MenuStyle; use iced::{ widget::pick_list::{Catalog, Status, Style, StyleFn}, - Border, + Border, Shadow, }; use super::palette::Menu; @@ -25,7 +25,7 @@ pub fn primary(theme: &Theme, status: Status) -> Style { let style = match status { Status::Active => theme.colors.buttons.pick_list.active, Status::Hovered => theme.colors.buttons.pick_list.hovered, - Status::Opened => theme.colors.buttons.pick_list.hovered, + Status::Opened { .. } => theme.colors.buttons.pick_list.hovered, }; Style { text_color: style.text, @@ -62,6 +62,7 @@ impl From for MenuStyle { text_color: value.text, selected_text_color: value.selected_text, selected_background: value.selected_background.into(), + shadow: Shadow::default(), } } } diff --git a/liana-ui/src/theme/rule.rs b/liana-ui/src/theme/rule.rs index 207abd2d0..2a5abc046 100644 --- a/liana-ui/src/theme/rule.rs +++ b/liana-ui/src/theme/rule.rs @@ -18,9 +18,9 @@ impl Catalog for Theme { pub fn default(theme: &Theme) -> Style { Style { color: theme.colors.rule, - width: 2, radius: 0.0.into(), fill_mode: FillMode::Full, + snap: true, } } @@ -28,8 +28,8 @@ pub fn default(theme: &Theme) -> Style { pub fn accent(theme: &Theme) -> Style { Style { color: theme.colors.text.accent, - width: 3, radius: 2.0.into(), fill_mode: FillMode::Percent(30.0), + snap: true, } } diff --git a/liana-ui/src/theme/scrollable.rs b/liana-ui/src/theme/scrollable.rs index c8455c49d..76e9c2ed7 100644 --- a/liana-ui/src/theme/scrollable.rs +++ b/liana-ui/src/theme/scrollable.rs @@ -1,9 +1,9 @@ use iced::{ widget::{ container, - scrollable::{Catalog, Rail, Scroller, Status, Style, StyleFn}, + scrollable::{AutoScroll, Catalog, Rail, Scroller, Status, Style, StyleFn}, }, - Border, Color, Shadow, + Background, Border, Color, Shadow, }; use super::Theme; @@ -25,7 +25,7 @@ pub fn primary(theme: &Theme, status: Status) -> Style { background: None, border: Border::default(), scroller: Scroller { - color: theme.colors.general.scrollable, + background: Background::Color(theme.colors.general.scrollable), border: Border { radius: 8.0.into(), width: 0.0, @@ -45,10 +45,17 @@ pub fn primary(theme: &Theme, status: Status) -> Style { color: Color::TRANSPARENT, }, shadow: Shadow::default(), + snap: false, }, vertical_rail: rail, horizontal_rail: rail, gap: None, + auto_scroll: AutoScroll { + background: Background::Color(Color::TRANSPARENT), + border: Border::default(), + shadow: Shadow::default(), + icon: Color::TRANSPARENT, + }, }, } } diff --git a/liana-ui/src/theme/toggler.rs b/liana-ui/src/theme/toggler.rs index b9c59b53e..f4fdb3619 100644 --- a/liana-ui/src/theme/toggler.rs +++ b/liana-ui/src/theme/toggler.rs @@ -1,4 +1,5 @@ use iced::widget::toggler::{Catalog, Status, Style, StyleFn}; +use iced::Background; use super::Theme; @@ -17,20 +18,26 @@ impl Catalog for Theme { pub fn primary(theme: &Theme, status: Status) -> Style { match status { Status::Active { is_toggled: true } | Status::Hovered { is_toggled: true } => Style { - background: theme.colors.togglers.on.background, + background: Background::Color(theme.colors.togglers.on.background), background_border_width: 1.0, background_border_color: theme.colors.togglers.on.background_border, - foreground: theme.colors.togglers.on.foreground, + foreground: Background::Color(theme.colors.togglers.on.foreground), foreground_border_width: 1.0, foreground_border_color: theme.colors.togglers.on.foreground_border, + text_color: None, + border_radius: None, + padding_ratio: 0.1, }, _ => Style { - background: theme.colors.togglers.off.background, + background: Background::Color(theme.colors.togglers.off.background), background_border_width: 1.0, background_border_color: theme.colors.togglers.off.background_border, - foreground: theme.colors.togglers.off.foreground, + foreground: Background::Color(theme.colors.togglers.off.foreground), foreground_border_width: 1.0, foreground_border_color: theme.colors.togglers.off.foreground_border, + text_color: None, + border_radius: None, + padding_ratio: 0.1, }, } } diff --git a/liana-ui/src/widget/menu.rs b/liana-ui/src/widget/menu.rs index 2f51e3cc4..6118bb803 100644 --- a/liana-ui/src/widget/menu.rs +++ b/liana-ui/src/widget/menu.rs @@ -5,7 +5,7 @@ use iced::widget::scrollable::{self, Scrollable}; use iced_core::alignment; use iced_core::border::{self}; use iced_core::clipboard::{self, Clipboard}; -use iced_core::event::{self, Event}; +use iced_core::event::Event; use iced_core::layout::{self, Layout}; use iced_core::mouse; use iced_core::overlay; @@ -154,11 +154,11 @@ impl Default for State { struct Overlay<'a, 'b, Message, Theme, Renderer> where Theme: Catalog, - Renderer: iced_core::Renderer, + Renderer: text::Renderer, { position: Point, state: &'a mut Tree, - list: Scrollable<'a, Message, Theme, Renderer>, + list: Element<'a, Message, Theme, Renderer>, width: f32, target_height: f32, class: &'a ::Class<'b>, @@ -204,7 +204,8 @@ where class, }); - state.tree.diff(&list as &dyn Widget<_, _, _>); + let list: Element<'a, Message, Theme, Renderer> = list.into(); + state.tree.diff(&list); Self { position, @@ -240,7 +241,10 @@ where ) .width(self.width); - let node = self.list.layout(self.state, renderer, &limits); + let node = self + .list + .as_widget_mut() + .layout(self.state, renderer, &limits); let size = node.size(); node.move_to(if space_below > space_above { @@ -250,31 +254,35 @@ where }) } - fn on_event( + fn update( &mut self, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, - ) -> event::Status { + ) { let bounds = layout.bounds(); - self.list.on_event( + self.list.as_widget_mut().update( self.state, event, layout, cursor, renderer, clipboard, shell, &bounds, - ) + ); } fn mouse_interaction( &self, layout: Layout<'_>, cursor: mouse::Cursor, - viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { - self.list - .mouse_interaction(self.state, layout, cursor, viewport, renderer) + self.list.as_widget().mouse_interaction( + self.state, + layout, + cursor, + &layout.bounds(), + renderer, + ) } fn draw( @@ -298,7 +306,7 @@ where style.background, ); - self.list.draw( + self.list.as_widget().draw( self.state, renderer, theme, defaults, layout, cursor, &bounds, ); } @@ -335,7 +343,7 @@ where } fn layout( - &self, + &mut self, _tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, @@ -349,7 +357,7 @@ where let size = { let intrinsic = Size::new( 0.0, - (f32::from(text_line_height) + self.padding.vertical()) * self.options.len() as f32, + (f32::from(text_line_height) + self.padding.y()) * self.options.len() as f32, ); limits.resolve(Length::Fill, Length::Shrink, intrinsic) @@ -358,17 +366,17 @@ where layout::Node::new(size) } - fn on_event( + fn update( &mut self, _state: &mut Tree, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, _viewport: &Rectangle, - ) -> event::Status { + ) { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => { if cursor.is_over(layout.bounds()) { @@ -393,7 +401,7 @@ where if let Some(msg) = (self.on_select)(content) { shell.publish(msg); } - return event::Status::Captured; + return; } } } @@ -403,8 +411,8 @@ where if let Some(cursor_position) = cursor.position_in(layout.bounds()) { let text_size = self.text_size.unwrap_or_else(|| renderer.default_size()); - let option_height = f32::from(self.text_line_height.to_absolute(text_size)) - + self.padding.vertical(); + let option_height = + f32::from(self.text_line_height.to_absolute(text_size)) + self.padding.y(); let new_hovered_option = (cursor_position.y / option_height) as usize; @@ -415,8 +423,8 @@ where if let Some(cursor_position) = cursor.position_in(layout.bounds()) { let text_size = self.text_size.unwrap_or_else(|| renderer.default_size()); - let option_height = f32::from(self.text_line_height.to_absolute(text_size)) - + self.padding.vertical(); + let option_height = + f32::from(self.text_line_height.to_absolute(text_size)) + self.padding.y(); *self.hovered_option = Some((cursor_position.y / option_height) as usize); @@ -441,15 +449,13 @@ where if let Some(msg) = (self.on_select)(content) { shell.publish(msg); } - return event::Status::Captured; + return; } } } } _ => {} } - - event::Status::Ignored } fn mouse_interaction( @@ -484,7 +490,7 @@ where let text_size = self.text_size.unwrap_or_else(|| renderer.default_size()); let option_height = - f32::from(self.text_line_height.to_absolute(text_size)) + self.padding.vertical(); + f32::from(self.text_line_height.to_absolute(text_size)) + self.padding.y(); let offset = viewport.y - bounds.y; let start = (offset / option_height) as usize; @@ -525,8 +531,8 @@ where size: text_size, line_height: self.text_line_height, font: self.font.unwrap_or_else(|| renderer.default_font()), - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Center, + align_x: alignment::Horizontal::Left.into(), + align_y: alignment::Vertical::Center, shaping: self.text_shaping, wrapping: text::Wrapping::default(), }, diff --git a/liana-ui/src/widget/mod.rs b/liana-ui/src/widget/mod.rs index 869ba5d89..69388b130 100644 --- a/liana-ui/src/widget/mod.rs +++ b/liana-ui/src/widget/mod.rs @@ -22,3 +22,33 @@ pub type PickList<'a, T, L, V, Message> = iced::widget::PickList<'a, T, L, V, Message, Theme, Renderer>; pub type Scrollable<'a, Message> = iced::widget::Scrollable<'a, Message, Theme, Renderer>; pub type Svg<'a> = iced::widget::Svg<'a, Theme>; + +/// Extension trait to restore `push_maybe` for `Column`, removed in iced 0.14. +pub trait ColumnExt<'a, Message> { + fn push_maybe(self, child: Option>>) -> Self; +} + +impl<'a, Message> ColumnExt<'a, Message> for Column<'a, Message> { + fn push_maybe(self, child: Option>>) -> Self { + if let Some(child) = child { + self.push(child) + } else { + self + } + } +} + +/// Extension trait to restore `push_maybe` for `Row`, removed in iced 0.14. +pub trait RowExt<'a, Message> { + fn push_maybe(self, child: Option>>) -> Self; +} + +impl<'a, Message> RowExt<'a, Message> for Row<'a, Message> { + fn push_maybe(self, child: Option>>) -> Self { + if let Some(child) = child { + self.push(child) + } else { + self + } + } +} diff --git a/liana-ui/src/widget/modal.rs b/liana-ui/src/widget/modal.rs index c4a2736dd..5943d48a8 100644 --- a/liana-ui/src/widget/modal.rs +++ b/liana-ui/src/widget/modal.rs @@ -5,7 +5,6 @@ use iced::advanced::renderer; use iced::advanced::widget::{self, Tree, Widget}; use iced::advanced::{self, Clipboard, Shell}; use iced::alignment::Alignment; -use iced::event; use iced::mouse; use iced::{Element, Event, Length, Point, Rectangle, Size, Vector}; @@ -55,28 +54,28 @@ where } fn layout( - &self, + &mut self, tree: &mut widget::Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { self.base - .as_widget() + .as_widget_mut() .layout(&mut tree.children[0], renderer, limits) } - fn on_event( + fn update( &mut self, state: &mut widget::Tree, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, - ) -> event::Status { - self.base.as_widget_mut().on_event( + ) { + self.base.as_widget_mut().update( &mut state.children[0], event, layout, @@ -112,8 +111,9 @@ where fn overlay<'b>( &'b mut self, state: &'b mut Tree, - layout: Layout<'_>, + layout: Layout<'b>, _renderer: &Renderer, + _viewport: &Rectangle, translation: Vector, ) -> Option> { Some(overlay::Element::new(Box::new(Overlay { @@ -143,14 +143,14 @@ where } fn operate( - &self, + &mut self, state: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn widget::Operation, ) { self.base - .as_widget() + .as_widget_mut() .operate(&mut state.children[0], layout, renderer, operation); } } @@ -176,34 +176,34 @@ where let child = self .content - .as_widget() + .as_widget_mut() .layout(self.tree, renderer, &limits) .align(Alignment::Center, Alignment::Center, limits.max()); layout::Node::with_children(self.size, vec![child]).move_to(self.position) } - fn on_event( + fn update( &mut self, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, - ) -> event::Status { + ) { let content_bounds = layout.children().next().unwrap().bounds(); if let Some(message) = self.on_blur.as_ref() { - if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event { + if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = event { if !cursor.is_over(content_bounds) { shell.publish(message.clone()); - return event::Status::Captured; + return; } } } - self.content.as_widget_mut().on_event( + self.content.as_widget_mut().update( self.tree, event, layout.children().next().unwrap(), @@ -212,7 +212,7 @@ where clipboard, shell, &layout.bounds(), - ) + ); } fn draw( @@ -248,7 +248,7 @@ where renderer: &Renderer, operation: &mut dyn widget::Operation, ) { - self.content.as_widget().operate( + self.content.as_widget_mut().operate( self.tree, layout.children().next().unwrap(), renderer, @@ -260,27 +260,27 @@ where &self, layout: Layout<'_>, cursor: mouse::Cursor, - viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { self.content.as_widget().mouse_interaction( self.tree, layout.children().next().unwrap(), cursor, - viewport, + &layout.bounds(), renderer, ) } fn overlay<'c>( &'c mut self, - layout: Layout<'_>, + layout: Layout<'c>, renderer: &Renderer, ) -> Option> { self.content.as_widget_mut().overlay( self.tree, layout.children().next().unwrap(), renderer, + &layout.bounds(), Vector::ZERO, ) } diff --git a/liana-ui/src/widget/text_input.rs b/liana-ui/src/widget/text_input.rs index 1c6585a98..9e2c4f6fc 100644 --- a/liana-ui/src/widget/text_input.rs +++ b/liana-ui/src/widget/text_input.rs @@ -7,7 +7,7 @@ use iced::widget::overlay::menu; use iced::widget::text_input::{Catalog, Status, Style, StyleFn, Value}; use iced_core::clipboard::{self, Clipboard}; -use iced_core::event::{self, Event}; +use iced_core::event::Event; use iced_core::keyboard; use iced_core::keyboard::key; use iced_core::layout; @@ -231,8 +231,8 @@ where content: self.placeholder.as_str(), bounds: Size::new(f32::INFINITY, text_bounds.height), size: text_size, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Center, + align_x: alignment::Horizontal::Left.into(), + align_y: alignment::Vertical::Center, shaping: text::Shaping::Advanced, wrapping: text::Wrapping::default(), }; @@ -256,8 +256,8 @@ where font: icon.font, size: icon.size.unwrap_or_else(|| renderer.default_size()), bounds: Size::new(f32::INFINITY, text_bounds.height), - horizontal_alignment: alignment::Horizontal::Center, - vertical_alignment: alignment::Vertical::Center, + align_x: alignment::Horizontal::Center.into(), + align_y: alignment::Vertical::Center, shaping: text::Shaping::Advanced, wrapping: text::Wrapping::default(), }; @@ -325,7 +325,9 @@ where let status = if is_disabled { Status::Disabled } else if state.is_focused() { - Status::Focused + Status::Focused { + is_hovered: is_mouse_over, + } } else if is_mouse_over { Status::Hovered } else { @@ -503,38 +505,38 @@ where } fn layout( - &self, + &mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - self.layout(tree, renderer, limits, None) + TextInput::layout(self, tree, renderer, limits, None) } fn operate( - &self, + &mut self, tree: &mut Tree, - _layout: Layout<'_>, + layout: Layout<'_>, _renderer: &Renderer, operation: &mut dyn Operation, ) { let state = tree.state.downcast_mut::>(); - operation.focusable(state, self.id.as_ref().map(|id| &id.0)); - operation.text_input(state, self.id.as_ref().map(|id| &id.0)); + operation.focusable(self.id.as_ref().map(|id| &id.0), layout.bounds(), state); + operation.text_input(self.id.as_ref().map(|id| &id.0), layout.bounds(), state); } - fn on_event( + fn update( &mut self, tree: &mut Tree, - event: Event, + event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, _viewport: &Rectangle, - ) -> event::Status { + ) { let update_cache = |state, value| { replace_paragraph( renderer, @@ -556,12 +558,12 @@ where // bounds or on the drop-down, either way we close the overlay. state.menu.is_open = false; - return event::Status::Captured; + return; } else if cursor.is_over(layout.bounds()) { state.menu.is_open = true; - return event::Status::Captured; + return; } else { - return event::Status::Ignored; + return; } } Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) @@ -659,7 +661,7 @@ where state.last_click = Some(click); - return event::Status::Captured; + return; } } Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) @@ -700,7 +702,7 @@ where .cursor .select_range(state.cursor.start(&value), position); - return event::Status::Captured; + return; } } Event::Keyboard(keyboard::Event::KeyPressed { key, text, .. }) => { @@ -721,13 +723,13 @@ where ); } - return event::Status::Captured; + return; } keyboard::Key::Character("x") if state.keyboard_modifiers.command() && !self.is_secure => { let Some(on_input) = &self.on_input else { - return event::Status::Ignored; + return; }; if let Some((start, end)) = state.cursor.selection(&self.value) { @@ -745,14 +747,14 @@ where update_cache(state, &self.value); - return event::Status::Captured; + return; } keyboard::Key::Character("v") if state.keyboard_modifiers.command() && !state.keyboard_modifiers.alt() => { let Some(on_input) = &self.on_input else { - return event::Status::Ignored; + return; }; let content = match state.is_pasting.take() { @@ -784,19 +786,19 @@ where update_cache(state, &self.value); - return event::Status::Captured; + return; } keyboard::Key::Character("a") if state.keyboard_modifiers.command() => { state.cursor.select_all(&self.value); - return event::Status::Captured; + return; } _ => {} } if let Some(text) = text { let Some(on_input) = &self.on_input else { - return event::Status::Ignored; + return; }; state.is_pasting = None; @@ -813,7 +815,7 @@ where update_cache(state, &self.value); - return event::Status::Captured; + return; } } @@ -825,7 +827,7 @@ where } keyboard::Key::Named(key::Named::Backspace) => { let Some(on_input) = &self.on_input else { - return event::Status::Ignored; + return; }; if modifiers.jump() && state.cursor.selection(&self.value).is_none() { @@ -847,7 +849,7 @@ where } keyboard::Key::Named(key::Named::Delete) => { let Some(on_input) = &self.on_input else { - return event::Status::Ignored; + return; }; if modifiers.jump() && state.cursor.selection(&self.value).is_none() { @@ -945,12 +947,12 @@ where keyboard::Key::Named( key::Named::Tab | key::Named::ArrowUp | key::Named::ArrowDown, ) => { - return event::Status::Ignored; + return; } _ => {} } - return event::Status::Captured; + return; } } Event::Keyboard(keyboard::Event::KeyReleased { key, .. }) => { @@ -964,12 +966,12 @@ where keyboard::Key::Named( key::Named::Tab | key::Named::ArrowUp | key::Named::ArrowDown, ) => { - return event::Status::Ignored; + return; } _ => {} } - return event::Status::Captured; + return; } state.is_pasting = None; @@ -977,7 +979,7 @@ where Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { let state = state::(tree); - state.keyboard_modifiers = modifiers; + state.keyboard_modifiers = *modifiers; } Event::Window(window::Event::Unfocused) => { let state = state::(tree); @@ -993,7 +995,7 @@ where focus.is_window_focused = true; focus.updated_at = Instant::now(); - shell.request_redraw(window::RedrawRequest::NextFrame); + shell.request_redraw(); } } Event::Window(window::Event::RedrawRequested(now)) => { @@ -1001,21 +1003,19 @@ where if let Some(focus) = &mut state.is_focused { if focus.is_window_focused { - focus.now = now; + focus.now = *now; let millis_until_redraw = CURSOR_BLINK_INTERVAL_MILLIS - - (now - focus.updated_at).as_millis() % CURSOR_BLINK_INTERVAL_MILLIS; + - (*now - focus.updated_at).as_millis() % CURSOR_BLINK_INTERVAL_MILLIS; - shell.request_redraw(window::RedrawRequest::At( - now + Duration::from_millis(millis_until_redraw as u64), - )); + shell.request_redraw_at( + *now + Duration::from_millis(millis_until_redraw as u64), + ); } } } _ => {} } - - event::Status::Ignored } fn draw( @@ -1053,8 +1053,9 @@ where fn overlay<'b>( &'b mut self, tree: &'b mut Tree, - layout: Layout<'_>, + layout: Layout<'b>, renderer: &Renderer, + _viewport: &Rectangle, translation: Vector, ) -> Option> { let state = tree.state.downcast_mut::>(); @@ -1122,11 +1123,11 @@ where *state_value = paragraph::Plain::new(Text { font, line_height, - content: &value.to_string(), + content: value.to_string(), bounds: Size::new(f32::INFINITY, text_bounds.height), size: text_size, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, + align_x: alignment::Horizontal::Left.into(), + align_y: alignment::Vertical::Top, shaping: text::Shaping::Advanced, wrapping: text::Wrapping::default(), }); @@ -1197,7 +1198,7 @@ pub struct Id(widget::Id); impl Id { /// Creates a custom [`Id`]. - pub fn new(id: impl Into>) -> Self { + pub fn new(id: &'static str) -> Self { Self(widget::Id::new(id)) } @@ -1221,12 +1222,6 @@ impl From<&'static str> for Id { } } -impl From for Id { - fn from(id: String) -> Self { - Self::new(id) - } -} - /// Produces a [`Task`] that focuses the [`TextInput`] with the given [`Id`]. pub fn focus(id: impl Into) -> Task { task::effect(Action::widget(operation::focusable::focus(id.into().0))) @@ -1368,6 +1363,10 @@ impl operation::Focusable for State

{ } impl operation::TextInput for State

{ + fn text(&self) -> &str { + self.value.content() + } + fn move_cursor_to_front(&mut self) { State::move_cursor_to_front(self); } @@ -1383,6 +1382,10 @@ impl operation::TextInput for State

{ fn select_all(&mut self) { State::select_all(self); } + + fn select_range(&mut self, start: usize, end: usize) { + self.cursor.select_range(start, end); + } } fn offset(text_bounds: Rectangle, value: &Value, state: &State

) -> f32 { @@ -1463,11 +1466,11 @@ fn replace_paragraph( state.value = paragraph::Plain::new(Text { font, line_height, - content: &value.to_string(), + content: value.to_string(), bounds: Size::new(f32::INFINITY, text_bounds.height), size: text_size, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, + align_x: alignment::Horizontal::Left.into(), + align_y: alignment::Vertical::Top, shaping: text::Shaping::Advanced, wrapping: text::Wrapping::default(), }); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d36ebb47..89a22d9ff 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.85.1" +channel = "1.88.0" profile = "default" components = ["rust-src", "rust-analyzer"] targets = ["x86_64-pc-windows-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin"] From 0d68b6aa47682f659ba51775d2a772eaf28e6fb4 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 10 Apr 2026 12:30:58 +0200 Subject: [PATCH 2/4] ci: bump rust version --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 55f4f12e2..7f7515294 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.85.0 + toolchain: 1.88.0 components: rustfmt, clippy override: true - name: rustfmt @@ -27,7 +27,7 @@ jobs: strategy: matrix: toolchain: - - 1.85.0 + - 1.88.0 - nightly os: - ubuntu-latest From 740f802aded245e7fe9aef0da4eba8dd05af8dfa Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 10 Apr 2026 14:21:33 +0200 Subject: [PATCH 3/4] fix clippy errors --- liana-business/build.rs | 8 +-- .../business-installer/src/client.rs | 36 +++++------ .../business-installer/src/state/app.rs | 10 ++-- .../business-installer/src/state/update.rs | 12 ++-- .../src/state/views/xpub/mod.rs | 6 +- .../business-installer/src/views/mod.rs | 2 +- .../src/views/paths/modal.rs | 6 +- .../template_visualization.rs | 38 ++++-------- .../src/views/xpub/modal.rs | 2 +- .../business-installer/src/views/xpub/view.rs | 2 +- liana-business/src/main.rs | 2 +- liana-business/src/settings/mod.rs | 7 +-- liana-business/src/settings/views/mod.rs | 2 +- liana-connect/src/keys/api.rs | 6 +- liana-connect/src/keys/mod.rs | 2 +- liana-connect/src/ws_business/models.rs | 28 ++++----- liana-connect/src/ws_business/protocol.rs | 10 ++-- liana-gui/build.rs | 6 +- liana-gui/src/app/config.rs | 16 ++--- liana-gui/src/app/error.rs | 31 +++++----- liana-gui/src/app/mod.rs | 7 ++- liana-gui/src/app/settings/mod.rs | 31 +++++----- liana-gui/src/app/state/export.rs | 2 +- liana-gui/src/app/state/label.rs | 2 + liana-gui/src/app/state/psbt.rs | 3 +- liana-gui/src/app/state/receive.rs | 3 +- liana-gui/src/app/state/settings/wallet.rs | 1 + liana-gui/src/app/state/spend/step.rs | 2 + liana-gui/src/app/state/transactions.rs | 1 + liana-gui/src/app/view/coins.rs | 4 +- liana-gui/src/app/view/export.rs | 2 +- liana-gui/src/app/view/fiat.rs | 12 ++-- liana-gui/src/app/view/home.rs | 4 +- liana-gui/src/app/view/message.rs | 1 + liana-gui/src/app/view/settings/mod.rs | 12 ++-- liana-gui/src/app/view/transactions.rs | 2 +- liana-gui/src/app/view/warning.rs | 10 ++-- liana-gui/src/app/wallet.rs | 4 +- liana-gui/src/args.rs | 6 +- liana-gui/src/daemon/client/error.rs | 6 +- liana-gui/src/daemon/client/jsonrpc.rs | 16 +++-- liana-gui/src/daemon/embedded.rs | 2 +- liana-gui/src/daemon/mod.rs | 10 ++-- liana-gui/src/daemon/model.rs | 6 +- liana-gui/src/delete.rs | 8 +-- liana-gui/src/download.rs | 2 +- liana-gui/src/export.rs | 22 ++++--- liana-gui/src/gui/mod.rs | 1 + liana-gui/src/gui/pane.rs | 1 + liana-gui/src/gui/tab.rs | 4 +- liana-gui/src/hw.rs | 4 +- liana-gui/src/installer/context.rs | 1 + liana-gui/src/installer/decrypt.rs | 3 +- liana-gui/src/installer/message.rs | 1 + liana-gui/src/installer/mod.rs | 59 +++++++++---------- liana-gui/src/installer/step/backend.rs | 3 +- .../installer/step/descriptor/editor/key.rs | 3 +- .../src/installer/step/import_descriptor.rs | 1 + liana-gui/src/installer/step/node/bitcoind.rs | 10 ++-- liana-gui/src/installer/view/editor/mod.rs | 2 +- liana-gui/src/installer/view/mod.rs | 17 +++--- liana-gui/src/launcher.rs | 3 +- liana-gui/src/loader.rs | 10 ++-- liana-gui/src/main.rs | 2 +- liana-gui/src/node/bitcoind.rs | 30 +++++----- .../services/connect/client/backend/mod.rs | 59 ++++++++----------- .../src/services/connect/client/cache.rs | 40 ++++++------- liana-gui/src/services/connect/client/mod.rs | 2 +- liana-gui/src/services/connect/login.rs | 11 ++-- liana-gui/src/services/fiat/api.rs | 8 +-- liana-ui/src/component/amount.rs | 2 +- liana-ui/src/component/hw.rs | 36 +++++------ liana-ui/src/component/notification.rs | 2 +- liana-ui/src/component/toast.rs | 2 +- liana-ui/src/widget/menu.rs | 2 - liana-ui/src/widget/text_input.rs | 12 +--- liana/src/descriptors/analysis.rs | 19 +++--- liana/src/descriptors/keys.rs | 4 +- liana/src/descriptors/mod.rs | 8 +-- liana/src/random.rs | 6 +- liana/src/signer.rs | 8 +-- liana/src/spend.rs | 18 +++--- lianad/src/bin/cli.rs | 8 +-- lianad/src/bin/daemon.rs | 10 ++-- lianad/src/bitcoin/d/mod.rs | 19 +++--- lianad/src/bitcoin/electrum/client.rs | 2 +- lianad/src/bitcoin/electrum/mod.rs | 11 ++-- lianad/src/commands/mod.rs | 44 +++++++------- lianad/src/config.rs | 14 ++--- lianad/src/database/mod.rs | 6 +- lianad/src/database/sqlite/mod.rs | 20 +++---- lianad/src/database/sqlite/utils.rs | 3 +- lianad/src/jsonrpc/api.rs | 28 ++++----- lianad/src/jsonrpc/server/unix.rs | 2 +- lianad/src/lib.rs | 11 ++-- 95 files changed, 464 insertions(+), 521 deletions(-) diff --git a/liana-business/build.rs b/liana-business/build.rs index c405086ae..96a64d09e 100644 --- a/liana-business/build.rs +++ b/liana-business/build.rs @@ -20,14 +20,14 @@ fn main() { } if let Err(e) = res.compile() { - eprintln!("Failed to compile Windows resources: {}", e); - panic!("Windows resource compilation failed: {}", e); + eprintln!("Failed to compile Windows resources: {e}"); + panic!("Windows resource compilation failed: {e}"); } // Explicitly link the resource object file (needed for cross-compilation) - let resource_obj = format!("{}/resource.o", out_dir); + let resource_obj = format!("{out_dir}/resource.o"); if std::path::Path::new(&resource_obj).exists() { - println!("cargo:rustc-link-arg-bins={}", resource_obj); + println!("cargo:rustc-link-arg-bins={resource_obj}"); } } } diff --git a/liana-business/business-installer/src/client.rs b/liana-business/business-installer/src/client.rs index 0578209ef..22babde02 100644 --- a/liana-business/business-installer/src/client.rs +++ b/liana-business/business-installer/src/client.rs @@ -76,7 +76,7 @@ fn get_service_config_blocking(network: Network) -> Result Some(cfg), - Err(_) => None, - }; + let config = get_service_config_blocking(network).ok(); let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { @@ -869,7 +866,7 @@ fn wss_thread( let url = if url.starts_with("ws://") || url.starts_with("wss://") { url } else { - format!("wss://{}", url) + format!("wss://{url}") }; tracing::debug!("wss_thread: connecting to {}", url); @@ -1121,7 +1118,7 @@ fn handle_wss_message( n_waker: &SharedWaker, ) -> Result<(), String> { let (response, request_id) = Response::from_ws_message(msg) - .map_err(|e| format!("Failed to convert WSS message: {}", e))?; + .map_err(|e| format!("Failed to convert WSS message: {e}"))?; let request_id = request_id.and_then(|s| Uuid::try_parse(&s).ok()); // Unknown or unparseable message — already logged in protocol layer. @@ -1201,8 +1198,7 @@ fn handle_wss_message( if !matches_response_type(&response, expected) { tracing::error!("Response {response:?} do not match request {request:?}"); return Err(format!( - "Response type mismatch for {req_id}: expected {:?}, got {:?}", - expected, response + "Response type mismatch for {req_id}: expected {expected:?}, got {response:?}" )); } // Remove from cache on successful match @@ -1954,8 +1950,8 @@ impl DummyServer { self.shutdown_sender = Some(shutdown_sender); let handle = thread::spawn(move || { - let listener = TcpListener::bind(format!("127.0.0.1:{}", port)) - .expect("Failed to bind to address"); + let listener = + TcpListener::bind(format!("127.0.0.1:{port}")).expect("Failed to bind to address"); listener.set_nonblocking(false).unwrap(); // Accept one connection @@ -2634,7 +2630,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -2665,9 +2661,7 @@ mod tests { assert!( connected_notified || is_connected, - "Client should have connected (notification: {}, state: {})", - connected_notified, - is_connected + "Client should have connected (notification: {connected_notified}, state: {is_connected})" ); client.close(); @@ -2703,7 +2697,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -2771,7 +2765,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -2840,7 +2834,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -2909,7 +2903,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -2961,7 +2955,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); @@ -3036,7 +3030,7 @@ mod tests { let notif_waker: SharedWaker = Arc::new(Mutex::new(None)); let mut client = Client::new(sender, notif_waker); client.set_token("test-token".to_string()); - let url = format!("ws://127.0.0.1:{}", port); + let url = format!("ws://127.0.0.1:{port}"); let (sender, receiver) = channel::unbounded(); client.connect_ws(url, 1, sender); diff --git a/liana-business/business-installer/src/state/app.rs b/liana-business/business-installer/src/state/app.rs index bd8fd1217..41445aeb6 100644 --- a/liana-business/business-installer/src/state/app.rs +++ b/liana-business/business-installer/src/state/app.rs @@ -65,35 +65,35 @@ impl AppState { if mins == 1 { "1 minute ago".to_string() } else { - format!("{} minutes ago", mins) + format!("{mins} minutes ago") } } else if diff < DAY { let hours = diff / HOUR; if hours == 1 { "1 hour ago".to_string() } else { - format!("{} hours ago", hours) + format!("{hours} hours ago") } } else if diff < WEEK { let days = diff / DAY; if days == 1 { "1 day ago".to_string() } else { - format!("{} days ago", days) + format!("{days} days ago") } } else if diff < MONTH { let weeks = diff / WEEK; if weeks == 1 { "1 week ago".to_string() } else { - format!("{} weeks ago", weeks) + format!("{weeks} weeks ago") } } else { let months = diff / MONTH; if months == 1 { "1 month ago".to_string() } else { - format!("{} months ago", months) + format!("{months} months ago") } } } diff --git a/liana-business/business-installer/src/state/update.rs b/liana-business/business-installer/src/state/update.rs index e90bf062a..d5d53d063 100644 --- a/liana-business/business-installer/src/state/update.rs +++ b/liana-business/business-installer/src/state/update.rs @@ -1055,10 +1055,7 @@ impl State { // Show warning modal self.on_warning_show_modal( "Connection Failed", - format!( - "Failed to connect with account {}. The session may have expired.", - failed_email - ), + format!("Failed to connect with account {failed_email}. The session may have expired."), ); // Decide next state based on remaining accounts @@ -1403,7 +1400,7 @@ impl State { .keys .get(&key_id) .map(|k| k.alias.clone()) - .unwrap_or_else(|| format!("Key {}", key_id)); + .unwrap_or_else(|| format!("Key {key_id}")); deleted_keys.push((key_id, key_alias)); } } @@ -1427,8 +1424,7 @@ impl State { conflict_type: ConflictType::KeyInPathDeleted, title: "Key Removed".to_string(), message: format!( - "\"{}\" was deleted by another user and has been removed from your path selection.", - first_key_alias + "\"{first_key_alias}\" was deleted by another user and has been removed from your path selection." ), }); return; @@ -1844,7 +1840,7 @@ impl State { .to_string(); Ok((xpub, filename)) } - Err(e) => Err(format!("Failed to read file: {}", e)), + Err(e) => Err(format!("Failed to read file: {e}")), } } else { // User cancelled - return empty error to do nothing diff --git a/liana-business/business-installer/src/state/views/xpub/mod.rs b/liana-business/business-installer/src/state/views/xpub/mod.rs index a474767f0..544a75c93 100644 --- a/liana-business/business-installer/src/state/views/xpub/mod.rs +++ b/liana-business/business-installer/src/state/views/xpub/mod.rs @@ -213,7 +213,7 @@ pub fn validate_xpub_format(xpub_str: &str) -> Result Result( for (key_id, key) in state.app.keys.iter() { let is_selected = modal_state.selected_key_ids.contains(key_id); let name = if key.alias.is_empty() { - format!("Key {}", key_id) + format!("Key {key_id}") } else { key.alias.clone() }; @@ -92,7 +92,7 @@ pub fn edit_path_modal_view<'a>( let label = if identity_str.is_empty() { name } else { - format!("{} ({})", name, identity_str) + format!("{name} ({identity_str})") }; col = col.push( checkbox(is_selected) @@ -123,7 +123,7 @@ pub fn edit_path_modal_view<'a>( // Threshold row (only shown when 2+ keys are selected) let threshold_row: Option> = threshold_enabled.then_some({ - let threshold_label_text = format!("Threshold (1-{}):", selected_count); + let threshold_label_text = format!("Threshold (1-{selected_count}):"); let threshold_label: Element<'_, Msg> = text::p1_medium(threshold_label_text) .style(theme::text::primary) .into(); diff --git a/liana-business/business-installer/src/views/template_builder/template_visualization.rs b/liana-business/business-installer/src/views/template_builder/template_visualization.rs index 5586a2784..49988ff83 100644 --- a/liana-business/business-installer/src/views/template_builder/template_visualization.rs +++ b/liana-business/business-installer/src/views/template_builder/template_visualization.rs @@ -55,7 +55,7 @@ fn get_secondary_color(index: usize, total_count: usize) -> String { let g = (start_g + (end_g - start_g) * factor) as u8; let b = (start_b + (end_b - start_b) * factor) as u8; - format!("#{:02x}{:02x}{:02x}", r, g, b) + format!("#{r:02x}{g:02x}{b:02x}") } /// Generate a single "r" shape SVG as an iced Element. @@ -86,28 +86,10 @@ pub fn r_shape(index: usize, count: usize) -> Element<'static, Msg> { let arc_end_y = center_y; let svg_content = format!( - r#" - - - "#, - width, - height, - width, - height, - center_x, - stem_top, - center_x, - stem_bottom, - color, - thickness, - center_x, - arc_start_y, - radius, - radius, - arc_end_x, - arc_end_y, - color, - thickness + r#" + + + "# ); let svg_handle = iced::widget::svg::Handle::from_memory(svg_content.as_bytes().to_vec()); @@ -137,21 +119,21 @@ fn format_timelock_human(timelock: &ws_business::Timelock) -> String { if months == 1 { "After 1 month".to_string() } else { - format!("After {} months", months) + format!("After {months} months") } } else if blocks >= BLOCKS_PER_DAY { let days = blocks / BLOCKS_PER_DAY; if days == 1 { "After 1 day".to_string() } else { - format!("After {} days", days) + format!("After {days} days") } } else { let hours = blocks / BLOCKS_PER_HOUR; if hours <= 1 { "After 1 hour".to_string() } else { - format!("After {} hours", hours) + format!("After {hours} hours") } } } @@ -188,9 +170,9 @@ fn path_card( } else { let names = key_aliases.join(", "); if threshold >= key_count { - format!("All of {}", names) + format!("All of {names}") } else { - format!("{} of {}", threshold, names) + format!("{threshold} of {names}") } }; diff --git a/liana-business/business-installer/src/views/xpub/modal.rs b/liana-business/business-installer/src/views/xpub/modal.rs index 2a991df11..eff70f52f 100644 --- a/liana-business/business-installer/src/views/xpub/modal.rs +++ b/liana-business/business-installer/src/views/xpub/modal.rs @@ -226,7 +226,7 @@ fn details_view(modal_state: &XpubEntryModalState) -> Element<'_, Msg> { /// Format account for display (e.g., "Account #0") fn format_account(account: ChildNumber) -> String { let index = account.to_string().replace("'", ""); - format!("Account #{}", index) + format!("Account #{index}") } /// Render the Hardware Wallet section (Select step only) diff --git a/liana-business/business-installer/src/views/xpub/view.rs b/liana-business/business-installer/src/views/xpub/view.rs index db52513fe..5543478e1 100644 --- a/liana-business/business-installer/src/views/xpub/view.rs +++ b/liana-business/business-installer/src/views/xpub/view.rs @@ -152,7 +152,7 @@ pub fn xpub_view(state: &State) -> Element<'_, Msg> { .spacing(10) .align_x(Alignment::Center) .padding(20) - .push(text::h2(format!("{} - Set Keys", wallet_name))) + .push(text::h2(format!("{wallet_name} - Set Keys"))) .push(Space::new().height(10)) .push(instruction); diff --git a/liana-business/src/main.rs b/liana-business/src/main.rs index c848daa1f..9608c1a6c 100644 --- a/liana-business/src/main.rs +++ b/liana-business/src/main.rs @@ -81,7 +81,7 @@ fn main() -> Result<(), Box> { .run() { log::error!("{}", e); - Err(format!("Failed to launch UI: {}", e).into()) + Err(format!("Failed to launch UI: {e}").into()) } else { Ok(()) } diff --git a/liana-business/src/settings/mod.rs b/liana-business/src/settings/mod.rs index 9cc56660e..5d9e88917 100644 --- a/liana-business/src/settings/mod.rs +++ b/liana-business/src/settings/mod.rs @@ -92,12 +92,11 @@ impl BusinessSettings { std::fs::read(path) .map_err(|e| match e.kind() { std::io::ErrorKind::NotFound => SettingsError::NotFound, - _ => SettingsError::ReadingFile(format!("Reading settings file: {}", e)), + _ => SettingsError::ReadingFile(format!("Reading settings file: {e}")), }) .and_then(|file_content| { - serde_json::from_slice::(&file_content).map_err(|e| { - SettingsError::ReadingFile(format!("Parsing settings file: {}", e)) - }) + serde_json::from_slice::(&file_content) + .map_err(|e| SettingsError::ReadingFile(format!("Parsing settings file: {e}"))) }) } } diff --git a/liana-business/src/settings/views/mod.rs b/liana-business/src/settings/views/mod.rs index 2bbff7a22..9fb2e35b8 100644 --- a/liana-business/src/settings/views/mod.rs +++ b/liana-business/src/settings/views/mod.rs @@ -153,7 +153,7 @@ pub fn about_view() -> Element<'static, Msg> { .push( Row::new() .push(Space::new().width(Length::Fill)) - .push(text(format!("liana-business v{}", VERSION))), + .push(text(format!("liana-business v{VERSION}"))), ), ); diff --git a/liana-connect/src/keys/api.rs b/liana-connect/src/keys/api.rs index 47a7a5e65..d6448489a 100644 --- a/liana-connect/src/keys/api.rs +++ b/liana-connect/src/keys/api.rs @@ -27,8 +27,7 @@ impl<'de> Deserialize<'de> for KeyKind { "safetynet" => Ok(KeyKind::SafetyNet), "cosigner" => Ok(KeyKind::Cosigner), s => Err(de::Error::custom(format!( - "invalid value for KeyKind: '{}'", - s + "invalid value for KeyKind: '{s}'" ))), } } @@ -52,8 +51,7 @@ impl<'de> Deserialize<'de> for KeyStatus { "fetched" => Ok(KeyStatus::Fetched), "redeemed" => Ok(KeyStatus::Redeemed), s => Err(de::Error::custom(format!( - "invalid value for KeyStatus: '{}'", - s + "invalid value for KeyStatus: '{s}'" ))), } } diff --git a/liana-connect/src/keys/mod.rs b/liana-connect/src/keys/mod.rs index fbf2dec6a..e1bfc472d 100644 --- a/liana-connect/src/keys/mod.rs +++ b/liana-connect/src/keys/mod.rs @@ -17,7 +17,7 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Http(kind, e) => write!(f, "Http error: [{:?}] {}", kind, e), + Self::Http(kind, e) => write!(f, "Http error: [{kind:?}] {e}"), } } } diff --git a/liana-connect/src/ws_business/models.rs b/liana-connect/src/ws_business/models.rs index 549ff2ae4..3350ed47a 100644 --- a/liana-connect/src/ws_business/models.rs +++ b/liana-connect/src/ws_business/models.rs @@ -164,7 +164,7 @@ impl fmt::Display for DeviceKind { DeviceKind::Coldcard => write!(f, "Coldcard"), DeviceKind::ColdcardMk4 => write!(f, "ColdcardMk4"), DeviceKind::ColdcardQ => write!(f, "ColdcardQ"), - DeviceKind::Other(s) => write!(f, "{}", s), + DeviceKind::Other(s) => write!(f, "{s}"), } } } @@ -283,27 +283,27 @@ impl Display for Timelock { // Years if remaining >= BLOCKS_PER_YEAR { let years = remaining / BLOCKS_PER_YEAR; - parts.push(format!("{}y", years)); + parts.push(format!("{years}y")); remaining %= BLOCKS_PER_YEAR; } // Months if remaining >= BLOCKS_PER_MONTH { let months = remaining / BLOCKS_PER_MONTH; - parts.push(format!("{}m", months)); + parts.push(format!("{months}m")); remaining %= BLOCKS_PER_MONTH; } // Days if remaining >= BLOCKS_PER_DAY { let days = remaining / BLOCKS_PER_DAY; - parts.push(format!("{}d", days)); + parts.push(format!("{days}d")); remaining %= BLOCKS_PER_DAY; } // Blocks (only show if there are no larger units) if parts.is_empty() { - parts.push(format!("{} blocks", remaining)); + parts.push(format!("{remaining} blocks")); } write!(f, "{}", parts.join(" ")) @@ -606,7 +606,7 @@ mod wire_format_tests { // Test UUIDs - use parse_str instead of new_v4 (no v4 feature dependency) fn test_uuid(n: u8) -> Uuid { - Uuid::parse_str(&format!("12345678-1234-1234-1234-12345678900{}", n)).unwrap() + Uuid::parse_str(&format!("12345678-1234-1234-1234-12345678900{n}")).unwrap() } // Helper to roundtrip a type through JSON @@ -644,7 +644,7 @@ mod wire_format_tests { ]; for (status, expected) in cases { let json = serde_json::to_value(status).unwrap(); - assert_eq!(json, expected, "WalletStatus::{:?}", status); + assert_eq!(json, expected, "WalletStatus::{status:?}"); } } @@ -657,7 +657,7 @@ mod wire_format_tests { ]; for (role, expected) in cases { let json = serde_json::to_value(role).unwrap(); - assert_eq!(json, expected, "UserRole::{:?}", role); + assert_eq!(json, expected, "UserRole::{role:?}"); } } @@ -671,7 +671,7 @@ mod wire_format_tests { ]; for (kt, expected) in cases { let json = serde_json::to_value(kt).unwrap(); - assert_eq!(json, expected, "KeyType::{:?}", kt); + assert_eq!(json, expected, "KeyType::{kt:?}"); } } @@ -684,7 +684,7 @@ mod wire_format_tests { ]; for (src, expected) in cases { let json = serde_json::to_value(&src).unwrap(); - assert_eq!(json, expected, "XpubSource::{:?}", src); + assert_eq!(json, expected, "XpubSource::{src:?}"); } } @@ -700,7 +700,7 @@ mod wire_format_tests { ]; for (dk, expected) in known_cases { let json = serde_json::to_value(&dk).unwrap(); - assert_eq!(json, expected, "DeviceKind::{:?}", dk); + assert_eq!(json, expected, "DeviceKind::{dk:?}"); } // Other variant serializes as {"other": "value"} (snake_case) @@ -1520,7 +1520,7 @@ mod wire_format_tests { for (json_str, expected) in cases { // Test deserialization let parsed: WalletStatus = serde_json::from_str(json_str) - .unwrap_or_else(|_| panic!("should parse {}", json_str)); + .unwrap_or_else(|_| panic!("should parse {json_str}")); assert_eq!(parsed, expected); // Test serialization produces same string @@ -1587,9 +1587,9 @@ mod wire_format_tests { fn make_key(id: u8) -> Key { Key { id, - alias: format!("Key{}", id), + alias: format!("Key{id}"), description: "".to_string(), - identity: KeyIdentity::Email(format!("key{}@example.com", id)), + identity: KeyIdentity::Email(format!("key{id}@example.com")), key_type: KeyType::Internal, xpub: None, xpub_source: None, diff --git a/liana-connect/src/ws_business/protocol.rs b/liana-connect/src/ws_business/protocol.rs index 6e07a9079..dc7cae764 100644 --- a/liana-connect/src/ws_business/protocol.rs +++ b/liana-connect/src/ws_business/protocol.rs @@ -64,7 +64,7 @@ impl std::fmt::Display for WssConversionError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { WssConversionError::DeserializationFailed(msg) => { - write!(f, "Failed to deserialize WSS response: {}", msg) + write!(f, "Failed to deserialize WSS response: {msg}") } WssConversionError::InvalidMessageType => { write!(f, "Invalid WebSocket message type (expected Text)") @@ -214,7 +214,7 @@ fn parse_fetch_request(payload: Option) -> Result) -> Result { @@ -235,7 +235,7 @@ fn parse_edit_xpub_request(payload: Option) -> Result) -> Result Uuid { - Uuid::parse_str(&format!("12345678-1234-1234-1234-12345678900{}", n)).unwrap() + Uuid::parse_str(&format!("12345678-1234-1234-1234-12345678900{n}")).unwrap() } // ==================== REQUEST WIRE FORMAT TESTS ==================== diff --git a/liana-gui/build.rs b/liana-gui/build.rs index 318e897d8..07bc525b6 100644 --- a/liana-gui/build.rs +++ b/liana-gui/build.rs @@ -24,14 +24,14 @@ fn main() { } if let Err(e) = res.compile() { - eprintln!("Failed to compile Windows resources: {}", e); + eprintln!("Failed to compile Windows resources: {e}"); panic!("Windows resource compilation failed: {}", e); } // Explicitly link the resource object file (needed for cross-compilation) - let resource_obj = format!("{}/resource.o", out_dir); + let resource_obj = format!("{out_dir}/resource.o"); if std::path::Path::new(&resource_obj).exists() { - println!("cargo:rustc-link-arg-bins={}", resource_obj); + println!("cargo:rustc-link-arg-bins={resource_obj}"); } } } diff --git a/liana-gui/src/app/config.rs b/liana-gui/src/app/config.rs index b48bf06ee..3ab161745 100644 --- a/liana-gui/src/app/config.rs +++ b/liana-gui/src/app/config.rs @@ -31,11 +31,11 @@ impl Config { let config = std::fs::read(path) .map_err(|e| match e.kind() { std::io::ErrorKind::NotFound => ConfigError::NotFound, - _ => ConfigError::ReadingFile(format!("Reading configuration file: {}", e)), + _ => ConfigError::ReadingFile(format!("Reading configuration file: {e}")), }) .and_then(|file_content| { toml::from_slice::(&file_content).map_err(|e| { - ConfigError::ReadingFile(format!("Parsing configuration file: {}", e)) + ConfigError::ReadingFile(format!("Parsing configuration file: {e}")) }) })?; @@ -46,7 +46,7 @@ impl Config { pub fn to_file(&self, path: &Path) -> Result<(), ConfigError> { let content = toml::to_string(&self) - .map_err(|e| ConfigError::WritingFile(format!("Failed to serialize config: {}", e)))?; + .map_err(|e| ConfigError::WritingFile(format!("Failed to serialize config: {e}")))?; let mut config_file = OpenOptions::new() .write(true) @@ -73,7 +73,7 @@ impl Config { "trace" => Ok(filter::LevelFilter::TRACE), _ => Err(ConfigError::InvalidField( "log_level", - format!("Unknown value '{}'", level), + format!("Unknown value '{level}'"), )), } } else if let Some(true) = self.debug { @@ -98,11 +98,11 @@ impl std::fmt::Display for ConfigError { match self { Self::NotFound => write!(f, "Config file not found"), Self::InvalidField(field, message) => { - write!(f, "Config field {} is invalid: {}", field, message) + write!(f, "Config field {field} is invalid: {message}") } - Self::ReadingFile(e) => write!(f, "Error while reading file: {}", e), - Self::WritingFile(e) => write!(f, "Error while writing file: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), + Self::ReadingFile(e) => write!(f, "Error while reading file: {e}"), + Self::WritingFile(e) => write!(f, "Error while writing file: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), } } } diff --git a/liana-gui/src/app/error.rs b/liana-gui/src/app/error.rs index 9bbf46586..1154e7f91 100644 --- a/liana-gui/src/app/error.rs +++ b/liana-gui/src/app/error.rs @@ -12,6 +12,7 @@ use crate::{ }; #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum Error { Config(String), Wallet(WalletError), @@ -28,11 +29,11 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Config(e) => write!(f, "{}", e), - Self::Wallet(e) => write!(f, "{}", e), - Self::Spend(e) => write!(f, "{}", e), + Self::Config(e) => write!(f, "{e}"), + Self::Wallet(e) => write!(f, "{e}"), + Self::Spend(e) => write!(f, "{e}"), Self::Daemon(e) => match e { - DaemonError::Unexpected(e) => write!(f, "{}", e), + DaemonError::Unexpected(e) => write!(f, "{e}"), DaemonError::NoAnswer => write!(f, "Daemon did not answer"), DaemonError::DaemonStopped => write!(f, "Daemon stopped"), DaemonError::RpcSocket(Some(ErrorKind::ConnectionRefused), _) => { @@ -40,32 +41,32 @@ impl std::fmt::Display for Error { } DaemonError::RpcSocket(kind, e) => { if let Some(k) = kind { - write!(f, "{} [{:?}]", e, k) + write!(f, "{e} [{k:?}]") } else { - write!(f, "{}", e) + write!(f, "{e}") } } DaemonError::Start(e) => { - write!(f, "Failed to start daemon: {}", e) + write!(f, "Failed to start daemon: {e}") } DaemonError::ClientNotSupported => { write!(f, "Daemon client is not supported") } DaemonError::Rpc(code, e) => { - write!(f, "[{:?}] {}", code, e) + write!(f, "[{code:?}] {e}") } DaemonError::Http(code, e) => { - write!(f, "[{:?}] {}", code, e) + write!(f, "[{code:?}] {e}") } - DaemonError::CoinSelectionError => write!(f, "{}", e), - DaemonError::NotImplemented => write!(f, "{}", e), + DaemonError::CoinSelectionError => write!(f, "{e}"), + DaemonError::NotImplemented => write!(f, "{e}"), }, - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), - Self::HardwareWallet(e) => write!(f, "error: {}\nPlease check if the device is still connected and unlocked with the correct firmware open for the current network and no other application is accessing the device.", e), - Self::Desc(e) => write!(f, "Liana descriptor error: {}", e), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), + Self::HardwareWallet(e) => write!(f, "error: {e}\nPlease check if the device is still connected and unlocked with the correct firmware open for the current network and no other application is accessing the device."), + Self::Desc(e) => write!(f, "Liana descriptor error: {e}"), Self::ImportExport(e) => write!(f, "{e}"), Self::RestoreBackup(e) => write!(f, "{e}"), - Self::FiatPrice(e) => write!(f, "Fiat price error: {}", e), + Self::FiatPrice(e) => write!(f, "Fiat price error: {e}"), } } } diff --git a/liana-gui/src/app/mod.rs b/liana-gui/src/app/mod.rs index bb889b142..f23a604c8 100644 --- a/liana-gui/src/app/mod.rs +++ b/liana-gui/src/app/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::result_large_err)] + pub mod cache; pub mod config; pub mod menu; @@ -442,14 +444,13 @@ impl App { match daemon.get_fiat_rates().await { Ok(rates) => { tracing::trace!("Fiat: got rates from backend: {:?}", rates); - let key = format!("BTC{}", currency); + let key = format!("BTC{currency}"); let res = rates .get(&key) .copied() .ok_or_else(|| { PriceApiError::CannotParseData(format!( - "No rate for {}", - key + "No rate for {key}" )) }) .map(|value| GetPriceResult { diff --git a/liana-gui/src/app/settings/mod.rs b/liana-gui/src/app/settings/mod.rs index 8daf8a16a..8966c6f29 100644 --- a/liana-gui/src/app/settings/mod.rs +++ b/liana-gui/src/app/settings/mod.rs @@ -125,12 +125,11 @@ impl LianaSettings { std::fs::read(path) .map_err(|e| match e.kind() { std::io::ErrorKind::NotFound => SettingsError::NotFound, - _ => SettingsError::ReadingFile(format!("Reading settings file: {}", e)), + _ => SettingsError::ReadingFile(format!("Reading settings file: {e}")), }) .and_then(|file_content| { - serde_json::from_slice::(&file_content).map_err(|e| { - SettingsError::ReadingFile(format!("Parsing settings file: {}", e)) - }) + serde_json::from_slice::(&file_content) + .map_err(|e| SettingsError::ReadingFile(format!("Parsing settings file: {e}"))) }) } } @@ -195,16 +194,16 @@ where .truncate(false) .open(&path) .await - .map_err(|e| SettingsError::ReadingFile(format!("Opening file: {}", e)))? + .map_err(|e| SettingsError::ReadingFile(format!("Opening file: {e}")))? .lock_write() .await - .map_err(|e| SettingsError::ReadingFile(format!("Locking file: {:?}", e)))?; + .map_err(|e| SettingsError::ReadingFile(format!("Locking file: {e:?}")))?; let settings: S = if file_exists { let mut file_content = Vec::new(); file.read_to_end(&mut file_content) .await - .map_err(|e| SettingsError::ReadingFile(format!("Reading file content: {}", e)))?; + .map_err(|e| SettingsError::ReadingFile(format!("Reading file content: {e}")))?; serde_json::from_slice::(&file_content) .map_err(|e| SettingsError::ReadingFile(e.to_string()))? @@ -222,11 +221,11 @@ where } let content = serde_json::to_vec_pretty(&settings) - .map_err(|e| SettingsError::WritingFile(format!("Failed to serialize settings: {}", e)))?; + .map_err(|e| SettingsError::WritingFile(format!("Failed to serialize settings: {e}")))?; - file.seek(SeekFrom::Start(0)).await.map_err(|e| { - SettingsError::WritingFile(format!("Failed to seek to start of file: {}", e)) - })?; + file.seek(SeekFrom::Start(0)) + .await + .map_err(|e| SettingsError::WritingFile(format!("Failed to seek to start of file: {e}")))?; file.write_all(&content).await.map_err(|e| { tracing::warn!("failed to write to file: {:?}", e); @@ -236,7 +235,7 @@ where file.inner_mut() .set_len(content.len() as u64) .await - .map_err(|e| SettingsError::WritingFile(format!("Failed to truncate file: {}", e)))?; + .map_err(|e| SettingsError::WritingFile(format!("Failed to truncate file: {e}")))?; Ok(()) } @@ -554,10 +553,10 @@ impl std::fmt::Display for SettingsError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::NotFound => write!(f, "Settings file not found"), - Self::ReadingFile(e) => write!(f, "Error while reading file: {}", e), - Self::DeletingFile(e) => write!(f, "Error while deleting file: {}", e), - Self::WritingFile(e) => write!(f, "Error while writing file: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), + Self::ReadingFile(e) => write!(f, "Error while reading file: {e}"), + Self::DeletingFile(e) => write!(f, "Error while deleting file: {e}"), + Self::WritingFile(e) => write!(f, "Error while writing file: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), } } } diff --git a/liana-gui/src/app/state/export.rs b/liana-gui/src/app/state/export.rs index 840faa9b1..449a93113 100644 --- a/liana-gui/src/app/state/export.rs +++ b/liana-gui/src/app/state/export.rs @@ -102,7 +102,7 @@ impl ExportModal { .map(|(_, checksum)| checksum) .expect("cannot fail") .to_string(); - format!("liana-{}.txt", checksum) + format!("liana-{checksum}.txt") } ImportExportType::ExportEncryptedDescriptor(_) => "liana.bed".into(), ImportExportType::ImportPsbt(_) => "psbt.psbt".into(), diff --git a/liana-gui/src/app/state/label.rs b/liana-gui/src/app/state/label.rs index a9b712310..ad48990c8 100644 --- a/liana-gui/src/app/state/label.rs +++ b/liana-gui/src/app/state/label.rs @@ -1,3 +1,5 @@ +#![allow(clippy::result_large_err)] + use liana::miniscript::bitcoin; use std::str::FromStr; use std::{collections::HashMap, iter::IntoIterator, sync::Arc}; diff --git a/liana-gui/src/app/state/psbt.rs b/liana-gui/src/app/state/psbt.rs index 7efca2d11..a6353f512 100644 --- a/liana-gui/src/app/state/psbt.rs +++ b/liana-gui/src/app/state/psbt.rs @@ -52,6 +52,7 @@ pub trait Modal { fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message>; } +#[allow(clippy::large_enum_variant)] pub enum PsbtModal { Save(SaveModal), Sign(SignModal), @@ -642,7 +643,7 @@ async fn sign_psbt_with_hot_signer( if let Some(signer) = &wallet.signer { let res = signer .sign_psbt(psbt) - .map_err(|e| WalletError::HotSigner(format!("Hot signer failed to sign psbt: {}", e))) + .map_err(|e| WalletError::HotSigner(format!("Hot signer failed to sign psbt: {e}"))) .map_err(|e| e.into()); (signer.fingerprint(), res) } else { diff --git a/liana-gui/src/app/state/receive.rs b/liana-gui/src/app/state/receive.rs index 4df5012f7..82d0d24eb 100644 --- a/liana-gui/src/app/state/receive.rs +++ b/liana-gui/src/app/state/receive.rs @@ -30,6 +30,7 @@ use crate::daemon::{ const PREV_ADDRESSES_PAGE_SIZE: usize = 20; +#[allow(clippy::large_enum_variant)] pub enum Modal { VerifyAddress(VerifyAddressModal), ShowQrCode(ShowQrCodeModal), @@ -421,7 +422,7 @@ pub struct ShowQrCodeModal { impl ShowQrCodeModal { pub fn new(address: &Address, index: ChildNumber) -> Option { - qr_code::Data::new(format!("bitcoin:{}?index={}", address, index)) + qr_code::Data::new(format!("bitcoin:{address}?index={index}")) .ok() .map(|qr_code| Self { qr_code, diff --git a/liana-gui/src/app/state/settings/wallet.rs b/liana-gui/src/app/state/settings/wallet.rs index 485f210f5..579bbfa77 100644 --- a/liana-gui/src/app/state/settings/wallet.rs +++ b/liana-gui/src/app/state/settings/wallet.rs @@ -32,6 +32,7 @@ use crate::{ services::connect::client::backend::WALLET_ALIAS_MAXIMUM_LENGTH, }; +#[allow(clippy::large_enum_variant)] enum Modal { None, RegisterWallet(RegisterWalletModal), diff --git a/liana-gui/src/app/state/spend/step.rs b/liana-gui/src/app/state/spend/step.rs index ba9dc3844..662eb109a 100644 --- a/liana-gui/src/app/state/spend/step.rs +++ b/liana-gui/src/app/state/spend/step.rs @@ -1,3 +1,5 @@ +#![allow(clippy::result_large_err)] + use std::{ cmp::Ordering, collections::{HashMap, HashSet}, diff --git a/liana-gui/src/app/state/transactions.rs b/liana-gui/src/app/state/transactions.rs index 04d4d1f6f..f847cafe9 100644 --- a/liana-gui/src/app/state/transactions.rs +++ b/liana-gui/src/app/state/transactions.rs @@ -39,6 +39,7 @@ use crate::daemon::{ use super::export::ExportModal; #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum TransactionsModal { CreateRbf(CreateRbfModal), Export(ExportModal), diff --git a/liana-gui/src/app/view/coins.rs b/liana-gui/src/app/view/coins.rs index 5ca02c3d3..becafd7a3 100644 --- a/liana-gui/src/app/view/coins.rs +++ b/liana-gui/src/app/view/coins.rs @@ -261,7 +261,7 @@ fn coin_list_view<'a>( .style(theme::text::secondary), ) .push( - p2_regular(format!("{}", b)) + p2_regular(format!("{b}")) .style(theme::text::secondary), ) .spacing(5) @@ -286,7 +286,7 @@ fn coin_list_view<'a>( .bold() .style(theme::text::secondary), ) - .push(p2_regular(format!("{}", height))) + .push(p2_regular(format!("{height}"))) .spacing(5) } else { Row::new().push( diff --git a/liana-gui/src/app/view/export.rs b/liana-gui/src/app/view/export.rs index 71b3eb911..20541769d 100644 --- a/liana-gui/src/app/view/export.rs +++ b/liana-gui/src/app/view/export.rs @@ -41,7 +41,7 @@ pub fn export_modal<'a, Message: From + Clone + 'static>( }; let msg = if let Some(error) = error { - format!("{}", error) + format!("{error}") } else { match state { ImportExportState::Init => "".to_string(), diff --git a/liana-gui/src/app/view/fiat.rs b/liana-gui/src/app/view/fiat.rs index 3a7ac2320..24ae070fc 100644 --- a/liana-gui/src/app/view/fiat.rs +++ b/liana-gui/src/app/view/fiat.rs @@ -29,7 +29,7 @@ impl std::fmt::Display for AmountError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Negative => write!(f, "Amount must be non-negative"), - Self::ParseError(e) => write!(f, "Parse error: {}", e), + Self::ParseError(e) => write!(f, "Parse error: {e}"), } } } @@ -96,15 +96,11 @@ impl std::fmt::Display for AmountConverterError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::NonPositivePrice => write!(f, "Price per BTC must be positive"), - Self::ParseError(e) => write!(f, "Parse error: {}", e), + Self::ParseError(e) => write!(f, "Parse error: {e}"), Self::CurrencyMismatch { expected, actual } => { - write!( - f, - "Currency mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Currency mismatch: expected {expected}, got {actual}") } - Self::ConversionError(e) => write!(f, "Conversion error: {}", e), + Self::ConversionError(e) => write!(f, "Conversion error: {e}"), } } } diff --git a/liana-gui/src/app/view/home.rs b/liana-gui/src/app/view/home.rs index f4bdabd44..0d840c052 100644 --- a/liana-gui/src/app/view/home.rs +++ b/liana-gui/src/app/view/home.rs @@ -261,7 +261,7 @@ fn event_list_view(event: &Payment) -> Element<'_, Message> { Some(p1_regular(label)) } else { event.address_label.as_ref().map(|label| { - p1_regular(format!("address label: {}", label)).style(theme::text::secondary) + p1_regular(format!("address label: {label}")).style(theme::text::secondary) }) }; if event.kind == PaymentKind::Incoming { @@ -385,7 +385,7 @@ pub fn payment_view<'a>( Row::new() .width(Length::Fill) .push(Container::new(text("Date:").bold()).width(Length::Fill)) - .push(Container::new(text(format!("{}", date))).width(Length::Shrink)) + .push(Container::new(text(format!("{date}"))).width(Length::Shrink)) })) .push( Row::new() diff --git a/liana-gui/src/app/view/message.rs b/liana-gui/src/app/view/message.rs index dd874bacf..d460f5e41 100644 --- a/liana-gui/src/app/view/message.rs +++ b/liana-gui/src/app/view/message.rs @@ -90,6 +90,7 @@ pub enum SpendTxMessage { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum SettingsMessage { EditBitcoindSettings, BitcoindSettings(SettingsEditMessage), diff --git a/liana-gui/src/app/view/settings/mod.rs b/liana-gui/src/app/view/settings/mod.rs index 8df1400f9..fef564bbf 100644 --- a/liana-gui/src/app/view/settings/mod.rs +++ b/liana-gui/src/app/view/settings/mod.rs @@ -310,7 +310,7 @@ pub fn about_section<'a>( Column::new() .push(text(format!("liana-gui v{}", crate::VERSION))) .push_maybe( - lianad_version.map(|version| text(format!("lianad v{}", version))), + lianad_version.map(|version| text(format!("lianad v{version}"))), ), ), ), @@ -437,7 +437,7 @@ pub fn bitcoind_edit<'a>( .spacing(10), |row, auth_type| { row.push(radio( - format!("{}", auth_type), + format!("{auth_type}"), *auth_type, Some(*selected_auth_type), SettingsEditMessage::BitcoindRpcAuthTypeSelected, @@ -1195,7 +1195,7 @@ fn display_policy<'a>( .style(theme::card::simple), ) } else { - Container::new(text(format!("[{}]", k)).bold()) + Container::new(text(format!("[{k}]")).bold()) }; if primary_keys.len() == 1 || i == primary_keys.len() - 1 { row.push(content) @@ -1248,7 +1248,7 @@ fn display_policy<'a>( .style(theme::card::simple), ) } else { - Container::new(text(format!("[{}]", k)).bold()) + Container::new(text(format!("[{k}]")).bold()) }; if recovery_keys.len() == 1 || i == recovery_keys.len() - 1 { row.push(content) @@ -1306,7 +1306,7 @@ fn expire_message_units(sequence: u32) -> Vec { .iter() .filter_map(|(n, u)| { if *n != 0 { - Some(format!("{}{}", n, u)) + Some(format!("{n}{u}")) } else { None } @@ -1320,7 +1320,7 @@ fn expire_message_units(sequence: u32) -> Vec { .iter() .filter_map(|(n, u)| { if *n != 0 { - Some(format!("{}{}", n, u)) + Some(format!("{n}{u}")) } else { None } diff --git a/liana-gui/src/app/view/transactions.rs b/liana-gui/src/app/view/transactions.rs index d6e74eded..d1df0ca78 100644 --- a/liana-gui/src/app/view/transactions.rs +++ b/liana-gui/src/app/view/transactions.rs @@ -399,7 +399,7 @@ pub fn tx_view<'a>( Row::new() .width(Length::Fill) .push(Container::new(text("Date:").bold()).width(Length::Fill)) - .push(Container::new(text(format!("{}", date))).width(Length::Shrink)) + .push(Container::new(text(format!("{date}"))).width(Length::Shrink)) })) .push( Row::new() diff --git a/liana-gui/src/app/view/warning.rs b/liana-gui/src/app/view/warning.rs index 1aa20c31d..1b0afa946 100644 --- a/liana-gui/src/app/view/warning.rs +++ b/liana-gui/src/app/view/warning.rs @@ -26,9 +26,9 @@ impl From<&Error> for WarningMessage { } } DaemonError::Http(Some(code), error) => { - WarningMessage(format!("HTTP error {}: {}", code, error)) + WarningMessage(format!("HTTP error {code}: {error}")) } - DaemonError::Http(None, error) => WarningMessage(format!("HTTP error: {}", error)), + DaemonError::Http(None, error) => WarningMessage(format!("HTTP error: {error}")), DaemonError::Unexpected(_) => WarningMessage("Unknown error".to_string()), DaemonError::Start(_) => WarningMessage("Daemon failed to start".to_string()), DaemonError::ClientNotSupported => { @@ -47,11 +47,11 @@ impl From<&Error> for WarningMessage { }, Error::Unexpected(_) => WarningMessage("Unknown error".to_string()), Error::HardwareWallet(_) => WarningMessage("Hardware wallet error".to_string()), - Error::Desc(e) => WarningMessage(format!("Descriptor analysis error: '{}'.", e)), - Error::Spend(e) => WarningMessage(format!("Spend creation error: '{}'.", e)), + Error::Desc(e) => WarningMessage(format!("Descriptor analysis error: '{e}'.")), + Error::Spend(e) => WarningMessage(format!("Spend creation error: '{e}'.")), Error::ImportExport(e) => WarningMessage(format!("{e}")), Error::RestoreBackup(e) => WarningMessage(format!("Failed to restore backup: {e}")), - Error::FiatPrice(e) => WarningMessage(format!("Fiat price error: {}", e)), + Error::FiatPrice(e) => WarningMessage(format!("Fiat price error: {e}")), } } } diff --git a/liana-gui/src/app/wallet.rs b/liana-gui/src/app/wallet.rs index 091169d00..ee714a304 100644 --- a/liana-gui/src/app/wallet.rs +++ b/liana-gui/src/app/wallet.rs @@ -229,8 +229,8 @@ impl std::fmt::Display for WalletError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::WrongWalletLoaded => write!(f, "Wrong wallet was loaded"), - Self::Settings(e) => write!(f, "Failed to load settings: {}", e), - Self::HotSigner(e) => write!(f, "Failed to load hot signer: {}", e), + Self::Settings(e) => write!(f, "Failed to load settings: {e}"), + Self::HotSigner(e) => write!(f, "Failed to load hot signer: {e}"), } } } diff --git a/liana-gui/src/args.rs b/liana-gui/src/args.rs index 021c01de7..66e9cf736 100644 --- a/liana-gui/src/args.rs +++ b/liana-gui/src/args.rs @@ -35,7 +35,7 @@ pub fn parse_args( .unwrap_or("liana"); if args.len() > 1 && (args[1] == "--version" || args[1] == "-v") { - eprintln!("{}", version); + eprintln!("{version}"); process::exit(0); } @@ -49,7 +49,7 @@ pub fn parse_args( } else { "" }; - format!(" --{:<15} Use {} network{}", name, name, default_marker) + format!(" --{name:<15} Use {name} network{default_marker}") }) .collect::>() .join("\n"); @@ -78,7 +78,7 @@ Options: } else if arg.starts_with("--") && arg != "--datadir" { let network = Network::from_str(arg.trim_start_matches("--"))?; if !available_networks.contains(&network) { - return Err(format!("network {} is not available", network).into()); + return Err(format!("network {network} is not available").into()); } res.push(Arg::Network(network)); } diff --git a/liana-gui/src/daemon/client/error.rs b/liana-gui/src/daemon/client/error.rs index 3d282fadd..714fb0f94 100644 --- a/liana-gui/src/daemon/client/error.rs +++ b/liana-gui/src/daemon/client/error.rs @@ -73,9 +73,9 @@ impl From for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Json(ref e) => write!(f, "JSON decode error: {}", e), - Error::Io(ref e) => write!(f, "IO error response: {}", e), - Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r), + Error::Json(ref e) => write!(f, "JSON decode error: {e}"), + Error::Io(ref e) => write!(f, "IO error response: {e}"), + Error::Rpc(ref r) => write!(f, "RPC error response: {r:?}"), Error::NoErrorOrResult => write!(f, "Malformed RPC response"), Error::NonceMismatch => write!(f, "Nonce of response did not match nonce of request"), Error::VersionMismatch => write!(f, "`jsonrpc` field set to non-\"2.0\""), diff --git a/liana-gui/src/daemon/client/jsonrpc.rs b/liana-gui/src/daemon/client/jsonrpc.rs index 4ead066b1..77c09489a 100644 --- a/liana-gui/src/daemon/client/jsonrpc.rs +++ b/liana-gui/src/daemon/client/jsonrpc.rs @@ -224,9 +224,9 @@ impl From for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Json(ref e) => write!(f, "JSON decode error: {}", e), - Error::Io(ref e) => write!(f, "IO error response: {}", e), - Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r), + Error::Json(ref e) => write!(f, "JSON decode error: {e}"), + Error::Io(ref e) => write!(f, "IO error response: {e}"), + Error::Rpc(ref r) => write!(f, "RPC error response: {r:?}"), Error::NoErrorOrResult => write!(f, "Malformed RPC response"), Error::NonceMismatch => write!(f, "Nonce of response did not match nonce of request"), Error::VersionMismatch => write!(f, "`jsonrpc` field set to non-\"2.0\""), @@ -247,13 +247,11 @@ impl error::Error for Error { impl From for super::DaemonError { fn from(e: Error) -> super::DaemonError { match e { - Error::Io(e) => super::DaemonError::RpcSocket(Some(e.kind()), format!("io: {:?}", e)), - Error::Json(e) => super::DaemonError::RpcSocket(None, format!("json decode: {}", e)), - Error::NonceMismatch => { - super::DaemonError::RpcSocket(None, format!("transport: {}", e)) - } + Error::Io(e) => super::DaemonError::RpcSocket(Some(e.kind()), format!("io: {e:?}")), + Error::Json(e) => super::DaemonError::RpcSocket(None, format!("json decode: {e}")), + Error::NonceMismatch => super::DaemonError::RpcSocket(None, format!("transport: {e}")), Error::VersionMismatch => { - super::DaemonError::RpcSocket(None, format!("transport: {}", e)) + super::DaemonError::RpcSocket(None, format!("transport: {e}")) } Error::NoErrorOrResult => super::DaemonError::NoAnswer, Error::NotSupported => super::DaemonError::ClientNotSupported, diff --git a/liana-gui/src/daemon/embedded.rs b/liana-gui/src/daemon/embedded.rs index 59213b2ea..5b867bfdf 100644 --- a/liana-gui/src/daemon/embedded.rs +++ b/liana-gui/src/daemon/embedded.rs @@ -44,7 +44,7 @@ impl EmbeddedDaemon { impl From> for DaemonError { fn from(value: std::sync::PoisonError) -> Self { - DaemonError::Unexpected(format!("Daemon panic: {}", value)) + DaemonError::Unexpected(format!("Daemon panic: {value}")) } } diff --git a/liana-gui/src/daemon/mod.rs b/liana-gui/src/daemon/mod.rs index fea57b25d..0567f3458 100644 --- a/liana-gui/src/daemon/mod.rs +++ b/liana-gui/src/daemon/mod.rs @@ -53,13 +53,13 @@ pub enum DaemonError { impl std::fmt::Display for DaemonError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Rpc(code, e) => write!(f, "Daemon error rpc call: [{:?}] {}", code, e), + Self::Rpc(code, e) => write!(f, "Daemon error rpc call: [{code:?}] {e}"), Self::NoAnswer => write!(f, "Daemon returned no answer"), Self::DaemonStopped => write!(f, "Daemon stopped"), - Self::RpcSocket(kind, e) => write!(f, "Daemon transport error: [{:?}] {}", kind, e), - Self::Http(kind, e) => write!(f, "Http error: [{:?}] {}", kind, e), - Self::Unexpected(e) => write!(f, "Daemon unexpected error: {}", e), - Self::Start(e) => write!(f, "Daemon did not start: {}", e), + Self::RpcSocket(kind, e) => write!(f, "Daemon transport error: [{kind:?}] {e}"), + Self::Http(kind, e) => write!(f, "Http error: [{kind:?}] {e}"), + Self::Unexpected(e) => write!(f, "Daemon unexpected error: {e}"), + Self::Start(e) => write!(f, "Daemon did not start: {e}"), Self::ClientNotSupported => write!(f, "Daemon communication is not supported"), Self::CoinSelectionError => write!(f, "Coin selection error"), Self::NotImplemented => write!(f, "This feature is not implemented for this backend"), diff --git a/liana-gui/src/daemon/model.rs b/liana-gui/src/daemon/model.rs index f9dc00f14..2ee069136 100644 --- a/liana-gui/src/daemon/model.rs +++ b/liana-gui/src/daemon/model.rs @@ -20,11 +20,7 @@ pub type Coin = ListCoinsEntry; pub fn remaining_sequence(coin: &Coin, blockheight: u32, timelock: u16) -> u32 { if let Some(coin_blockheight) = coin.block_height { - if blockheight > coin_blockheight as u32 + timelock as u32 { - 0 - } else { - coin_blockheight as u32 + timelock as u32 - blockheight - } + (coin_blockheight as u32 + timelock as u32).saturating_sub(blockheight) } else { timelock as u32 } diff --git a/liana-gui/src/delete.rs b/liana-gui/src/delete.rs index ad4f0fc72..385faeb05 100644 --- a/liana-gui/src/delete.rs +++ b/liana-gui/src/delete.rs @@ -25,10 +25,10 @@ pub enum DeleteError { impl std::fmt::Display for DeleteError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Io(e) => write!(f, "{}", e), - Self::Settings(e) => write!(f, "{}", e), - Self::ConnectCache(e) => write!(f, "{}", e), - Self::Connect(e) => write!(f, "{}", e), + Self::Io(e) => write!(f, "{e}"), + Self::Settings(e) => write!(f, "{e}"), + Self::ConnectCache(e) => write!(f, "{e}"), + Self::Connect(e) => write!(f, "{e}"), } } } diff --git a/liana-gui/src/download.rs b/liana-gui/src/download.rs index 293939338..18c803424 100644 --- a/liana-gui/src/download.rs +++ b/liana-gui/src/download.rs @@ -71,7 +71,7 @@ impl std::fmt::Display for DownloadError { write!(f, "Response has unknown content length.") } Self::RequestFailed(e) => { - write!(f, "Request error: '{}'.", e) + write!(f, "Request error: '{e}'.") } } } diff --git a/liana-gui/src/export.rs b/liana-gui/src/export.rs index 5e04082a4..a377938f6 100644 --- a/liana-gui/src/export.rs +++ b/liana-gui/src/export.rs @@ -75,6 +75,7 @@ async fn open_file_write(path: &Path) -> Result { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum ImportExportMessage { Open, Progress(Progress), @@ -166,6 +167,7 @@ impl Display for Error { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum ImportExportType { Transactions, ExportPsbt(String), @@ -207,25 +209,25 @@ impl ImportExportType { impl From for Error { fn from(value: JoinError) -> Self { - Error::JoinError(format!("{:?}", value)) + Error::JoinError(format!("{value:?}")) } } impl From for Error { fn from(value: std::io::Error) -> Self { - Error::Io(format!("{:?}", value)) + Error::Io(format!("{value:?}")) } } impl From for Error { fn from(value: DaemonError) -> Self { - Error::Daemon(format!("{:?}", value)) + Error::Daemon(format!("{value:?}")) } } impl From for Error { fn from(value: ExportError) -> Self { - Error::Bip329Export(format!("{:?}", value)) + Error::Bip329Export(format!("{value:?}")) } } @@ -545,7 +547,7 @@ pub async fn export_transactions( "".to_string() }; if !label.is_empty() { - label = format!("\"{}\"", label); + label = format!("\"{label}\""); } let txid = tx.txid.to_string(); let fee = tx.fee_amount.unwrap_or(Amount::ZERO).to_sat() as i128; @@ -563,10 +565,7 @@ pub async fn export_transactions( "".into() }; - let line = format!( - "{},{},{},{},{},{}\n", - date_time, label, value, fee, txid, block - ); + let line = format!("{date_time},{label},{value},{fee},{txid},{block}\n"); file.write_all(line.as_bytes())?; } send_progress!(sender, Progress(100.0)); @@ -841,7 +840,7 @@ pub async fn import_backup( let backup = match backup { Ok(psbt) => psbt, Err(e) => { - return Err(Error::BackupImport(format!("{:?}", e))); + return Err(Error::BackupImport(format!("{e:?}"))); } }; @@ -1057,8 +1056,7 @@ pub async fn import_backup( .await { return Err(Error::BackupImport(format!( - "Failed to import keys aliases: {}", - e + "Failed to import keys aliases: {e}" ))); } else { // Update wallet state diff --git a/liana-gui/src/gui/mod.rs b/liana-gui/src/gui/mod.rs index a2098c9ce..e4bbe90a2 100644 --- a/liana-gui/src/gui/mod.rs +++ b/liana-gui/src/gui/mod.rs @@ -66,6 +66,7 @@ pub enum Key { } #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum Message where M: Clone + Send + 'static, diff --git a/liana-gui/src/gui/pane.rs b/liana-gui/src/gui/pane.rs index 1f476e9b3..2506d143b 100644 --- a/liana-gui/src/gui/pane.rs +++ b/liana-gui/src/gui/pane.rs @@ -12,6 +12,7 @@ use crate::{ use super::tab; #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum Message where M: Clone + Send + 'static, diff --git a/liana-gui/src/gui/tab.rs b/liana-gui/src/gui/tab.rs index 7c99b1aa4..59eeefec8 100644 --- a/liana-gui/src/gui/tab.rs +++ b/liana-gui/src/gui/tab.rs @@ -35,6 +35,7 @@ use crate::{ }, }; +#[allow(clippy::large_enum_variant)] pub enum State where M: Clone + Send + 'static, @@ -81,6 +82,7 @@ where } #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum Message where M: Clone + Send + 'static, @@ -739,7 +741,7 @@ async fn connect_for_business( .map_err(|e| login::Error::Unexpected(e.to_string()))? .into_iter() .find(|w| w.id == wallet_id) - .ok_or_else(|| login::Error::Unexpected(format!("Wallet {} not found", wallet_id)))?; + .ok_or_else(|| login::Error::Unexpected(format!("Wallet {wallet_id} not found")))?; // Create wallet client let (wallet_client, wallet) = client.connect_wallet(wallet); diff --git a/liana-gui/src/hw.rs b/liana-gui/src/hw.rs index 98545af7b..a27ca0533 100644 --- a/liana-gui/src/hw.rs +++ b/liana-gui/src/hw.rs @@ -443,7 +443,7 @@ fn refresh(mut state: State) -> impl Stream { match specter::SerialTransport::enumerate_potential_ports() { Ok(ports) => { for port in ports { - let id = format!("specter-{}", port); + let id = format!("specter-{port}"); if state.connected_supported_hws.contains(&id) { still.push(id); } else { @@ -485,7 +485,7 @@ fn refresh(mut state: State) -> impl Stream { match jade::SerialTransport::enumerate_potential_ports() { Ok(ports) => { for port in ports { - let id = format!("jade-{}", port); + let id = format!("jade-{port}"); if state.connected_supported_hws.contains(&id) { still.push(id); } else { diff --git a/liana-gui/src/installer/context.rs b/liana-gui/src/installer/context.rs index afdae672e..a0eb976f9 100644 --- a/liana-gui/src/installer/context.rs +++ b/liana-gui/src/installer/context.rs @@ -15,6 +15,7 @@ use liana::{descriptors::LianaDescriptor, miniscript::bitcoin}; use lianad::config::{BitcoinBackend, BitcoinConfig}; #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum RemoteBackend { Undefined, None, diff --git a/liana-gui/src/installer/decrypt.rs b/liana-gui/src/installer/decrypt.rs index 6b1a96476..f51626044 100644 --- a/liana-gui/src/installer/decrypt.rs +++ b/liana-gui/src/installer/decrypt.rs @@ -101,6 +101,7 @@ impl Debug for DecryptModal { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum Decrypt { Fetched(Fingerprint, String /* name */), Backup(Backup), @@ -758,6 +759,6 @@ pub fn decrypt_view<'a>(state: &DecryptModal) -> Container<'a, installer::Messag .align_x(alignment::Horizontal::Center); card::simple(column) - .width(Length::Fixed(modal::MODAL_WIDTH as f32)) + .width(Length::Fixed(modal::MODAL_WIDTH)) .height(Length::Fixed(450.0)) } diff --git a/liana-gui/src/installer/message.rs b/liana-gui/src/installer/message.rs index 1d52ed193..422a824b2 100644 --- a/liana-gui/src/installer/message.rs +++ b/liana-gui/src/installer/message.rs @@ -98,6 +98,7 @@ impl From<(Fingerprint, ChildNumber)> for Message { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum SelectBackend { // view messages RequestOTP, diff --git a/liana-gui/src/installer/mod.rs b/liana-gui/src/installer/mod.rs index 2bcac44eb..cfdfe27b0 100644 --- a/liana-gui/src/installer/mod.rs +++ b/liana-gui/src/installer/mod.rs @@ -524,10 +524,9 @@ pub fn daemon_check(cfg: lianad::config::Config) -> Result<(), Error> { match lianad::DaemonHandle::start_default(cfg, false) { Ok(daemon) => daemon .stop() - .map_err(|e| Error::Unexpected(format!("Failed to stop Liana daemon: {}", e))), + .map_err(|e| Error::Unexpected(format!("Failed to stop Liana daemon: {e}"))), Err(e) => Err(Error::Unexpected(format!( - "Failed to start Liana daemon: {}", - e + "Failed to start Liana daemon: {e}" ))), } } @@ -549,7 +548,7 @@ pub async fn install_local_wallet( .network_directory(ctx.bitcoin_config.network); network_datadir .init() - .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {e}")))?; let descriptor = ctx .descriptor @@ -586,7 +585,7 @@ pub async fn install_local_wallet( // Step needed because of ValueAfterTable error in the toml serialize implementation. let daemon_config = toml::Value::try_from(&cfg) - .map_err(|e| Error::Unexpected(format!("Failed to serialize daemon config: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to serialize daemon config: {e}")))?; // create lianad configuration file create_and_write_file( @@ -615,7 +614,7 @@ pub async fn install_local_wallet( .timestamp .expect("Every new wallet have now a timestamp"), ) - .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {e}")))?; info!("Hot signer mnemonic stored"); } @@ -630,7 +629,7 @@ pub async fn install_local_wallet( .timestamp .expect("Every new wallet have now a timestamp"), ) - .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {e}")))?; info!("Recovered signer mnemonic stored"); } @@ -647,7 +646,7 @@ pub async fn install_local_wallet( // Installer started a bitcoind, it is expected that gui will start it on startup ctx.internal_bitcoind.is_some(), )) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {e}")))? .as_bytes(), )?; info!("Gui configuration file created"); @@ -675,7 +674,7 @@ pub async fn create_remote_wallet( let network_datadir = ctx.liana_directory.network_directory(ctx.network); network_datadir .init() - .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {e}")))?; let descriptor = ctx .descriptor @@ -697,7 +696,7 @@ pub async fn create_remote_wallet( .timestamp .expect("Every new wallet have now a timestamp"), ) - .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {e}")))?; info!("Hot signer mnemonic stored"); } @@ -712,7 +711,7 @@ pub async fn create_remote_wallet( .timestamp .expect("Every new wallet have now a timestamp"), ) - .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {e}")))?; info!("Recovered signer mnemonic stored"); } @@ -726,7 +725,7 @@ pub async fn create_remote_wallet( create_and_write_file( &gui_config_path, toml::to_string(&gui_config::Config::new(false)) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {e}")))? .as_bytes(), )?; info!("Gui configuration file created"); @@ -842,7 +841,7 @@ pub async fn import_remote_wallet( .timestamp .expect("Every new wallet have now a timestamp"), ) - .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to store mnemonic: {e}")))?; info!("Recovered signer mnemonic stored"); } @@ -850,7 +849,7 @@ pub async fn import_remote_wallet( let network_datadir = ctx.liana_directory.network_directory(ctx.network); network_datadir .init() - .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to create datadir path: {e}")))?; backend .update_wallet_metadata(Some(ctx.wallet_alias.clone()), &HashMap::new(), &[]) @@ -895,7 +894,7 @@ pub async fn import_remote_wallet( create_and_write_file( &gui_config_path, toml::to_string(&gui_config::Config::new(false)) - .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {}", e)))? + .map_err(|e| Error::Unexpected(format!("Failed to serialize gui config: {e}")))? .as_bytes(), )?; info!("Gui configuration file created"); @@ -941,7 +940,7 @@ pub fn extract_daemon_config(ctx: &Context, settings: &WalletSettings) -> Result .path() .to_path_buf() .canonicalize() - .map_err(|e| Error::Unexpected(format!("Failed to canonicalize datadir path: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to canonicalize datadir path: {e}")))?; let bitcoin_backend = if let Some(BitcoinBackend::Bitcoind(BitcoindConfig { rpc_auth: BitcoindRpcAuth::CookieFile(cookie_path), addr, @@ -951,7 +950,7 @@ pub fn extract_daemon_config(ctx: &Context, settings: &WalletSettings) -> Result // We already checked in the installer that bitcoind is running. let cookie_path = cookie_path .canonicalize() - .map_err(|e| Error::Unexpected(format!("Failed to canonicalize cookie path: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to canonicalize cookie path: {e}")))?; Some(BitcoinBackend::Bitcoind(BitcoindConfig { rpc_auth: BitcoindRpcAuth::CookieFile(cookie_path), addr: *addr, @@ -1028,19 +1027,19 @@ impl From for Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Auth(e) => write!(f, "Authentication error: {}", e), - Self::Backend(e) => write!(f, "Remote backend error: {}", e), - Self::Services(e) => write!(f, "Services error: {}", e), - Self::Settings(e) => write!(f, "Settings file error: {}", e), - Self::Bitcoind(e) => write!(f, "Failed to ping bitcoind: {}", e), - Self::Electrum(e) => write!(f, "Failed to ping Electrum: {}", e), - Self::CannotCreateDatadir(e) => write!(f, "Failed to create datadir: {}", e), - Self::CannotGetAvailablePort(e) => write!(f, "Failed to get available port: {}", e), - Self::CannotWriteToFile(e) => write!(f, "Failed to write to file: {}", e), - Self::CannotCreateFile(e) => write!(f, "Failed to create file: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected: {}", e), - Self::HardwareWallet(e) => write!(f, "Hardware Wallet: {}", e), - Self::Backup(e) => write!(f, "Backup: {:?}", e), + Self::Auth(e) => write!(f, "Authentication error: {e}"), + Self::Backend(e) => write!(f, "Remote backend error: {e}"), + Self::Services(e) => write!(f, "Services error: {e}"), + Self::Settings(e) => write!(f, "Settings file error: {e}"), + Self::Bitcoind(e) => write!(f, "Failed to ping bitcoind: {e}"), + Self::Electrum(e) => write!(f, "Failed to ping Electrum: {e}"), + Self::CannotCreateDatadir(e) => write!(f, "Failed to create datadir: {e}"), + Self::CannotGetAvailablePort(e) => write!(f, "Failed to get available port: {e}"), + Self::CannotWriteToFile(e) => write!(f, "Failed to write to file: {e}"), + Self::CannotCreateFile(e) => write!(f, "Failed to create file: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected: {e}"), + Self::HardwareWallet(e) => write!(f, "Hardware Wallet: {e}"), + Self::Backup(e) => write!(f, "Backup: {e:?}"), } } } diff --git a/liana-gui/src/installer/step/backend.rs b/liana-gui/src/installer/step/backend.rs index 7a88dbdf5..ae3300421 100644 --- a/liana-gui/src/installer/step/backend.rs +++ b/liana-gui/src/installer/step/backend.rs @@ -89,6 +89,7 @@ impl Step for ChooseBackend { } } +#[allow(clippy::large_enum_variant)] pub enum ConnectionStep { EnterEmail { email: form::Value, @@ -442,7 +443,7 @@ pub async fn connect_with_existing_account( if tokens.expires_at < chrono::Utc::now().timestamp() { tokens = cache::update_connect_cache(&network_dir, &tokens, &client, true) .await - .map_err(|e| Error::Unexpected(format!("Failed to update cache: {}", e)))?; + .map_err(|e| Error::Unexpected(format!("Failed to update cache: {e}")))?; } let client = BackendClient::connect(client, config.backend_api_url, tokens, network).await?; diff --git a/liana-gui/src/installer/step/descriptor/editor/key.rs b/liana-gui/src/installer/step/descriptor/editor/key.rs index 1535e0b75..2a0aee69b 100644 --- a/liana-gui/src/installer/step/descriptor/editor/key.rs +++ b/liana-gui/src/installer/step/descriptor/editor/key.rs @@ -106,6 +106,7 @@ enum Focus { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum SelectKeySourceMessage { SelectDevice(Fingerprint), FetchFromDevice(Fingerprint, ChildNumber), @@ -1167,7 +1168,7 @@ impl SelectKeySource { } else { (!available).then_some("Key already used in this path".to_string()) }; - let fg_str = format!("#{}", fg); + let fg_str = format!("#{fg}"); let on_press = message .is_none() .then_some(move || Self::route(SelectKeySourceMessage::SelectKey(fg))); diff --git a/liana-gui/src/installer/step/import_descriptor.rs b/liana-gui/src/installer/step/import_descriptor.rs index 69e48ffbc..509b5c425 100644 --- a/liana-gui/src/installer/step/import_descriptor.rs +++ b/liana-gui/src/installer/step/import_descriptor.rs @@ -14,6 +14,7 @@ use crate::{ pub const BACKUP_NETWORK_NOT_MATCH: &str = "Backup network do not match the selected network!"; #[derive(Debug)] +#[allow(clippy::large_enum_variant)] pub enum ImportDescriptorModal { None, Export(ExportModal), diff --git a/liana-gui/src/installer/step/node/bitcoind.rs b/liana-gui/src/installer/step/node/bitcoind.rs index e692053ac..3174939b5 100644 --- a/liana-gui/src/installer/step/node/bitcoind.rs +++ b/liana-gui/src/installer/step/node/bitcoind.rs @@ -62,7 +62,7 @@ impl Download { pub fn start(&mut self) { match self.state { - DownloadState::Idle { .. } + DownloadState::Idle | DownloadState::Finished { .. } | DownloadState::Errored { .. } => { self.state = DownloadState::Downloading { progress: 0.0 }; @@ -128,7 +128,7 @@ impl std::fmt::Display for InstallBitcoindError { write!(f, "Hashes do not match.") } Self::UnpackingError(e) => { - write!(f, "Error unpacking: '{}'.", e) + write!(f, "Error unpacking: '{e}'.") } } } @@ -364,7 +364,7 @@ impl DefineBitcoind { RpcAuthType::CookieFile => { let cookie_path = rpc_auth_vals.cookie_path.value; let cookie = std::fs::read_to_string(cookie_path) - .map_err(|e| Error::Bitcoind(format!("Failed to read cookie file: {}", e)))?; + .map_err(|e| Error::Bitcoind(format!("Failed to read cookie file: {e}")))?; SimpleHttpTransport::builder().cookie_auth(cookie) } RpcAuthType::UserPass => { @@ -604,12 +604,12 @@ impl Step for InternalBitcoindStep { (rpc_port, p2p_port) } (Ok(_), Err(e)) | (Err(e), Ok(_)) => { - self.error = Some(format!("Could not get available port: {}.", e)); + self.error = Some(format!("Could not get available port: {e}.")); return Task::none(); } (Err(e1), Err(e2)) => { self.error = - Some(format!("Could not get available ports: {}; {}.", e1, e2)); + Some(format!("Could not get available ports: {e1}; {e2}.")); return Task::none(); } } diff --git a/liana-gui/src/installer/view/editor/mod.rs b/liana-gui/src/installer/view/editor/mod.rs index 2d989654d..6c2b620a1 100644 --- a/liana-gui/src/installer/view/editor/mod.rs +++ b/liana-gui/src/installer/view/editor/mod.rs @@ -184,7 +184,7 @@ pub fn defined_key<'a>( .push( Row::new() .spacing(10) - .push(p1_regular(format!("{}", title)).style(theme::text::secondary)) + .push(p1_regular(format!("{title}")).style(theme::text::secondary)) .push(p1_bold(alias)), ) .push_maybe(warning.map(|w| p2_regular(w).style(theme::text::error))), diff --git a/liana-gui/src/installer/view/mod.rs b/liana-gui/src/installer/view/mod.rs index caf740774..b4e23d858 100644 --- a/liana-gui/src/installer/view/mod.rs +++ b/liana-gui/src/installer/view/mod.rs @@ -872,7 +872,7 @@ fn display_policy( .style(theme::card::simple), ) } else { - Container::new(text(format!("[{}]", k)).bold()) + Container::new(text(format!("[{k}]")).bold()) }; if primary_keys.len() == 1 || i == primary_keys.len() - 1 { row.push(content) @@ -919,7 +919,7 @@ fn display_policy( .style(theme::card::simple), ) } else { - Container::new(text(format!("[{}]", k)).bold()) + Container::new(text(format!("[{k}]")).bold()) }; if recovery_keys.len() == 1 || i == recovery_keys.len() - 1 { row.push(content) @@ -977,7 +977,7 @@ fn expire_message_units(sequence: u32) -> Vec { .iter() .filter_map(|(n, u)| { if *n != 0 { - Some(format!("{}{}", n, u)) + Some(format!("{n}{u}")) } else { None } @@ -991,7 +991,7 @@ fn expire_message_units(sequence: u32) -> Vec { .iter() .filter_map(|(n, u)| { if *n != 0 { - Some(format!("{}{}", n, u)) + Some(format!("{n}{u}")) } else { None } @@ -1154,7 +1154,7 @@ pub fn define_bitcoind<'a>( .spacing(10), |row, auth_type| { row.push(radio( - format!("{}", auth_type), + format!("{auth_type}"), *auth_type, Some(*selected_auth_type), |new_selection| { @@ -1384,7 +1384,7 @@ pub fn start_internal_bitcoind<'a>( .spacing(10) .align_y(Alignment::Center) .push(icon::circle_cross_icon().style(theme::text::error)) - .push(text(format!("Download failed: '{}'.", e)).style(theme::text::error)), + .push(text(format!("Download failed: '{e}'.")).style(theme::text::error)), _ => Row::new().spacing(10).align_y(Alignment::Center), } })) @@ -1404,8 +1404,7 @@ pub fn start_internal_bitcoind<'a>( .align_y(Alignment::Center) .push(icon::circle_cross_icon().style(theme::text::error)) .push( - text(format!("Installation failed: '{}'.", e)) - .style(theme::text::error), + text(format!("Installation failed: '{e}'.")).style(theme::text::error), ), } } else if exe_path.is_some() { @@ -1582,7 +1581,7 @@ pub fn defined_sequence<'a>( .iter() .filter_map(|(n, unit)| { if *n > 0 { - Some(format!("{}{}", n, unit)) + Some(format!("{n}{unit}")) } else { None } diff --git a/liana-gui/src/launcher.rs b/liana-gui/src/launcher.rs index c1610512a..b5a15c9ef 100644 --- a/liana-gui/src/launcher.rs +++ b/liana-gui/src/launcher.rs @@ -724,8 +724,7 @@ async fn check_network_datadir(path: NetworkDirectory) -> Result } ConfigError::Unexpected(e) => { format!( - "Unexpected {}", - e, + "Unexpected {e}", ) } })?; diff --git a/liana-gui/src/loader.rs b/liana-gui/src/loader.rs index a561c5f67..b12e5155f 100644 --- a/liana-gui/src/loader.rs +++ b/liana-gui/src/loader.rs @@ -623,11 +623,11 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Config(e) => write!(f, "Config error: {}", e), - Self::Wallet(e) => write!(f, "Wallet error: {}", e), - Self::Daemon(e) => write!(f, "Liana daemon error: {}", e), - Self::Bitcoind(e) => write!(f, "Bitcoind error: {}", e), - Self::BitcoindLogs(e) => write!(f, "Bitcoind logs error: {}", e), + Self::Config(e) => write!(f, "Config error: {e}"), + Self::Wallet(e) => write!(f, "Wallet error: {e}"), + Self::Daemon(e) => write!(f, "Liana daemon error: {e}"), + Self::Bitcoind(e) => write!(f, "Bitcoind error: {e}"), + Self::BitcoindLogs(e) => write!(f, "Bitcoind logs error: {e}"), Self::RestoreBackup(e) => write!(f, "Restore backup: {e}"), } } diff --git a/liana-gui/src/main.rs b/liana-gui/src/main.rs index 3a3c0091c..b475dbda0 100644 --- a/liana-gui/src/main.rs +++ b/liana-gui/src/main.rs @@ -59,7 +59,7 @@ fn main() -> Result<(), Box> { .run() { log::error!("{}", e); - Err(format!("Failed to launch UI: {}", e).into()) + Err(format!("Failed to launch UI: {e}").into()) } else { Ok(()) } diff --git a/liana-gui/src/node/bitcoind.rs b/liana-gui/src/node/bitcoind.rs index d2274e35e..8b2e7f12e 100644 --- a/liana-gui/src/node/bitcoind.rs +++ b/liana-gui/src/node/bitcoind.rs @@ -90,7 +90,7 @@ pub fn internal_bitcoind_exe_path( bitcoind_version: &str, ) -> PathBuf { internal_bitcoind_directory(liana_datadir) - .join(format!("bitcoin-{}", bitcoind_version)) + .join(format!("bitcoin-{bitcoind_version}")) .join("bin") .join(if cfg!(target_os = "windows") { "bitcoind.exe" @@ -249,16 +249,16 @@ pub enum InternalBitcoindConfigError { impl std::fmt::Display for InternalBitcoindConfigError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::KeyNotFound(e) => write!(f, "Config file does not contain expected key: {}", e), - Self::CouldNotParseValue(e) => write!(f, "Value could not be parsed: {}", e), - Self::UnexpectedSection(e) => write!(f, "Unexpected section in file: {}", e), + Self::KeyNotFound(e) => write!(f, "Config file does not contain expected key: {e}"), + Self::CouldNotParseValue(e) => write!(f, "Value could not be parsed: {e}"), + Self::UnexpectedSection(e) => write!(f, "Unexpected section in file: {e}"), Self::TooManyElements(section) => { - write!(f, "Section in file contains too many elements: {}", section) + write!(f, "Section in file contains too many elements: {section}") } Self::FileNotFound => write!(f, "File not found"), - Self::ReadingFile(e) => write!(f, "Error while reading file: {}", e), - Self::WritingFile(e) => write!(f, "Error while writing file: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), + Self::ReadingFile(e) => write!(f, "Error while reading file: {e}"), + Self::WritingFile(e) => write!(f, "Error while writing file: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), } } } @@ -387,18 +387,18 @@ impl std::fmt::Display for StartInternalBitcoindError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Lock(e) => { - write!(f, "lock file error: {}", e) + write!(f, "lock file error: {e}") } Self::CommandError(e) => { - write!(f, "Command to start bitcoind returned an error: {}", e) + write!(f, "Command to start bitcoind returned an error: {e}") } Self::CouldNotCanonicalizeDataDir(e) => { - write!(f, "Failed to canonicalize datadir: {}", e) + write!(f, "Failed to canonicalize datadir: {e}") } - Self::BitcoinDError(e) => write!(f, "bitcoind connection check failed: {}", e), + Self::BitcoinDError(e) => write!(f, "bitcoind connection check failed: {e}"), Self::ExecutableNotFound => write!(f, "bitcoind executable not found."), Self::ProcessExited(status) => { - write!(f, "bitcoind process exited with status '{}'.", status) + write!(f, "bitcoind process exited with status '{status}'.") } } } @@ -421,7 +421,7 @@ impl Bitcoind { return Ok(Bitcoind { config, lock: LockFile::create(liana_datadir.bitcoind_directory(), network) - .map_err(|e| StartInternalBitcoindError::Lock(format!("{:?}", e)))?, + .map_err(|e| StartInternalBitcoindError::Lock(format!("{e:?}")))?, }); } let bitcoind_datadir = internal_bitcoind_datadir(liana_datadir); @@ -504,7 +504,7 @@ impl Bitcoind { return Ok(Self { config, lock: LockFile::create(liana_datadir.bitcoind_directory(), network) - .map_err(|e| StartInternalBitcoindError::Lock(format!("{:?}", e)))?, + .map_err(|e| StartInternalBitcoindError::Lock(format!("{e:?}")))?, }); } Err(lianad::BitcoindError::CookieFile(_)) => { diff --git a/liana-gui/src/services/connect/client/backend/mod.rs b/liana-gui/src/services/connect/client/backend/mod.rs index 0432e713d..6b8c5c24c 100644 --- a/liana-gui/src/services/connect/client/backend/mod.rs +++ b/liana-gui/src/services/connect/client/backend/mod.rs @@ -58,7 +58,7 @@ fn request( ) -> RequestBuilder { let req = http .request(method, url) - .header("Authorization", format!("Bearer {}", access_token)) + .header("Authorization", format!("Bearer {access_token}")) .header("Content-Type", "application/json") .header("Liana-Version", crate::VERSION) .header("User-Agent", user_agent); @@ -90,7 +90,7 @@ impl BackendClient { let response = request( &http, Method::GET, - format!("{}/v1/me", url), + format!("{url}/v1/me"), &credentials.access_token, auth_client.user_agent(), ) @@ -261,20 +261,16 @@ impl BackendClient { ledger_hmac.fingerprint == cfg.fingerprint && ledger_hmac.hmac == cfg.token }) { - self.exec_request( - Method::PATCH, - &format!("/v1/wallets/{}", wallet_uuid), - |r| { - r.json(&api::payload::UpdateWallet { - alias: None, - ledger_hmac: Some(api::payload::UpdateLedgerHmac { - fingerprint: cfg.fingerprint.to_string(), - hmac: cfg.token.clone(), - }), - fingerprint_aliases: None, - }) - }, - ) + self.exec_request(Method::PATCH, &format!("/v1/wallets/{wallet_uuid}"), |r| { + r.json(&api::payload::UpdateWallet { + alias: None, + ledger_hmac: Some(api::payload::UpdateLedgerHmac { + fingerprint: cfg.fingerprint.to_string(), + hmac: cfg.token.clone(), + }), + fingerprint_aliases: None, + }) + }) .await?; } } @@ -304,17 +300,13 @@ impl BackendClient { }; if fingerprint_aliases.is_some() || wallet_alias.is_some() { - self.exec_request( - Method::PATCH, - &format!("/v1/wallets/{}", wallet_uuid), - |r| { - r.json(&api::payload::UpdateWallet { - alias: wallet_alias, - ledger_hmac: None, - fingerprint_aliases, - }) - }, - ) + self.exec_request(Method::PATCH, &format!("/v1/wallets/{wallet_uuid}"), |r| { + r.json(&api::payload::UpdateWallet { + alias: wallet_alias, + ledger_hmac: None, + fingerprint_aliases, + }) + }) .await?; } @@ -327,7 +319,7 @@ impl BackendClient { ) -> Result { self.request( Method::GET, - &format!("/v1/invitations/{}", invitation_id), + &format!("/v1/invitations/{invitation_id}"), |r| r, ) .await @@ -336,7 +328,7 @@ impl BackendClient { pub async fn accept_wallet_invitation(&self, invitation_id: &str) -> Result<(), DaemonError> { self.exec_request( Method::POST, - &format!("/v1/invitations/{}/accept", invitation_id), + &format!("/v1/invitations/{invitation_id}/accept"), |r| r, ) .await @@ -584,8 +576,7 @@ impl Daemon for BackendWalletClient { DaemonError::Http(http_status, serde_json::Value::String(error)) } else { DaemonError::Unexpected(format!( - "Cannot update Liana-connect cache: {}", - e + "Cannot update Liana-connect cache: {e}" )) } })?; @@ -900,7 +891,7 @@ impl Daemon for BackendWalletClient { .find(|tx| tx.txid == *txid) .ok_or(DaemonError::Http( Some(404), - serde_json::Value::String(format!("psbt not found with txid: {}", txid)), + serde_json::Value::String(format!("psbt not found with txid: {txid}")), ))?; self.inner @@ -1183,7 +1174,7 @@ fn history_tx_from_api(value: api::Transaction, network: Network) -> HistoryTran let mut changes_indexes = Vec::new(); let txid = value.raw.compute_txid().to_string(); for (index, output) in value.outputs.iter().enumerate() { - labels.insert(format!("{}:{}", txid, index), output.label.clone()); + labels.insert(format!("{txid}:{index}"), output.label.clone()); if let Some(address) = &output.address { labels.insert(address.to_string(), output.address_label.clone()); } @@ -1239,7 +1230,7 @@ fn spend_tx_from_api( let mut changes_indexes = Vec::new(); let txid = value.raw.unsigned_tx.compute_txid().to_string(); for (index, output) in value.outputs.iter().enumerate() { - labels.insert(format!("{}:{}", txid, index), output.label.clone()); + labels.insert(format!("{txid}:{index}"), output.label.clone()); if let Some(address) = &output.address { labels.insert(address.to_string(), output.address_label.clone()); } diff --git a/liana-gui/src/services/connect/client/cache.rs b/liana-gui/src/services/connect/client/cache.rs index 19e86547e..02f7016e8 100644 --- a/liana-gui/src/services/connect/client/cache.rs +++ b/liana-gui/src/services/connect/client/cache.rs @@ -35,11 +35,11 @@ impl ConnectCache { std::fs::read(path) .map_err(|e| match e.kind() { std::io::ErrorKind::NotFound => ConnectCacheError::NotFound, - _ => ConnectCacheError::ReadingFile(format!("Reading settings file: {}", e)), + _ => ConnectCacheError::ReadingFile(format!("Reading settings file: {e}")), }) .and_then(|file_content| { serde_json::from_slice::(&file_content).map_err(|e| { - ConnectCacheError::ReadingFile(format!("Parsing settings file: {}", e)) + ConnectCacheError::ReadingFile(format!("Parsing settings file: {e}")) }) }) } @@ -74,7 +74,7 @@ pub async fn update_connect_cache( // Create parent directory if it doesn't exist if let Some(parent) = path.parent() { std::fs::create_dir_all(parent) - .map_err(|e| ConnectCacheError::WritingFile(format!("Creating directory: {}", e)))?; + .map_err(|e| ConnectCacheError::WritingFile(format!("Creating directory: {e}")))?; } let file_exists = tokio::fs::try_exists(&path).await.unwrap_or(false); @@ -86,16 +86,16 @@ pub async fn update_connect_cache( .truncate(false) .open(&path) .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Opening file: {}", e)))? + .map_err(|e| ConnectCacheError::ReadingFile(format!("Opening file: {e}")))? .lock_write() .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Locking file: {:?}", e)))?; + .map_err(|e| ConnectCacheError::ReadingFile(format!("Locking file: {e:?}")))?; let mut cache = if file_exists { let mut file_content = Vec::new(); file.read_to_end(&mut file_content) .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Reading file content: {}", e)))?; + .map_err(|e| ConnectCacheError::ReadingFile(format!("Reading file content: {e}")))?; match serde_json::from_slice::(&file_content) { Ok(cache) => cache, @@ -129,11 +129,11 @@ pub async fn update_connect_cache( cache.upsert_credential(email, tokens.clone()); let content = serde_json::to_vec_pretty(&cache).map_err(|e| { - ConnectCacheError::WritingFile(format!("Failed to serialize settings: {}", e)) + ConnectCacheError::WritingFile(format!("Failed to serialize settings: {e}")) })?; file.seek(SeekFrom::Start(0)).await.map_err(|e| { - ConnectCacheError::WritingFile(format!("Failed to seek to start of file: {}", e)) + ConnectCacheError::WritingFile(format!("Failed to seek to start of file: {e}")) })?; file.write_all(&content).await.map_err(|e| { @@ -144,7 +144,7 @@ pub async fn update_connect_cache( file.inner_mut() .set_len(content.len() as u64) .await - .map_err(|e| ConnectCacheError::WritingFile(format!("Failed to truncate file: {}", e)))?; + .map_err(|e| ConnectCacheError::WritingFile(format!("Failed to truncate file: {e}")))?; Ok(tokens) } @@ -159,7 +159,7 @@ pub async fn filter_connect_cache( // Create parent directory if it doesn't exist if let Some(parent) = path.parent() { std::fs::create_dir_all(parent) - .map_err(|e| ConnectCacheError::WritingFile(format!("Creating directory: {}", e)))?; + .map_err(|e| ConnectCacheError::WritingFile(format!("Creating directory: {e}")))?; } let file_exists = tokio::fs::try_exists(&path).await.unwrap_or(false); @@ -171,16 +171,16 @@ pub async fn filter_connect_cache( .truncate(false) .open(&path) .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Opening file: {}", e)))? + .map_err(|e| ConnectCacheError::ReadingFile(format!("Opening file: {e}")))? .lock_write() .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Locking file: {:?}", e)))?; + .map_err(|e| ConnectCacheError::ReadingFile(format!("Locking file: {e:?}")))?; let mut cache = if file_exists { let mut file_content = Vec::new(); file.read_to_end(&mut file_content) .await - .map_err(|e| ConnectCacheError::ReadingFile(format!("Reading file content: {}", e)))?; + .map_err(|e| ConnectCacheError::ReadingFile(format!("Reading file content: {e}")))?; match serde_json::from_slice::(&file_content) { Ok(cache) => cache, @@ -197,11 +197,11 @@ pub async fn filter_connect_cache( cache.accounts.retain(|a| emails.contains(&a.email)); let content = serde_json::to_vec_pretty(&cache).map_err(|e| { - ConnectCacheError::WritingFile(format!("Failed to serialize settings: {}", e)) + ConnectCacheError::WritingFile(format!("Failed to serialize settings: {e}")) })?; file.seek(SeekFrom::Start(0)).await.map_err(|e| { - ConnectCacheError::WritingFile(format!("Failed to seek to start of file: {}", e)) + ConnectCacheError::WritingFile(format!("Failed to seek to start of file: {e}")) })?; file.write_all(&content).await.map_err(|e| { @@ -212,7 +212,7 @@ pub async fn filter_connect_cache( file.inner_mut() .set_len(content.len() as u64) .await - .map_err(|e| ConnectCacheError::WritingFile(format!("Failed to truncate file: {}", e)))?; + .map_err(|e| ConnectCacheError::WritingFile(format!("Failed to truncate file: {e}")))?; Ok(()) } @@ -229,10 +229,10 @@ impl std::fmt::Display for ConnectCacheError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::NotFound => write!(f, "ConnectCache file not found"), - Self::ReadingFile(e) => write!(f, "Error while reading file: {}", e), - Self::WritingFile(e) => write!(f, "Error while writing file: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), - Self::Updating(e) => write!(f, "Error while updating cache file: {}", e), + Self::ReadingFile(e) => write!(f, "Error while reading file: {e}"), + Self::WritingFile(e) => write!(f, "Error while writing file: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), + Self::Updating(e) => write!(f, "Error while updating cache file: {e}"), } } } diff --git a/liana-gui/src/services/connect/client/mod.rs b/liana-gui/src/services/connect/client/mod.rs index 55c4aa1a0..7e466a902 100644 --- a/liana-gui/src/services/connect/client/mod.rs +++ b/liana-gui/src/services/connect/client/mod.rs @@ -54,7 +54,7 @@ pub async fn get_service_config( }; let client = reqwest::Client::new(); let res: ServiceConfigResource = client - .get(format!("{}/v1/desktop", backend_api_url)) + .get(format!("{backend_api_url}/v1/desktop")) .header("User-Agent", backend.user_agent()) .send() .await? diff --git a/liana-gui/src/services/connect/login.rs b/liana-gui/src/services/connect/login.rs index 385624c58..4dee6eaf8 100644 --- a/liana-gui/src/services/connect/login.rs +++ b/liana-gui/src/services/connect/login.rs @@ -40,12 +40,12 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::Auth(e) => write!(f, "Authentication error: {}", e), + Self::Auth(e) => write!(f, "Authentication error: {e}"), Self::CredentialsMissing => write!(f, "credentials missing"), - Self::Backend(e) => write!(f, "Remote backend error: {}", e), - Self::Settings(e) => write!(f, "Settings file error: {}", e), - Self::Cache(e) => write!(f, "Connect cache file error: {}", e), - Self::Unexpected(e) => write!(f, "Unexpected error: {}", e), + Self::Backend(e) => write!(f, "Remote backend error: {e}"), + Self::Settings(e) => write!(f, "Settings file error: {e}"), + Self::Cache(e) => write!(f, "Connect cache file error: {e}"), + Self::Unexpected(e) => write!(f, "Unexpected error: {e}"), } } } @@ -105,6 +105,7 @@ pub enum ViewMessage { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum BackendState { NoWallet(BackendClient), WalletExists( diff --git a/liana-gui/src/services/fiat/api.rs b/liana-gui/src/services/fiat/api.rs index e2f54eef0..415afe613 100644 --- a/liana-gui/src/services/fiat/api.rs +++ b/liana-gui/src/services/fiat/api.rs @@ -26,10 +26,10 @@ pub enum PriceApiError { impl std::fmt::Display for PriceApiError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::RequestFailed(e) => write!(f, "Request failed: {}", e), - Self::NotSuccessResponse(info) => write!(f, "Not success response: {:?}", info), - Self::CannotParseResponse(e) => write!(f, "Cannot parse response: {}", e), - Self::CannotParseData(e) => write!(f, "Cannot parse data: {}", e), + Self::RequestFailed(e) => write!(f, "Request failed: {e}"), + Self::NotSuccessResponse(info) => write!(f, "Not success response: {info:?}"), + Self::CannotParseResponse(e) => write!(f, "Cannot parse response: {e}"), + Self::CannotParseData(e) => write!(f, "Cannot parse data: {e}"), } } } diff --git a/liana-ui/src/component/amount.rs b/liana-ui/src/component/amount.rs index 40c7dfd06..0db870255 100644 --- a/liana-ui/src/component/amount.rs +++ b/liana-ui/src/component/amount.rs @@ -59,7 +59,7 @@ pub fn format_f64_as_string( sep_decimals: bool, ) -> String { // Format with the requested number of decimals. - let amount = format!("{:.*}", num_decimals, value); + let amount = format!("{value:.num_decimals$}"); // Split into integer and fractional parts. let (integer, fraction) = match amount.split_once('.') { diff --git a/liana-ui/src/component/hw.rs b/liana-ui/src/component/hw.rs index 1d594eba4..7bcba044f 100644 --- a/liana-ui/src/component/hw.rs +++ b/liana-ui/src/component/hw.rs @@ -47,7 +47,7 @@ pub fn supported_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>( Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -76,7 +76,7 @@ impl Display for Account { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let index = self.index.to_string(); let index = index.replace("'", ""); - write!(f, "Account #{}", index) + write!(f, "Account #{index}") } } @@ -122,7 +122,7 @@ pub fn supported_hardware_wallet_with_account< Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -155,7 +155,7 @@ pub fn warning_hardware_wallet<'a, T: 'static, K: Display, V: Display, F: Displa Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -189,7 +189,7 @@ pub fn unimplemented_method_hardware_wallet<'a, T: 'a, K: Display, V: Display, F tooltip::Tooltip::new( container( column(vec![ - text::p1_regular(format!("#{}", fingerprint)).into(), + text::p1_regular(format!("#{fingerprint}")).into(), Row::new() .spacing(5) .push(text::caption(kind.to_string())) @@ -215,7 +215,7 @@ pub fn disabled_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>( label: &'static str, ) -> Container<'a, T> { let key = column(vec![ - text::p1_regular(format!("#{}", fingerprint)).into(), + text::p1_regular(format!("#{fingerprint}")).into(), Row::new() .spacing(5) .push(text::caption(kind.to_string())) @@ -264,7 +264,7 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display> Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -309,7 +309,7 @@ pub fn selected_hardware_wallet<'a, T: 'static, K: Display, V: Display, F: Displ Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -349,7 +349,7 @@ pub fn sign_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -384,7 +384,7 @@ pub fn registration_success_hardware_wallet<'a, T: 'a, K: Display, V: Display, F Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -480,7 +480,7 @@ pub fn unsupported_version_hardware_wallet<'a, T: 'static, K: Display, V: Displa row(vec![ column(vec![ text::p1_bold("Unsupported firmware version").into(), - text::p1_regular(format!("Install version {} or later", requested_version)).into(), + text::p1_regular(format!("Install version {requested_version} or later")).into(), Row::new() .spacing(5) .push(text::caption(kind.to_string())) @@ -525,7 +525,7 @@ pub fn sign_success_hot_signer<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -557,7 +557,7 @@ pub fn selected_hot_signer<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -585,7 +585,7 @@ pub fn unselected_hot_signer<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -611,7 +611,7 @@ pub fn hot_signer<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push_maybe(alias.map(|a| text::p1_bold(a))) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -644,7 +644,7 @@ pub fn selected_provider_key<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push(text::p1_bold(alias)) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -671,7 +671,7 @@ pub fn unselected_provider_key<'a, T: 'a, F: Display>( Row::new() .spacing(5) .push(text::p1_bold(alias)) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) @@ -695,7 +695,7 @@ pub fn unsaved_provider_key<'a, T: 'a, F: Display>( column(vec![ Row::new() .spacing(5) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) diff --git a/liana-ui/src/component/notification.rs b/liana-ui/src/component/notification.rs index 887da43d4..c27dc1708 100644 --- a/liana-ui/src/component/notification.rs +++ b/liana-ui/src/component/notification.rs @@ -69,7 +69,7 @@ pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display> Row::new() .spacing(5) .push_maybe(alias.map(text::p1_bold)) - .push(text::p1_regular(format!("#{}", fingerprint))) + .push(text::p1_regular(format!("#{fingerprint}"))) .into(), Row::new() .spacing(5) diff --git a/liana-ui/src/component/toast.rs b/liana-ui/src/component/toast.rs index bbf3d5366..51c876b91 100644 --- a/liana-ui/src/component/toast.rs +++ b/liana-ui/src/component/toast.rs @@ -79,7 +79,7 @@ where instants.truncate(new); } (old, new) if old < new => { - instants.extend(std::iter::repeat(Some(Instant::now())).take(new - old)); + instants.extend(std::iter::repeat_n(Some(Instant::now()), new - old)); } _ => {} } diff --git a/liana-ui/src/widget/menu.rs b/liana-ui/src/widget/menu.rs index 6118bb803..badcd54a6 100644 --- a/liana-ui/src/widget/menu.rs +++ b/liana-ui/src/widget/menu.rs @@ -401,7 +401,6 @@ where if let Some(msg) = (self.on_select)(content) { shell.publish(msg); } - return; } } } @@ -449,7 +448,6 @@ where if let Some(msg) = (self.on_select)(content) { shell.publish(msg); } - return; } } } diff --git a/liana-ui/src/widget/text_input.rs b/liana-ui/src/widget/text_input.rs index 9e2c4f6fc..9d04888f2 100644 --- a/liana-ui/src/widget/text_input.rs +++ b/liana-ui/src/widget/text_input.rs @@ -557,8 +557,6 @@ where // Event wasn't processed by overlay, so cursor was clicked either outside its // bounds or on the drop-down, either way we close the overlay. state.menu.is_open = false; - - return; } else if cursor.is_over(layout.bounds()) { state.menu.is_open = true; return; @@ -660,8 +658,6 @@ where } state.last_click = Some(click); - - return; } } Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) @@ -701,8 +697,6 @@ where state .cursor .select_range(state.cursor.start(&value), position); - - return; } } Event::Keyboard(keyboard::Event::KeyPressed { key, text, .. }) => { @@ -946,13 +940,9 @@ where } keyboard::Key::Named( key::Named::Tab | key::Named::ArrowUp | key::Named::ArrowDown, - ) => { - return; - } + ) => {} _ => {} } - - return; } } Event::Keyboard(keyboard::Event::KeyReleased { key, .. }) => { diff --git a/liana/src/descriptors/analysis.rs b/liana/src/descriptors/analysis.rs index c4e4b0fc6..5240b3606 100644 --- a/liana/src/descriptors/analysis.rs +++ b/liana/src/descriptors/analysis.rs @@ -40,29 +40,28 @@ impl std::fmt::Display for LianaPolicyError { match self { Self::MissingRecoveryPath => write!(f, "A Liana policy requires at least one recovery path."), Self::InsaneTimelock(tl) => { - write!(f, "Timelock value '{}' isn't valid or safe to use", tl) + write!(f, "Timelock value '{tl}' isn't valid or safe to use") } Self::InvalidKey(key) => { write!( f, - "Invalid key '{}'. Need a wildcard ('ranged') xpub with an origin and a multipath for (and only for) deriving change addresses. That is, an xpub of the form '[aaff0099]xpub.../<0;1>/*'.", - key + "Invalid key '{key}'. Need a wildcard ('ranged') xpub with an origin and a multipath for (and only for) deriving change addresses. That is, an xpub of the form '[aaff0099]xpub.../<0;1>/*'." ) } - Self::InvalidMultiThresh(thresh) => write!(f, "Invalid multisig threshold value '{}'. The threshold must be > to 0 and <= to the number of keys.", thresh), - Self::InvalidMultiKeys(n_keys) => write!(f, "Invalid number of keys '{}'. Between 2 and 20 keys must be given to use multiple keys in a specific path.", n_keys), + Self::InvalidMultiThresh(thresh) => write!(f, "Invalid multisig threshold value '{thresh}'. The threshold must be > to 0 and <= to the number of keys."), + Self::InvalidMultiKeys(n_keys) => write!(f, "Invalid number of keys '{n_keys}'. Between 2 and 20 keys must be given to use multiple keys in a specific path."), Self::DuplicateKey(key) => { - write!(f, "Duplicate key '{}'.", key) + write!(f, "Duplicate key '{key}'.") } Self::DuplicateOriginSamePath(key) => { - write!(f, "Key '{}' is derived from the same origin as another key present in the same spending path. It is not possible to use a signer more than once within a single spending path.", key) + write!(f, "Key '{key}' is derived from the same origin as another key present in the same spending path. It is not possible to use a signer more than once within a single spending path.") } Self::IncompatibleDesc => write!( f, "Descriptor is not compatible with a Liana spending policy." ), - Self::InvalidPolicy(e) => write!(f, "Invalid Miniscript policy: {}", e), - Self::PolicyAnalysis(e) => write!(f, "Analyzing the policy of the miniscript: {}", e), + Self::InvalidPolicy(e) => write!(f, "Invalid Miniscript policy: {e}"), + Self::PolicyAnalysis(e) => write!(f, "Analyzing the policy of the miniscript: {e}"), } } } @@ -96,7 +95,7 @@ impl DescKeyChecker { /// - Be deriveable (to contain a wildcard) /// - Be multipath (to contain a step in the derivation path with multiple indexes) /// - The multipath step to only contain two indexes. These can be any indexes, which is - /// useful for deriving multiple keys from the same xpub. + /// useful for deriving multiple keys from the same xpub. /// - Be 'signable' by an external signer (to contain an origin) /// /// This returns the origin fingerprint for this xpub, to make it possible for the caller to diff --git a/liana/src/descriptors/keys.rs b/liana/src/descriptors/keys.rs index 788d8a21f..8b9de5455 100644 --- a/liana/src/descriptors/keys.rs +++ b/liana/src/descriptors/keys.rs @@ -39,10 +39,10 @@ impl fmt::Display for DerivedPublicKey { write!(f, "[")?; for byte in fingerprint.as_bytes().iter() { - write!(f, "{:02x}", byte)?; + write!(f, "{byte:02x}")?; } for child in deriv_path { - write!(f, "/{}", child)?; + write!(f, "/{child}")?; } write!(f, "]{}", self.key) } diff --git a/liana/src/descriptors/mod.rs b/liana/src/descriptors/mod.rs index 9ab29756b..44f627300 100644 --- a/liana/src/descriptors/mod.rs +++ b/liana/src/descriptors/mod.rs @@ -42,9 +42,9 @@ pub enum LianaDescError { impl std::fmt::Display for LianaDescError { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { match self { - Self::Miniscript(e) => write!(f, "Miniscript error: '{}'.", e), - Self::DescKey(e) => write!(f, "{}", e), - Self::Policy(e) => write!(f, "{}", e), + Self::Miniscript(e) => write!(f, "Miniscript error: '{e}'."), + Self::DescKey(e) => write!(f, "{e}"), + Self::Policy(e) => write!(f, "{e}"), Self::InsanePsbt => write!(f, "Analyzed PSBT is empty or malformed."), Self::InconsistentPsbt => write!(f, "Analyzed PSBT is inconsistent across inputs."), } @@ -614,7 +614,7 @@ impl LianaDescriptor { /// - If there is two recovery paths, and the PSBT's first input nSequence isn't set to unlock /// any of them, prune all but the primary path's bip32 derivations. /// - If there is two recovery paths, and the PSBT's first input nSequence is set to unlock the - /// first one, prune all but the first recovery path's bip32 derivations. + /// first one, prune all but the first recovery path's bip32 derivations. /// - Etc.. pub fn prune_bip32_derivs_last_avail(&self, psbt: Psbt) -> Result { let spend_info = self.partial_spend_info(&psbt)?; diff --git a/liana/src/random.rs b/liana/src/random.rs index ea567b039..94af74386 100644 --- a/liana/src/random.rs +++ b/liana/src/random.rs @@ -16,9 +16,9 @@ pub enum RandomnessError { impl fmt::Display for RandomnessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::Hardware(s) => write!(f, "Error when getting randomness from hardware: {}", s), - Self::Os(s) => write!(f, "Error when getting randomness from the OS: {}", s), - Self::ContextualInfo(s) => write!(f, "Error when getting contextual info: {}", s), + Self::Hardware(s) => write!(f, "Error when getting randomness from hardware: {s}"), + Self::Os(s) => write!(f, "Error when getting randomness from the OS: {s}"), + Self::ContextualInfo(s) => write!(f, "Error when getting contextual info: {s}"), } } } diff --git a/liana/src/signer.rs b/liana/src/signer.rs index be7f671b0..14e9d62f8 100644 --- a/liana/src/signer.rs +++ b/liana/src/signer.rs @@ -37,10 +37,10 @@ pub enum SignerError { impl fmt::Display for SignerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::Randomness(s) => write!(f, "Error related to getting randomness: {}", s), - Self::Mnemonic(s) => write!(f, "Error when working with mnemonics: {}", s), - Self::Bip32(e) => write!(f, "BIP32 error: {}", e), - Self::MnemonicStorage(e) => write!(f, "BIP39 mnemonic storage error: {}", e), + Self::Randomness(s) => write!(f, "Error related to getting randomness: {s}"), + Self::Mnemonic(s) => write!(f, "Error when working with mnemonics: {s}"), + Self::Bip32(e) => write!(f, "BIP32 error: {e}"), + Self::MnemonicStorage(e) => write!(f, "BIP39 mnemonic storage error: {e}"), Self::InsanePsbt => write!(f, "Information contained in the PSBT is wrong."), Self::IncompletePsbt => write!( f, diff --git a/liana/src/spend.rs b/liana/src/spend.rs index 4cbe42417..57e07d872 100644 --- a/liana/src/spend.rs +++ b/liana/src/spend.rs @@ -1,3 +1,5 @@ +#![allow(clippy::result_large_err)] + use crate::descriptors; use std::{ @@ -53,6 +55,7 @@ pub enum InsaneFeeInfo { #[derive(Debug, Clone, PartialEq, Eq)] pub enum SpendCreationError { InvalidFeerate(/* sats/vb */ u64), + #[allow(clippy::large_enum_variant)] InvalidOutputValue(bitcoin::Amount), InsaneFees(InsaneFeeInfo), SanityCheckFailure(Psbt), @@ -63,8 +66,8 @@ pub enum SpendCreationError { impl fmt::Display for SpendCreationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::InvalidFeerate(sats_vb) => write!(f, "Invalid feerate: {} sats/vb.", sats_vb), - Self::InvalidOutputValue(amount) => write!(f, "Invalid output value '{}'.", amount), + Self::InvalidFeerate(sats_vb) => write!(f, "Invalid feerate: {sats_vb} sats/vb."), + Self::InvalidOutputValue(amount) => write!(f, "Invalid output value '{amount}'."), Self::InsaneFees(info) => write!( f, "We assume transactions with a fee larger than {} or a feerate larger than {} sats/vb are a mistake. \ @@ -73,19 +76,18 @@ impl fmt::Display for SpendCreationError { MAX_FEERATE, match info { InsaneFeeInfo::NegativeFee => "would have a negative fee".to_string(), - InsaneFeeInfo::TooHighFee(f) => format!("{} sats in fees", f), + InsaneFeeInfo::TooHighFee(f) => format!("{f} sats in fees"), InsaneFeeInfo::InvalidFeerate => "would have an invalid feerate".to_string(), - InsaneFeeInfo::TooHighFeerate(r) => format!("has a feerate of {} sats/vb", r), + InsaneFeeInfo::TooHighFeerate(r) => format!("has a feerate of {r} sats/vb"), }, ), Self::FetchingTransaction(op) => { - write!(f, "Could not fetch transaction for coin {}", op) + write!(f, "Could not fetch transaction for coin {op}") } - Self::CoinSelection(e) => write!(f, "Coin selection error: '{}'", e), + Self::CoinSelection(e) => write!(f, "Coin selection error: '{e}'"), Self::SanityCheckFailure(psbt) => write!( f, - "BUG! Please report this. Failed sanity checks for PSBT '{}'.", - psbt + "BUG! Please report this. Failed sanity checks for PSBT '{psbt}'." ), } } diff --git a/lianad/src/bin/cli.rs b/lianad/src/bin/cli.rs index 66cf3d764..0a1d7ea5f 100644 --- a/lianad/src/bin/cli.rs +++ b/lianad/src/bin/cli.rs @@ -85,7 +85,7 @@ fn rpc_request(method: String, params: Vec) -> Json { fn socket_file(conf_file: Option) -> PathBuf { let config = Config::from_file(conf_file).unwrap_or_else(|e| { - eprintln!("Error getting config: {}", e); + eprintln!("Error getting config: {e}"); process::exit(1); }); let data_dir = config @@ -117,7 +117,7 @@ fn main() { let mut raw_response = vec![0; 256]; let mut socket = UnixStream::connect(&socket_file).unwrap_or_else(|e| { - eprintln!("Could not connect to {:?}: '{}'", socket_file, e); + eprintln!("Could not connect to {socket_file:?}: '{e}'"); process::exit(1); }); socket @@ -147,7 +147,7 @@ fn main() { Ok(response) => { if response.get("id") == request.get("id") { if raw { - print!("{}", response); + print!("{response}"); } else if let Some(r) = response.get("result") { println!("{:#}", serde_json::json!({ "result": r })); } else if let Some(e) = response.get("error") { @@ -157,7 +157,7 @@ fn main() { "lianad response doesn't contain result or error: '{}'", response ); - println!("{:#}", response); + println!("{response:#}"); } return; } diff --git a/lianad/src/bin/daemon.rs b/lianad/src/bin/daemon.rs index dcc756bdb..b18c05391 100644 --- a/lianad/src/bin/daemon.rs +++ b/lianad/src/bin/daemon.rs @@ -8,7 +8,7 @@ use std::{ use lianad::{config::Config, setup_panic_hook, DaemonHandle, VERSION}; fn print_help_exit(code: i32) { - eprintln!("lianad version {}", VERSION); + eprintln!("lianad version {VERSION}"); eprintln!("A TOML configuration file is required to run lianad. By default lianad looks for a 'config.toml' file in its data directory. A different one may be provided like so: '--conf '."); eprintln!("A documented sample is available at 'contrib/lianad_config_example.toml' in the source tree (https://github.com/wizardsardine/liana/blob/v1.0/contrib/lianad_config_example.toml)."); eprintln!("The default data directory path is a 'liana/' folder in the XDG standard configuration directory for all OSes but Linux ones, where it's '~/.liana/'."); @@ -16,7 +16,7 @@ fn print_help_exit(code: i32) { } fn print_version() { - eprintln!("{}", VERSION); + eprintln!("{VERSION}"); process::exit(0); } @@ -49,7 +49,7 @@ fn setup_logger(log_level: log::LevelFilter) -> Result<(), fern::InitError> { time::SystemTime::now() .duration_since(time::UNIX_EPOCH) .unwrap_or_else(|e| { - println!("Can't get time since epoch: '{}'. Using a dummy value.", e); + println!("Can't get time since epoch: '{e}'. Using a dummy value."); time::Duration::from_secs(0) }) .as_secs(), @@ -71,12 +71,12 @@ fn main() { let conf_file = parse_args(args); let config = Config::from_file(conf_file).unwrap_or_else(|e| { - eprintln!("Error parsing config: {}", e); + eprintln!("Error parsing config: {e}"); print_help_exit(1); unreachable!(); }); setup_logger(config.log_level).unwrap_or_else(|e| { - eprintln!("Error setting up logger: {}", e); + eprintln!("Error setting up logger: {e}"); process::exit(1); }); diff --git a/lianad/src/bitcoin/d/mod.rs b/lianad/src/bitcoin/d/mod.rs index 427a16248..a65c8a780 100644 --- a/lianad/src/bitcoin/d/mod.rs +++ b/lianad/src/bitcoin/d/mod.rs @@ -120,27 +120,25 @@ impl BitcoindError { impl std::fmt::Display for BitcoindError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - BitcoindError::CookieFile(e) => write!(f, "Reading bitcoind cookie file: {}", e), - BitcoindError::Server(ref e) => write!(f, "Bitcoind RPC server error: {}", e), + BitcoindError::CookieFile(e) => write!(f, "Reading bitcoind cookie file: {e}"), + BitcoindError::Server(ref e) => write!(f, "Bitcoind RPC server error: {e}"), BitcoindError::BatchMissingResponse => write!( f, "Bitcoind server replied without enough responses to our batched request" ), BitcoindError::Wallet(path, e) => { - write!(f, "Watchonly wallet (path: {}) error: {}", path, e) + write!(f, "Watchonly wallet (path: {path}) error: {e}") } BitcoindError::InvalidVersion(v) => { write!( f, - "Invalid bitcoind version '{}', minimum supported is '{}' and minimum supported if using Taproot is '{}'.", - v, MIN_BITCOIND_VERSION, MIN_TAPROOT_BITCOIND_VERSION + "Invalid bitcoind version '{v}', minimum supported is '{MIN_BITCOIND_VERSION}' and minimum supported if using Taproot is '{MIN_TAPROOT_BITCOIND_VERSION}'." ) } BitcoindError::NetworkMismatch(conf_net, bitcoind_net) => { write!( f, - "Network mismatch. We are supposed to run on '{}' but bitcoind is on '{}'.", - conf_net, bitcoind_net + "Network mismatch. We are supposed to run on '{conf_net}' but bitcoind is on '{bitcoind_net}'." ) } BitcoindError::StartRescan => { @@ -186,15 +184,14 @@ impl std::fmt::Display for WalletError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { WalletError::Creating(s) => { - write!(f, "Error creating watchonly wallet: {}", s) + write!(f, "Error creating watchonly wallet: {s}") } WalletError::ImportingDescriptor(s) => write!( f, - "Error importing descriptor. Response from bitcoind: '{}'", - s + "Error importing descriptor. Response from bitcoind: '{s}'" ), WalletError::Loading(s) => { - write!(f, "Error when loading watchonly wallet: '{}'.", s) + write!(f, "Error when loading watchonly wallet: '{s}'.") } WalletError::MissingOrTooManyWallet => { write!( diff --git a/lianad/src/bitcoin/electrum/client.rs b/lianad/src/bitcoin/electrum/client.rs index 74cb2a4f4..266d927e8 100644 --- a/lianad/src/bitcoin/electrum/client.rs +++ b/lianad/src/bitcoin/electrum/client.rs @@ -39,7 +39,7 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Error::Server(e) => write!(f, "Electrum error: '{}'.", e), + Error::Server(e) => write!(f, "Electrum error: '{e}'."), Error::TipChanged(expected, actual) => write!( f, "Electrum error: Expected tip '{}' but actual tip was {}.", diff --git a/lianad/src/bitcoin/electrum/mod.rs b/lianad/src/bitcoin/electrum/mod.rs index 96b9b77ac..21c70208f 100644 --- a/lianad/src/bitcoin/electrum/mod.rs +++ b/lianad/src/bitcoin/electrum/mod.rs @@ -26,13 +26,12 @@ pub enum ElectrumError { impl std::fmt::Display for ElectrumError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - ElectrumError::Client(e) => write!(f, "Electrum client error: '{}'.", e), + ElectrumError::Client(e) => write!(f, "Electrum client error: '{e}'."), ElectrumError::GenesisHashMismatch(expected, server, wallet) => { write!( f, - "Genesis hash mismatch. The genesis hash is expected to be '{}'. \ - The server has hash '{}' and the wallet has hash '{}'.", - expected, server, wallet, + "Genesis hash mismatch. The genesis hash is expected to be '{expected}'. \ + The server has hash '{server}' and the wallet has hash '{wallet}'.", ) } } @@ -150,8 +149,8 @@ impl Electrum { .index() .inner() // we include lookahead SPKs .all_spks() - .iter() - .map(|(_, script)| script.clone()) + .values() + .cloned() .collect(); request = request.chain_spks(all_spks); log::debug!("num SPKs for sync: {}", request.spks.len()); diff --git a/lianad/src/commands/mod.rs b/lianad/src/commands/mod.rs index c25afeab1..3fcdb8cea 100644 --- a/lianad/src/commands/mod.rs +++ b/lianad/src/commands/mod.rs @@ -1,6 +1,7 @@ //! # Liana commands //! //! External interface to the Liana daemon. +#![allow(clippy::result_large_err)] mod utils; @@ -46,6 +47,7 @@ use miniscript::{ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq)] +#[allow(clippy::large_enum_variant)] pub enum CommandError { NoOutpointForSelfSend, InvalidFeerate(/* sats/vb */ u64), @@ -82,55 +84,50 @@ impl fmt::Display for CommandError { Self::NoOutpointForSelfSend => { write!(f, "No provided outpoint for self-send. Need at least one.") } - Self::InvalidFeerate(sats_vb) => write!(f, "Invalid feerate: {} sats/vb.", sats_vb), - Self::AlreadySpent(op) => write!(f, "Coin at '{}' is already spent.", op), + Self::InvalidFeerate(sats_vb) => write!(f, "Invalid feerate: {sats_vb} sats/vb."), + Self::AlreadySpent(op) => write!(f, "Coin at '{op}' is already spent."), Self::ImmatureCoinbase(op) => write!( f, - "Coin at '{}' is from an immature coinbase transaction.", - op + "Coin at '{op}' is from an immature coinbase transaction." ), - Self::UnknownOutpoint(op) => write!(f, "Unknown outpoint '{}'.", op), - Self::Address(e) => write!(f, "Address error: {}", e), - Self::SpendCreation(e) => write!(f, "Creating spend: {}", e), + Self::UnknownOutpoint(op) => write!(f, "Unknown outpoint '{op}'."), + Self::Address(e) => write!(f, "Address error: {e}"), + Self::SpendCreation(e) => write!(f, "Creating spend: {e}"), Self::InsufficientFunds(in_val, out_val, feerate) => { if let Some(out_val) = out_val { write!( f, - "Cannot create a {} sat/vb transaction with input value {} and output value {}", - feerate, in_val, out_val + "Cannot create a {feerate} sat/vb transaction with input value {in_val} and output value {out_val}" ) } else { write!( f, - "Not enough fund to create a {} sat/vb transaction with input value {}", - feerate, in_val + "Not enough fund to create a {feerate} sat/vb transaction with input value {in_val}" ) } } - Self::UnknownSpend(txid) => write!(f, "Unknown spend transaction '{}'.", txid), + Self::UnknownSpend(txid) => write!(f, "Unknown spend transaction '{txid}'."), Self::SpendFinalization(e) => { - write!(f, "Failed to finalize the spend transaction PSBT: '{}'.", e) + write!(f, "Failed to finalize the spend transaction PSBT: '{e}'.") } - Self::TxBroadcast(e) => write!(f, "Failed to broadcast transaction: '{}'.", e), + Self::TxBroadcast(e) => write!(f, "Failed to broadcast transaction: '{e}'."), Self::AlreadyRescanning => write!( f, "There is already a rescan ongoing. Please wait for it to complete first." ), - Self::InsaneRescanTimestamp(t) => write!(f, "Insane timestamp '{}'.", t), - Self::RescanTrigger(s) => write!(f, "Error while starting rescan: '{}'", s), + Self::InsaneRescanTimestamp(t) => write!(f, "Insane timestamp '{t}'."), + Self::RescanTrigger(s) => write!(f, "Error while starting rescan: '{s}'"), Self::RecoveryNotAvailable => write!( f, "No coin currently spendable through this timelocked recovery path." ), - Self::OutpointNotRecoverable(op, t) => write!( - f, - "Coin at '{}' is not recoverable with timelock '{}'", - op, t - ), + Self::OutpointNotRecoverable(op, t) => { + write!(f, "Coin at '{op}' is not recoverable with timelock '{t}'") + } Self::InvalidDerivationIndex => { write!(f, "Unhardened or overflowing BIP32 derivation index.") } - Self::RbfError(e) => write!(f, "RBF error: '{}'.", e), + Self::RbfError(e) => write!(f, "RBF error: '{e}'."), Self::EmptyFilterList => write!(f, "Filter list is empty, should supply None instead."), } } @@ -162,7 +159,7 @@ impl fmt::Display for RbfErrorInfo { write!(f, "A feerate must not be provided if creating a cancel. We'll always use the smallest one which satisfies the RBF rules.") } Self::TooLowFeerate(r, m) => { - write!(f, "Feerate {} too low for minimum feerate {}.", r, m) + write!(f, "Feerate {r} too low for minimum feerate {m}.") } Self::NotSignaling => write!(f, "Replacement candidate does not signal for RBF."), } @@ -1485,6 +1482,7 @@ pub struct ListCoinsResult { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(untagged)] +#[allow(clippy::large_enum_variant)] pub enum CreateSpendResult { Success { #[serde(serialize_with = "ser_to_string", deserialize_with = "deser_fromstr")] diff --git a/lianad/src/config.rs b/lianad/src/config.rs index 2d0b2f2c5..86f7ce992 100644 --- a/lianad/src/config.rs +++ b/lianad/src/config.rs @@ -14,8 +14,7 @@ where ::Err: std::fmt::Display, { let string = String::deserialize(deserializer)?; - T::from_str(&string) - .map_err(|e| de::Error::custom(format!("Error parsing '{}': {}", string, e))) + T::from_str(&string).map_err(|e| de::Error::custom(format!("Error parsing '{string}': {e}"))) } pub fn serialize_to_string( @@ -70,7 +69,7 @@ fn serialize_userpass( password: &String, s: S, ) -> Result { - s.serialize_str(&format!("{}:{}", user, password)) + s.serialize_str(&format!("{user}:{password}")) } fn default_loglevel() -> log::LevelFilter { @@ -226,13 +225,12 @@ impl std::fmt::Display for ConfigError { match &self { Self::DatadirNotFound => write!(f, "Could not locate the configuration directory."), Self::FileNotFound => write!(f, "Could not locate the configuration file."), - Self::ReadingFile(e) => write!(f, "Failed to read configuration file: {}", e), + Self::ReadingFile(e) => write!(f, "Failed to read configuration file: {e}"), Self::UnexpectedDescriptor(desc) => write!( f, - "Unexpected descriptor '{}'. We only support wsh() descriptors for now.", - desc + "Unexpected descriptor '{desc}'. We only support wsh() descriptors for now." ), - Self::Unexpected(e) => write!(f, "Configuration error: {}", e), + Self::Unexpected(e) => write!(f, "Configuration error: {e}"), } } } @@ -294,7 +292,7 @@ impl Config { custom_path.unwrap_or(config_file_path().ok_or(ConfigError::DatadirNotFound)?); let config = toml::from_slice::(&std::fs::read(config_file)?) - .map_err(|e| ConfigError::ReadingFile(format!("Parsing configuration file: {}", e)))?; + .map_err(|e| ConfigError::ReadingFile(format!("Parsing configuration file: {e}")))?; config.check()?; Ok(config) diff --git a/lianad/src/database/mod.rs b/lianad/src/database/mod.rs index 57c4a835a..fedc827d1 100644 --- a/lianad/src/database/mod.rs +++ b/lianad/src/database/mod.rs @@ -548,9 +548,9 @@ impl From for LabelItem { impl Display for LabelItem { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - LabelItem::Address(a) => write!(f, "{}", a), - LabelItem::Txid(a) => write!(f, "{}", a), - LabelItem::OutPoint(a) => write!(f, "{}", a), + LabelItem::Address(a) => write!(f, "{a}"), + LabelItem::Txid(a) => write!(f, "{a}"), + LabelItem::OutPoint(a) => write!(f, "{a}"), } } } diff --git a/lianad/src/database/sqlite/mod.rs b/lianad/src/database/sqlite/mod.rs index 5f6876ee0..661d94c12 100644 --- a/lianad/src/database/sqlite/mod.rs +++ b/lianad/src/database/sqlite/mod.rs @@ -63,21 +63,21 @@ impl std::fmt::Display for SqliteDbError { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { match self { SqliteDbError::FileCreation(e) => { - write!(f, "Error when create SQLite database file: '{}'", e) + write!(f, "Error when create SQLite database file: '{e}'") } SqliteDbError::FileNotFound(p) => { write!(f, "SQLite database file not found at '{}'.", p.display()) } SqliteDbError::UnsupportedVersion(v) => { - write!(f, "Unsupported database version '{}'.", v) + write!(f, "Unsupported database version '{v}'.") } SqliteDbError::InvalidNetwork(net) => { - write!(f, "Database was created for network '{}'.", net) + write!(f, "Database was created for network '{net}'.") } SqliteDbError::DescriptorMismatch(desc) => { - write!(f, "Database descriptor mismatch: '{}'.", desc) + write!(f, "Database descriptor mismatch: '{desc}'.") } - SqliteDbError::Rusqlite(e) => write!(f, "SQLite error: '{}'", e), + SqliteDbError::Rusqlite(e) => write!(f, "SQLite error: '{e}'"), } } } @@ -433,15 +433,15 @@ impl SqliteConn { String::new() }; let where_clause = if !status_condition.is_empty() && !op_condition.is_empty() { - format!(" WHERE ({}) AND ({})", status_condition, op_condition) + format!(" WHERE ({status_condition}) AND ({op_condition})") } else if status_condition.is_empty() && !op_condition.is_empty() { - format!(" WHERE {}", op_condition) + format!(" WHERE {op_condition}") } else if !status_condition.is_empty() && op_condition.is_empty() { - format!(" WHERE {}", status_condition) + format!(" WHERE {status_condition}") } else { String::new() }; - let query = format!("SELECT * FROM coins{}", where_clause); + let query = format!("SELECT * FROM coins{where_clause}"); db_query(&mut self.conn, &query, rusqlite::params![], |row| { row.try_into() }) @@ -668,7 +668,7 @@ impl SqliteConn { "SELECT * FROM labels where item in ({})", items .iter() - .map(|a| format!("'{}'", a)) + .map(|a| format!("'{a}'")) .collect::>() .join(",") ); diff --git a/lianad/src/database/sqlite/utils.rs b/lianad/src/database/sqlite/utils.rs index f881de4be..10c735353 100644 --- a/lianad/src/database/sqlite/utils.rs +++ b/lianad/src/database/sqlite/utils.rs @@ -122,8 +122,7 @@ pub fn create_fresh_db( .derive(index.into(), secp) .address(options.bitcoind_network); query += &format!( - "INSERT INTO addresses (receive_address, change_address, derivation_index) VALUES (\"{}\", \"{}\", {});\n", - receive_address, change_address, index + "INSERT INTO addresses (receive_address, change_address, derivation_index) VALUES (\"{receive_address}\", \"{change_address}\", {index});\n" ); } diff --git a/lianad/src/jsonrpc/api.rs b/lianad/src/jsonrpc/api.rs index 7f6082e6d..ee45383f2 100644 --- a/lianad/src/jsonrpc/api.rs +++ b/lianad/src/jsonrpc/api.rs @@ -53,7 +53,7 @@ fn create_spend(control: &DaemonControl, params: Params) -> Result) -> Result) -> Result Result 100 { return Err(Error::invalid_params(format!( - "Invalid 'labels.{}' value length: must be less or equal than 100 characters", - item + "Invalid 'labels.{item}' value length: must be less or equal than 100 characters" ))); } } let item = LabelItem::from_str(item, control.config.bitcoin_config.network).ok_or_else(|| { Error::invalid_params(format!( - "Invalid 'labels.{}' parameter: must be an address, a txid or an outpoint", - item + "Invalid 'labels.{item}' parameter: must be an address, a txid or an outpoint" )) })?; items.insert(item, value); @@ -452,16 +450,14 @@ fn get_labels(control: &DaemonControl, params: Params) -> Result fmt::Result { match self { - Self::Io(e) => write!(f, "{}", e), + Self::Io(e) => write!(f, "{e}"), Self::DefaultDataDirNotFound => write!( f, "Not data directory was specified and a default path could not be determined for this platform." @@ -117,11 +117,11 @@ impl fmt::Display for StartupError { ), Self::DbMigrateBitcoinTxs(msg) => write!( f, - "Error when migrating Bitcoin transaction from Bitcoin backend to database: {}.", msg + "Error when migrating Bitcoin transaction from Bitcoin backend to database: {msg}." ), - Self::Database(e) => write!(f, "Error initializing database: '{}'.", e), - Self::Bitcoind(e) => write!(f, "Error setting up bitcoind interface: '{}'.", e), - Self::Electrum(e) => write!(f, "Error setting up Electrum interface: '{}'.", e), + Self::Database(e) => write!(f, "Error initializing database: '{e}'."), + Self::Bitcoind(e) => write!(f, "Error setting up bitcoind interface: '{e}'."), + Self::Electrum(e) => write!(f, "Error setting up Electrum interface: '{e}'."), #[cfg(windows)] Self::NoWatchonlyInDatadir => { write!( @@ -354,6 +354,7 @@ impl DaemonControl { /// The handle to a Liana daemon. It might either be the handle for a daemon which exposes a /// JSONRPC server or one which exposes its API through a `DaemonControl`. +#[allow(clippy::large_enum_variant)] pub enum DaemonHandle { Controller { poller_sender: mpsc::SyncSender, From 6807e7ac7d10eb8ab342b9dacb634505bf161794 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Fri, 10 Apr 2026 15:38:34 +0200 Subject: [PATCH 4/4] descriptors check: use div_ceil --- liana/src/descriptors/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/liana/src/descriptors/mod.rs b/liana/src/descriptors/mod.rs index 44f627300..762fc103c 100644 --- a/liana/src/descriptors/mod.rs +++ b/liana/src/descriptors/mod.rs @@ -1224,8 +1224,11 @@ mod tests { fn inheritance_descriptor_sat_size() { let desc = LianaDescriptor::from_str("wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/<0;1>/*),and_v(v:pkh([abcdef01]tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/<0;1>/*),older(2))))#ravw7jw5").unwrap(); // See the stack details below. - assert_eq!(desc.max_sat_vbytes(true), (1 + 66 + 73 + 3) / 4); - assert_eq!(desc.max_sat_vbytes(false), (1 + 66 + 1 + 34 + 73 + 3) / 4); + assert_eq!(desc.max_sat_vbytes(true), (1_usize + 66 + 73).div_ceil(4)); + assert_eq!( + desc.max_sat_vbytes(false), + (1_usize + 66 + 1 + 34 + 73).div_ceil(4) + ); // Maximum input size is (txid + vout + scriptsig + nSequence + max_sat). // Where max_sat is: @@ -1272,12 +1275,12 @@ mod tests { ); // If using the primary path, it's a keypath spend. - assert_eq!(desc.max_sat_vbytes(true), (1 + 65 + 3) / 4); + assert_eq!(desc.max_sat_vbytes(true), (1_usize + 65).div_ceil(4)); // If using the recovery path, it's a script path spend. The script is 40 bytes long. The // control block is just the internal key and parity, so 33 bytes long. assert_eq!( desc.max_sat_vbytes(false), - (1 + 65 + 1 + 40 + 1 + 33 + 3) / 4 + (1_usize + 65 + 1 + 40 + 1 + 33).div_ceil(4) ); // The same against the spender_input_size() helper, adding the size of the txin and