From fb33b39cecf719e32926947ca46c2f7fe1351285 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Fri, 31 Jul 2026 09:47:24 +0200 Subject: [PATCH] fix(network): align applet with cosmic-settings 1.3 nmrs backend cosmic-settings 1.3 replaced its custom NetworkManager backend with nmrs and removed subscriptions/network-manager, which cosmic-applet-network still referenced by path. That broke manifest resolution for the whole workspace, so no applet package could be built at all. Take upstream's post-migration cosmic-applet-network wholesale (upstream e318f0d4 "migrate NetworkManager flow to nmrs 3.4" plus the nine network fixes that followed it). None of our local commits touched this crate's sources, only its manifest, so the only local adjustments to reapply are the libcosmic -> cosmic workspace alias and the 1.3.0 version. This also drops the cosmic-dbus-networkmanager dependency, and with it the last user of the now-dead cosmic-settings-network-manager and cosmic-settings-sound patch entries, which are removed from the workspace manifest. Co-Authored-By: Claude Opus 5 (1M context) --- Cargo.lock | 465 +++------- Cargo.toml | 3 - cosmic-applet-network/Cargo.toml | 10 +- cosmic-applet-network/src/app.rs | 1352 +++++++++++++++++----------- cosmic-applet-network/src/lib.rs | 1 - cosmic-applet-network/src/utils.rs | 18 - 6 files changed, 923 insertions(+), 926 deletions(-) delete mode 100644 cosmic-applet-network/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 5ca8bed1..dc5deede 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,17 +107,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.8.12" @@ -165,7 +154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.11.1", + "bitflags 2.13.1", "cc", "jni", "libc", @@ -532,9 +521,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] @@ -554,15 +543,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "block2" version = "0.5.1" @@ -722,7 +702,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "polling", "rustix 1.1.4", "slab", @@ -741,15 +721,6 @@ dependencies = [ "wayland-client", ] -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.2.62" @@ -786,16 +757,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clipboard-win" version = "5.4.1" @@ -951,7 +912,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "core-foundation 0.10.1", "libc", ] @@ -967,7 +928,7 @@ dependencies = [ [[package]] name = "cosmic-app-list" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-app-list-config", @@ -994,7 +955,7 @@ dependencies = [ [[package]] name = "cosmic-app-list-config" -version = "1.0.15" +version = "1.3.0" dependencies = [ "libcosmic-yoda", "serde", @@ -1002,7 +963,7 @@ dependencies = [ [[package]] name = "cosmic-applet-a11y" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-client-toolkit", @@ -1021,7 +982,7 @@ dependencies = [ [[package]] name = "cosmic-applet-audio" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-settings-audio-client", "futures", @@ -1044,7 +1005,7 @@ dependencies = [ [[package]] name = "cosmic-applet-battery" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-applets-config", @@ -1069,7 +1030,7 @@ dependencies = [ [[package]] name = "cosmic-applet-bluetooth" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "bluer", @@ -1088,7 +1049,7 @@ dependencies = [ [[package]] name = "cosmic-applet-input-sources" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-comp-config", "i18n-embed", @@ -1104,7 +1065,7 @@ dependencies = [ [[package]] name = "cosmic-applet-minimize" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "i18n-embed", @@ -1122,12 +1083,9 @@ dependencies = [ [[package]] name = "cosmic-applet-network" -version = "1.0.15" +version = "1.3.0" dependencies = [ - "anyhow", "async-fn-stream", - "cosmic-dbus-networkmanager", - "cosmic-settings-network-manager-subscription", "futures", "futures-util", "i18n-embed", @@ -1143,12 +1101,11 @@ dependencies = [ "tracing-log", "tracing-subscriber", "uuid", - "zbus", ] [[package]] name = "cosmic-applet-notifications" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-notifications-config", @@ -1168,7 +1125,7 @@ dependencies = [ [[package]] name = "cosmic-applet-power" -version = "1.0.15" +version = "1.3.0" dependencies = [ "i18n-embed", "i18n-embed-fl", @@ -1185,7 +1142,7 @@ dependencies = [ [[package]] name = "cosmic-applet-status-area" -version = "1.0.15" +version = "1.3.0" dependencies = [ "futures", "libcosmic-yoda", @@ -1200,7 +1157,7 @@ dependencies = [ [[package]] name = "cosmic-applet-tiling" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-client-toolkit", @@ -1219,7 +1176,7 @@ dependencies = [ [[package]] name = "cosmic-applet-time" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-applets-config", "i18n-embed", @@ -1239,7 +1196,7 @@ dependencies = [ [[package]] name = "cosmic-applet-workspaces" -version = "1.0.15" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-client-toolkit", @@ -1256,7 +1213,7 @@ dependencies = [ [[package]] name = "cosmic-applets" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-app-list", "cosmic-applet-a11y", @@ -1282,7 +1239,7 @@ dependencies = [ [[package]] name = "cosmic-applets-config" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-config", "serde", @@ -1292,7 +1249,7 @@ dependencies = [ name = "cosmic-client-toolkit" version = "0.2.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cosmic-protocols", "libc", "smithay-client-toolkit", @@ -1340,22 +1297,11 @@ dependencies = [ [[package]] name = "cosmic-dbus-a11y" version = "0.1.0" +source = "git+https://github.com/pop-os/dbus-settings-bindings#eed01dd3609e90e3c8cd043656734c500956c793" dependencies = [ "zbus", ] -[[package]] -name = "cosmic-dbus-networkmanager" -version = "0.1.0" -dependencies = [ - "bitflags 2.11.1", - "derive_builder", - "jiff", - "procfs", - "zbus", - "zvariant", -] - [[package]] name = "cosmic-freedesktop-icons" version = "0.4.0" @@ -1392,7 +1338,7 @@ dependencies = [ [[package]] name = "cosmic-panel-button" -version = "1.0.15" +version = "1.3.0" dependencies = [ "cosmic-config", "libcosmic-yoda", @@ -1405,7 +1351,7 @@ dependencies = [ [[package]] name = "cosmic-panel-config" -version = "0.1.0" +version = "1.3.0" dependencies = [ "anyhow", "cosmic-config", @@ -1420,7 +1366,7 @@ dependencies = [ name = "cosmic-protocols" version = "0.2.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1510,24 +1456,6 @@ dependencies = [ "zbus", ] -[[package]] -name = "cosmic-settings-network-manager-subscription" -version = "1.0.7" -dependencies = [ - "bitflags 2.11.1", - "cosmic-dbus-networkmanager", - "futures", - "iced_futures", - "itertools", - "nm-secret-agent-manager", - "secret-service", - "secure-string", - "thiserror 2.0.18", - "tokio", - "tracing", - "zbus", -] - [[package]] name = "cosmic-settings-upower-subscription" version = "1.0.7" @@ -1545,7 +1473,7 @@ dependencies = [ name = "cosmic-text" version = "0.19.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "fontdb", "harfrust", "linebender_resource_handle", @@ -1831,37 +1759,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn", -] - [[package]] name = "derive_setters" version = "0.1.9" @@ -1893,7 +1790,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", - "subtle", ] [[package]] @@ -1923,7 +1819,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1953,7 +1849,7 @@ dependencies = [ name = "dnd" version = "0.1.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "mime 0.1.0", "raw-window-handle", "smithay-client-toolkit", @@ -1985,7 +1881,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "drm-ffi", "drm-fourcc", @@ -2461,9 +2357,9 @@ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" @@ -2616,7 +2512,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2627,7 +2523,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", ] [[package]] @@ -2664,7 +2560,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "core_maths", "read-fonts", @@ -2750,24 +2646,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "i18n-config" version = "0.4.8" @@ -2891,7 +2769,7 @@ dependencies = [ name = "iced_core" version = "0.14.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytes", "cosmic-client-toolkit", "dnd", @@ -2937,7 +2815,7 @@ dependencies = [ name = "iced_graphics" version = "0.14.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "cosmic-text", "half", @@ -3006,7 +2884,7 @@ dependencies = [ name = "iced_wgpu" version = "0.14.0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "cosmic-client-toolkit", "cryoglyph", @@ -3578,7 +3456,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "inotify-sys", "libc", ] @@ -3592,23 +3470,13 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "input" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "input-sys", "libc", "log", @@ -3657,15 +3525,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -3814,7 +3673,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "serde", ] @@ -3860,7 +3719,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "libc", ] @@ -3989,7 +3848,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "libc", "plain", "redox_syscall 0.8.1", @@ -4074,9 +3933,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "logind-zbus" @@ -4209,7 +4068,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -4289,7 +4148,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.1", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -4313,7 +4172,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -4343,28 +4202,21 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", ] -[[package]] -name = "nm-secret-agent-manager" -version = "0.1.0" -dependencies = [ - "zbus", -] - [[package]] name = "nmrs" -version = "3.1.4" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9493a0dfbe50783b53ef52ec8ddb8d1f85fd45098be8210205236ff0f43bb7b" +checksum = "33e42c05118e18f29f55eefa2fbfd98a06b0c7a1a829bdb0f328137d358c6013" dependencies = [ "async-trait", "base64", - "bitflags 2.11.1", + "bitflags 2.13.1", "futures", "futures-timer", "log", @@ -4391,7 +4243,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "fsevent-sys", "inotify", "kqueue", @@ -4409,7 +4261,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", ] [[package]] @@ -4421,20 +4273,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -4445,15 +4283,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.2.2" @@ -4480,17 +4309,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.2" @@ -4585,7 +4403,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4601,7 +4419,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", @@ -4614,7 +4432,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4626,7 +4444,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "dispatch2", "objc2 0.6.4", @@ -4638,7 +4456,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "libc", "objc2-core-foundation", ] @@ -4661,7 +4479,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "objc2-core-foundation", "objc2-core-graphics", ] @@ -4678,7 +4496,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4690,7 +4508,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", @@ -4702,7 +4520,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4714,7 +4532,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4727,7 +4545,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -5049,7 +4867,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", @@ -5186,27 +5004,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "procfs" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" -dependencies = [ - "bitflags 2.11.1", - "procfs-core", - "rustix 1.1.4", -] - -[[package]] -name = "procfs-core" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" -dependencies = [ - "bitflags 2.11.1", - "hex", -] - [[package]] name = "profiling" version = "1.0.18" @@ -5350,7 +5147,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c07d0d6d291e3a951bd847b1cd4af32fc6243d64116cf7702838c02797688b7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "libredox", ] @@ -5360,7 +5157,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", ] [[package]] @@ -5369,7 +5166,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", ] [[package]] @@ -5495,7 +5292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db09040cc89e461f1a265139777a2bde7f8d8c67c4936f700c63ce3e2904d468" dependencies = [ "base64", - "bitflags 2.11.1", + "bitflags 2.13.1", "serde", "serde_derive", "unicode-ident", @@ -5507,7 +5304,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "once_cell", "serde", "serde_derive", @@ -5582,7 +5379,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5595,7 +5392,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -5614,7 +5411,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "core_maths", "log", @@ -5690,25 +5487,6 @@ dependencies = [ "tiny-skia", ] -[[package]] -name = "secret-service" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a62d7f86047af0077255a29494136b9aaaf697c76ff70b8e49cded4e2623c14" -dependencies = [ - "aes", - "cbc", - "futures-util", - "generic-array", - "getrandom 0.2.17", - "hkdf", - "num", - "once_cell", - "serde", - "sha2", - "zbus", -] - [[package]] name = "secure-string" version = "0.3.0" @@ -5946,7 +5724,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "calloop", "calloop-wayland-source", @@ -6031,7 +5809,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.11.1", + "bitflags 2.13.1", ] [[package]] @@ -6083,12 +5861,6 @@ dependencies = [ "syn", ] -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "svg_fmt" version = "0.4.5" @@ -6650,6 +6422,7 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "upower_dbus" version = "0.3.2" +source = "git+https://github.com/pop-os/dbus-settings-bindings#eed01dd3609e90e3c8cd043656734c500956c793" dependencies = [ "serde", "serde_repr", @@ -6716,9 +6489,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -6856,7 +6629,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "hashbrown 0.15.5", "indexmap 2.14.0", "semver", @@ -6896,7 +6669,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -6908,7 +6681,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cursor-icon", "wayland-backend", ] @@ -6930,7 +6703,7 @@ version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6943,7 +6716,7 @@ version = "20250721.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6956,7 +6729,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6969,7 +6742,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6982,7 +6755,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7007,7 +6780,7 @@ version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc1846eb04c49182e04f4a099e2a830a2b745610bbc1d61246e206f29c7000a0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "downcast-rs", "rustix 1.1.4", "wayland-backend", @@ -7059,7 +6832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "cfg-if", "cfg_aliases", @@ -7091,7 +6864,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "cfg_aliases", "document-features", @@ -7151,7 +6924,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.11.1", + "bitflags 2.13.1", "block", "bytemuck", "cfg-if", @@ -7195,7 +6968,7 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "bytemuck", "js-sys", "log", @@ -7680,7 +7453,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" name = "winit" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cfg_aliases", "cursor-icon", "dpi", @@ -7705,7 +7478,7 @@ name = "winit-android" version = "0.31.0-beta.2" dependencies = [ "android-activity", - "bitflags 2.11.1", + "bitflags 2.13.1", "dpi", "ndk", "raw-window-handle", @@ -7718,7 +7491,7 @@ dependencies = [ name = "winit-appkit" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "dispatch2", "dpi", @@ -7752,7 +7525,7 @@ dependencies = [ name = "winit-core" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cursor-icon", "dpi", "keyboard-types", @@ -7765,7 +7538,7 @@ dependencies = [ name = "winit-orbital" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "dpi", "libredox", "orbclient", @@ -7780,7 +7553,7 @@ dependencies = [ name = "winit-uikit" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "block2 0.6.2", "dispatch2", "dpi", @@ -7800,7 +7573,7 @@ name = "winit-wayland" version = "0.31.0-beta.2" dependencies = [ "ahash", - "bitflags 2.11.1", + "bitflags 2.13.1", "calloop", "cursor-icon", "dpi", @@ -7825,7 +7598,7 @@ name = "winit-web" version = "0.31.0-beta.2" dependencies = [ "atomic-waker", - "bitflags 2.11.1", + "bitflags 2.13.1", "concurrent-queue", "cursor-icon", "dpi", @@ -7845,7 +7618,7 @@ dependencies = [ name = "winit-win32" version = "0.31.0-beta.2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "cursor-icon", "dpi", "raw-window-handle", @@ -7929,7 +7702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.13.1", "indexmap 2.14.0", "log", "serde", @@ -7988,7 +7761,7 @@ checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "xdg-shell-wrapper-config" -version = "0.1.0" +version = "1.3.0" dependencies = [ "serde", "wayland-protocols-wlr", @@ -8055,7 +7828,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.1", "dlib", "log", "once_cell", @@ -8135,9 +7908,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.15.0" +version = "5.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1" +checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a" dependencies = [ "async-broadcast", "async-executor", @@ -8195,9 +7968,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.15.0" +version = "5.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff" +checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8210,9 +7983,9 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.2" +version = "4.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" dependencies = [ "serde", "winnow", @@ -8424,9 +8197,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.11.0" +version = "5.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee" +checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911" dependencies = [ "endi", "enumflags2", @@ -8439,9 +8212,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.11.0" +version = "5.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda" +checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8452,9 +8225,9 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.3.1" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691" +checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7" dependencies = [ "proc-macro2", "quote", @@ -8467,10 +8240,6 @@ dependencies = [ name = "cosmic-settings-airplane-mode-subscription" version = "1.0.7" -[[patch.unused]] -name = "cosmic-settings-sound-subscription" -version = "1.0.7" - [[patch.unused]] name = "winit-x11" version = "0.31.0-beta.2" diff --git a/Cargo.toml b/Cargo.toml index 6f673cc2..ccbe504a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,13 +118,10 @@ cosmic-settings-a11y-manager-subscription = { path = "/home/lionel/Projets/COSMI cosmic-settings-accessibility-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/accessibility" } cosmic-settings-airplane-mode-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/airplane-mode" } cosmic-settings-daemon-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/settings-daemon" } -cosmic-settings-network-manager-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/network-manager" } -cosmic-settings-sound-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/sound" } cosmic-settings-upower-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/upower" } [patch."https://github.com/pop-os/cosmic-settings/"] cosmic-settings-airplane-mode-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/airplane-mode" } -cosmic-settings-network-manager-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/network-manager" } [patch."https://github.com/pop-os/cosmic-text.git"] cosmic-text = { path = "../cosmic-text" } diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index 034cfb79..a41dc80f 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -5,9 +5,7 @@ edition = "2024" license = "GPL-3.0-or-later" [dependencies] -anyhow.workspace = true async-fn-stream = "0.3" -cosmic-dbus-networkmanager = { path = "../../dbus-settings-bindings/networkmanager" } futures.workspace = true futures-util.workspace = true i18n-embed-fl.workspace = true @@ -25,13 +23,7 @@ tokio.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true tracing.workspace = true -zbus.workspace = true indexmap = "2.13.0" secure-string = "0.3.0" uuid = { version = "1.21.0", features = ["v4"] } -nmrs = "3.1.3" - - - -[dependencies.cosmic-settings-network-manager-subscription] -path = "../../cosmic-settings/subscriptions/network-manager" +nmrs = "3.4.0" diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 0b6dbe24..b5f12bfa 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -1,13 +1,7 @@ -use anyhow::Context; -use cosmic_settings_network_manager_subscription::{ - self as network_manager, NetworkManagerState, UUID, - available_wifi::{AccessPoint, NetworkType}, - current_networks::ActiveConnectionInfo, - hw_address::HwAddress, -}; use indexmap::IndexMap; use nmrs::{ - NetworkManager as NmrsManager, SettingsSummary, + ActiveConnection, ActiveConnectionState, ConnectType, ConnectivityState, EapOptions, + NetworkEvent, NetworkManager as NmrsManager, NetworkSnapshot, WifiSecurity, agent::{SecretAgent, SecretAgentCapabilities, SecretRequest, SecretResponder, SecretSetting}, }; use rustc_hash::FxHashSet; @@ -15,11 +9,13 @@ use secure_string::SecureString; use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, + fmt, + str::FromStr, sync::{Arc, LazyLock}, }; use cosmic::{ - Apply, Element, Task, app, + Element, Task, app, applet::{ menu_button, menu_control_padding, padded_control, token::subscription::{TokenRequest, TokenUpdate, activation_token_subscription}, @@ -29,7 +25,7 @@ use cosmic::{ iced::core::window, iced::{ Alignment, Length, Subscription, - platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup}, + platform_specific::shell::wayland::commands::popup::destroy_popup, }, surface, theme, widget::{ @@ -38,12 +34,12 @@ use cosmic::{ indeterminate_circular, row, scrollable, secure_input, text, text_input, toggler, }, }; -use cosmic_dbus_networkmanager::interface::enums::{ - ActiveConnectionState, DeviceState, NmConnectivityState, -}; -use futures::{StreamExt, lock::Mutex as AsyncMutex}; -use zbus::Connection; +use futures::{ + StreamExt, + channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded}, + lock::Mutex as AsyncMutex, +}; use crate::{config, fl}; @@ -64,17 +60,6 @@ enum NewConnectionState { Failure(AccessPoint), } -impl NewConnectionState { - pub fn ssid(&self) -> &str { - &match self { - Self::EnterPassword { access_point, .. } => access_point, - Self::Waiting(ap) => ap, - Self::Failure(ap) => ap, - } - .ssid - } -} - impl From for AccessPoint { fn from(connection_state: NewConnectionState) -> Self { match connection_state { @@ -87,13 +72,189 @@ impl From for AccessPoint { pub static SECURE_INPUT_WIFI: LazyLock = LazyLock::new(Id::unique); +type Uuid = Arc; +type Ssid = Arc; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NetworkType { + Open, + Password, + Eap, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DeviceState { + Unknown, + Unmanaged, + Unavailable, + Disconnected, + NeedAuth, + Activated, + Failed, + Other, +} + +impl From<&nmrs::DeviceState> for DeviceState { + fn from(state: &nmrs::DeviceState) -> Self { + match state { + nmrs::DeviceState::Unmanaged => Self::Unmanaged, + nmrs::DeviceState::Unavailable => Self::Unavailable, + nmrs::DeviceState::Disconnected => Self::Disconnected, + nmrs::DeviceState::NeedAuth => Self::NeedAuth, + nmrs::DeviceState::Activated => Self::Activated, + nmrs::DeviceState::Failed => Self::Failed, + nmrs::DeviceState::Other(_) => Self::Unknown, + _ => Self::Other, + } + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HwAddress([u8; 6]); + +impl HwAddress { + fn as_string(self) -> String { + self.0 + .iter() + .map(|byte| format!("{byte:02X}")) + .collect::>() + .join(":") + } +} + +impl FromStr for HwAddress { + type Err = (); + + fn from_str(value: &str) -> Result { + let mut bytes = [0; 6]; + let mut parts = value.split(':'); + for byte in &mut bytes { + let Some(part) = parts.next() else { + return Err(()); + }; + *byte = u8::from_str_radix(part, 16).map_err(|_| ())?; + } + if parts.next().is_some() { + return Err(()); + } + Ok(Self(bytes)) + } +} + +impl fmt::Display for HwAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.as_string()) + } +} + +fn same_access_point(left: &AccessPoint, right: &AccessPoint) -> bool { + left.ssid == right.ssid + && left.hw_address == right.hw_address + && left.interface == right.interface +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AccessPoint { + pub ssid: Ssid, + pub network_type: NetworkType, + pub hw_address: HwAddress, + pub strength: u8, + pub state: DeviceState, + pub working: bool, + pub wps_push: bool, + pub interface: Option, +} + +#[derive(Debug, Clone)] +pub enum ActiveConnectionInfo { + Wired { + name: String, + hw_address: String, + speed: u32, + ip4_address: Option, + ip6_address: Option, + }, + WiFi { + name: String, + ip4_address: Option, + ip6_address: Option, + state: ActiveConnectionState, + strength: u8, + hw_address: String, + }, + Vpn { + name: String, + ip4_address: Option, + ip6_address: Option, + }, +} + +impl ActiveConnectionInfo { + fn name(&self) -> &str { + match self { + Self::Wired { name, .. } | Self::WiFi { name, .. } | Self::Vpn { name, .. } => name, + } + } +} + +#[derive(Debug, Clone)] +pub struct NetworkManagerState { + pub wifi_enabled: bool, + pub airplane_mode: bool, + pub connectivity: ConnectivityState, + pub active_conns: Vec, + pub known_access_points: Vec, + pub wireless_access_points: Vec, +} + +impl Default for NetworkManagerState { + fn default() -> Self { + Self { + wifi_enabled: true, + airplane_mode: false, + connectivity: ConnectivityState::Unknown, + active_conns: Vec::new(), + known_access_points: Vec::new(), + wireless_access_points: Vec::new(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum DeviceType { + Wifi, +} + +#[derive(Clone, Debug)] +pub struct DeviceConnection { + pub id: String, +} + +#[derive(Clone, Debug)] +pub struct DeviceInfo { + pub interface: String, + pub device_type: DeviceType, + pub active_connection: Option<(DeviceConnection,)>, + pub known_connections: Vec, +} + +#[derive(Debug, Clone)] +pub struct AppletSnapshot { + pub state: NetworkManagerState, + pub devices: Vec, + pub known_vpns: IndexMap, + pub ssid_to_uuid: BTreeMap, Box>, + pub captive_portal_url: Option, +} + #[derive(Default, Debug, Clone)] pub struct MyNetworkState { - pub known_vpns: IndexMap, + pub known_vpns: IndexMap, pub ssid_to_uuid: BTreeMap, Box>, - pub devices: Vec>, + pub devices: Vec>, pub nm_state: NetworkManagerState, pub requested_vpn: Option, + pub pending_vpn: Option, } /// Shared, take-once handle to an `nmrs` [`SecretResponder`]. Cloned freely @@ -113,6 +274,18 @@ pub struct RequestedVpn { secret_keys: Vec, } +#[derive(Debug, Clone)] +pub struct PendingVpn { + uuid: Arc, + action: PendingVpnAction, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PendingVpnAction { + Activate, + Deactivate, +} + #[derive(Clone, Debug)] pub enum ConnectionSettings { Vpn { id: String }, @@ -148,21 +321,19 @@ struct CosmicNetworkApplet { popup: Option, // NM state - nm_sender: Option>, - nm_task: Option>, nm_state: MyNetworkState, // UI state show_visible_networks: bool, show_available_vpns: bool, new_connection: Option, - conn: Option, toggle_wifi_ctr: u128, token_tx: Option>, + secret_agent_reregister_tx: Option>, failed_known_ssids: FxHashSet>, /// When defined, displays connections for the specific device. - active_device: Option>, + active_device: Option>, } fn wifi_icon(strength: u8) -> &'static str { @@ -264,6 +435,11 @@ fn vpn_section<'a>( let is_active = nm_state.nm_state.active_conns.iter().any( |conn| matches!(conn, ActiveConnectionInfo::Vpn { name, .. } if name == id), ); + let pending_action = nm_state + .pending_vpn + .as_ref() + .filter(|pending| pending.uuid.as_ref() == uuid.as_ref()) + .map(|pending| pending.action); let mut btn_content = vec![ icon::from_name("network-vpn-symbolic") @@ -276,6 +452,9 @@ fn vpn_section<'a>( if is_active { btn_content.push(text::body(fl!("connected")).align_x(Alignment::End).into()); } + if pending_action.is_some() { + btn_content.push(indeterminate_circular().size(24.0).into()); + } let mut btn = menu_button( row::with_children(btn_content) @@ -283,7 +462,9 @@ fn vpn_section<'a>( .spacing(8), ); - btn = if is_active { + btn = if pending_action.is_some() { + btn + } else if is_active { btn.on_press(Message::DeactivateVpn(uuid.clone())) } else { btn.on_press(Message::ActivateVpn(uuid.clone())) @@ -297,7 +478,341 @@ fn vpn_section<'a>( vpn_col } +fn ip_address_elements<'a>( + ip4_address: &Option, + _ip6_address: &Option, +) -> Vec> { + let mut elements = Vec::with_capacity(1); + if let Some(addr) = ip4_address { + // Strip the subnet mask (e.g. "10.0.0.2/24" -> "10.0.0.2"); the drop-down + // only needs the address itself for glancing at the host on a local network. + let addr = addr.split('/').next().unwrap_or(addr.as_str()); + elements.push(text(format!("{}: {}", fl!("ipv4"), addr)).size(12).into()); + } + elements +} + +fn network_type(security: nmrs::SecurityFeatures) -> NetworkType { + match security.preferred_connect_type() { + ConnectType::Open | ConnectType::Owe => NetworkType::Open, + ConnectType::Eap => NetworkType::Eap, + ConnectType::Psk | ConnectType::Sae => NetworkType::Password, + _ => NetworkType::Password, + } +} + +fn wifi_security( + access_point: &AccessPoint, + identity: Option, + password: Option, +) -> WifiSecurity { + match access_point.network_type { + NetworkType::Open => WifiSecurity::Open, + NetworkType::Eap => WifiSecurity::WpaEap { + opts: EapOptions::new( + identity.unwrap_or_default(), + password + .as_ref() + .map(|password| password.unsecure().to_owned()) + .unwrap_or_default(), + ), + }, + NetworkType::Password => WifiSecurity::WpaPsk { + psk: password + .as_ref() + .map(|password| password.unsecure().to_owned()) + .unwrap_or_default(), + }, + } +} + +fn connect_access_point_task( + access_point: AccessPoint, + identity: Option, + password: Option, +) -> Task> { + cosmic::task::future(async move { + let ssid = access_point.ssid.to_string(); + let interface = access_point.interface.clone(); + let bssid = access_point.hw_address.as_string(); + let security = wifi_security(&access_point, identity, password); + match NmrsManager::new().await { + Ok(nm) => { + match nm + .connect_to_bssid(&ssid, Some(&bssid), interface.as_deref(), security) + .await + { + Ok(()) => Message::ConnectionAttemptFinished { + access_point, + success: true, + error: None, + }, + Err(e) => Message::ConnectionAttemptFinished { + access_point, + success: false, + error: Some(e.to_string()), + }, + } + } + Err(e) => Message::Error(format!("nmrs init: {e}")), + } + }) + .map(cosmic::Action::App) +} + +fn snapshot_task() -> Task { + cosmic::task::future(async move { + let nm = match NmrsManager::new().await { + Ok(nm) => nm, + Err(e) => return Message::Error(format!("nmrs init: {e}")), + }; + + match nm.snapshot().await { + Ok(snapshot) => Message::Snapshot(snapshot_to_applet(snapshot)), + Err(e) => Message::Error(format!("snapshot: {e}")), + } + }) +} + +fn network_events_task() -> Task { + cosmic::Task::stream(async_fn_stream::fn_stream(|emitter| async move { + let nm = match NmrsManager::new().await { + Ok(nm) => nm, + Err(e) => { + let _ = emitter + .emit(Message::Error(format!("nmrs init: {e}"))) + .await; + return; + } + }; + let mut events = match nm.network_events().await { + Ok(events) => events, + Err(e) => { + let _ = emitter + .emit(Message::Error(format!("network events: {e}"))) + .await; + return; + } + }; + + while let Some(event) = events.next().await { + match event { + Ok(event) => { + let _ = emitter.emit(Message::NetworkEvent(event)).await; + } + Err(e) => { + let _ = emitter + .emit(Message::Error(format!("network event: {e}"))) + .await; + } + } + } + })) +} + +fn snapshot_to_applet(snapshot: NetworkSnapshot) -> AppletSnapshot { + let summary = snapshot.applet_summary(); + let mut known_vpns = IndexMap::new(); + for vpn in summary.saved_vpns.values() { + let uuid: Uuid = Arc::from(vpn.uuid.as_str()); + let entry = match vpn.kind { + Some(nmrs::VpnKind::WireGuard) => ConnectionSettings::Wireguard { id: vpn.id.clone() }, + _ => ConnectionSettings::Vpn { id: vpn.id.clone() }, + }; + known_vpns.insert(uuid, entry); + } + + let mut ssid_to_uuid = BTreeMap::new(); + for (ssid, profiles) in &summary.known_wifi { + if let Some(profile) = profiles.first() { + ssid_to_uuid.insert( + ssid.clone().into_boxed_str(), + profile.uuid.clone().into_boxed_str(), + ); + } + } + + let active_conns = snapshot + .active_connections + .iter() + .filter_map(|conn| match conn { + ActiveConnection::Wired(wired) => Some(ActiveConnectionInfo::Wired { + name: wired.id.clone(), + hw_address: wired.hw_address.clone().unwrap_or_default(), + speed: wired.speed_mbps.unwrap_or_default(), + ip4_address: wired.ip4_address.clone(), + ip6_address: wired.ip6_address.clone(), + }), + ActiveConnection::Wifi(wifi) + if known_vpns.values().any(|connection| { + matches!( + connection, + ConnectionSettings::Vpn { id } | ConnectionSettings::Wireguard { id } + if id == &wifi.ssid + ) + }) => + { + Some(ActiveConnectionInfo::Vpn { + name: wifi.ssid.clone(), + ip4_address: wifi.ip4_address.clone(), + ip6_address: wifi.ip6_address.clone(), + }) + } + ActiveConnection::Wifi(wifi) => Some(ActiveConnectionInfo::WiFi { + name: wifi.ssid.clone(), + ip4_address: wifi.ip4_address.clone(), + ip6_address: wifi.ip6_address.clone(), + state: wifi.state, + strength: wifi.strength.unwrap_or_default(), + hw_address: wifi.bssid.clone().unwrap_or_default(), + }), + ActiveConnection::Vpn(vpn) => Some(ActiveConnectionInfo::Vpn { + name: vpn.id.clone(), + ip4_address: vpn.ip4_address.clone(), + ip6_address: vpn.ip6_address.clone(), + }), + ActiveConnection::Other(_) | _ => None, + }) + .collect(); + + let mut wireless_access_points = summary + .wifi_groups + .iter() + .filter(|group| !group.ssid.is_empty() && !group.strongest.ssid_bytes.is_empty()) + .map(|group| { + let strongest = &group.strongest; + AccessPoint { + ssid: Arc::from(group.ssid.as_str()), + network_type: network_type(strongest.security), + hw_address: HwAddress::from_str(&strongest.bssid).unwrap_or_default(), + strength: strongest.strength, + state: DeviceState::from(&strongest.device_state), + working: false, + wps_push: strongest.security.wps, + interface: Some(group.interface.clone()), + } + }) + .collect::>(); + wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength)); + + let known_access_points = summary + .wifi_groups + .iter() + .filter(|group| group.known || group.active) + .map(|group| { + let strongest = &group.strongest; + let device_state = DeviceState::from(&strongest.device_state); + AccessPoint { + ssid: Arc::from(group.ssid.as_str()), + network_type: network_type(strongest.security), + hw_address: HwAddress::from_str(&strongest.bssid).unwrap_or_default(), + strength: strongest.strength, + state: if group.active { + DeviceState::Activated + } else if matches!(device_state, DeviceState::Activated) { + DeviceState::Disconnected + } else { + device_state + }, + working: false, + wps_push: strongest.security.wps, + interface: Some(group.interface.clone()), + } + }) + .collect::>(); + + let devices = snapshot + .wifi_devices + .iter() + .map(|device| { + let known_connections = summary + .known_wifi + .iter() + .filter(|(ssid, _)| { + summary + .wifi_groups + .iter() + .any(|group| group.interface == device.interface && group.ssid == **ssid) + }) + .map(|(ssid, _)| DeviceConnection { id: ssid.clone() }) + .collect(); + DeviceInfo { + interface: device.interface.clone(), + device_type: DeviceType::Wifi, + active_connection: device + .active_ssid + .as_ref() + .map(|ssid| (DeviceConnection { id: ssid.clone() },)), + known_connections, + } + }) + .collect(); + + AppletSnapshot { + state: NetworkManagerState { + wifi_enabled: snapshot.wifi.enabled, + airplane_mode: summary.airplane_mode.is_airplane_mode(), + connectivity: summary.connectivity.state, + active_conns, + known_access_points, + wireless_access_points, + }, + devices, + known_vpns, + ssid_to_uuid, + captive_portal_url: summary.connectivity.captive_portal_url.clone(), + } +} + impl CosmicNetworkApplet { + fn apply_snapshot(&mut self, snapshot: AppletSnapshot) { + let previous_connectivity = self.nm_state.nm_state.connectivity; + self.nm_state.devices = snapshot.devices.into_iter().map(Arc::new).collect(); + self.nm_state.known_vpns = snapshot.known_vpns; + self.nm_state.ssid_to_uuid = snapshot.ssid_to_uuid; + self.update_nm_state(snapshot.state); + self.clear_completed_pending_vpn(); + + if !previous_connectivity.is_captive() && self.nm_state.nm_state.connectivity.is_captive() { + let mut browser = std::process::Command::new("xdg-open"); + browser.arg( + snapshot + .captive_portal_url + .as_deref() + .unwrap_or("http://204.pop-os.org/"), + ); + tokio::spawn(cosmic::process::spawn(browser)); + } + } + + fn clear_completed_pending_vpn(&mut self) { + let Some(pending) = self.nm_state.pending_vpn.as_ref() else { + return; + }; + let Some(connection) = self.nm_state.known_vpns.get(&pending.uuid) else { + self.nm_state.pending_vpn = None; + self.update_icon_name(); + return; + }; + let id = match connection { + ConnectionSettings::Vpn { id } | ConnectionSettings::Wireguard { id } => id, + }; + let is_active = self + .nm_state + .nm_state + .active_conns + .iter() + .any(|conn| matches!(conn, ActiveConnectionInfo::Vpn { name, .. } if name == id)); + let completed = match pending.action { + PendingVpnAction::Activate => is_active, + PendingVpnAction::Deactivate => !is_active, + }; + if completed { + self.nm_state.pending_vpn = None; + self.update_icon_name(); + } + } + fn update_nm_state(&mut self, mut new_state: NetworkManagerState) { self.update_togglers(&new_state); // check for failed conns that can be reset @@ -307,7 +822,7 @@ impl CosmicNetworkApplet { }; if matches!(state, ActiveConnectionState::Activated) { - self.failed_known_ssids.remove(new_s.name().as_str()); + self.failed_known_ssids.remove(new_s.name()); continue; } if matches!( @@ -334,6 +849,22 @@ impl CosmicNetworkApplet { } fn update_icon_name(&mut self) { + if self + .nm_state + .pending_vpn + .as_ref() + .is_some_and(|pending| pending.action == PendingVpnAction::Activate) + || self + .nm_state + .nm_state + .active_conns + .iter() + .any(|conn| matches!(conn, ActiveConnectionInfo::Vpn { .. })) + { + self.icon_name = "network-vpn-symbolic".to_string(); + return; + } + self.icon_name = self .nm_state .nm_state @@ -346,12 +877,7 @@ impl CosmicNetworkApplet { "network-wired-disconnected-symbolic", ActiveConnectionInfo::WiFi { strength, .. }, ) => wifi_icon(*strength), - (_, ActiveConnectionInfo::Wired { .. }) - if icon_name != "network-vpn-symbolic" => - { - "network-wired-symbolic" - } - (_, ActiveConnectionInfo::Vpn { .. }) => "network-vpn-symbolic", + (_, ActiveConnectionInfo::Wired { .. }) => "network-wired-symbolic", _ => icon_name, }, ) @@ -388,20 +914,30 @@ impl CosmicNetworkApplet { fn connect_vpn(&mut self, uuid: Arc) -> Task> { cosmic::task::future(async move { - match NmrsManager::new().await { - Ok(nm) => match nm.connect_vpn_by_uuid(&uuid).await { - Ok(()) => Message::Refresh, - Err(e) => Message::Error(format!("activate VPN {uuid}: {e}")), - }, - Err(e) => Message::Error(format!("nmrs init: {e}")), + let error = match NmrsManager::new().await { + Ok(nm) => nm + .connect_vpn_by_uuid(&uuid) + .await + .err() + .map(|e| format!("activate VPN {uuid}: {e}")), + Err(e) => Some(format!("nmrs init: {e}")), + }; + Message::VpnOperationFinished { + uuid, + action: PendingVpnAction::Activate, + error, } }) + .map(cosmic::Action::App) } } /// Registers an `nmrs` secret agent on the system bus and yields its /// requests + cancellations as [`NmAgentEvent`] for the applet to handle. -fn secret_agent_task(identifier: String) -> Task { +fn secret_agent_task( + identifier: String, + mut reregister_requests: UnboundedReceiver<()>, +) -> Task { cosmic::Task::stream(async_fn_stream::fn_stream(move |emitter| async move { let registration = SecretAgent::builder() .with_identifier(identifier) @@ -433,6 +969,11 @@ fn secret_agent_task(identifier: String) -> Task { } None => break, }, + Some(()) = reregister_requests.next() => { + if let Err(e) = handle.reregister().await { + tracing::warn!("failed to re-register secret agent: {e}"); + } + }, } } @@ -490,32 +1031,35 @@ pub(crate) enum Message { Surface(surface::Action), ActivateVpn(Arc), // UUID of VPN to activate DeactivateVpn(Arc), // UUID of VPN to deactivate - ToggleVpnList, // Show/hide available VPNs + VpnOperationFinished { + uuid: Arc, + action: PendingVpnAction, + error: Option, + }, + ToggleVpnList, // Show/hide available VPNs /// An update from the secret agent SecretAgent(NmAgentEvent), /// Connect to a WiFi network access point. - Connect(network_manager::SSID, HwAddress), + Connect(Ssid, HwAddress), /// Connect with a password ConnectWithPassword, - KnownConnections(IndexMap), - /// Settings for known connections. - ConnectionSettings(BTreeMap, Box>), /// Disconnect from an access point. - Disconnect(network_manager::SSID, HwAddress), + Disconnect(Ssid, HwAddress), + ConnectionAttemptFinished { + access_point: AccessPoint, + success: bool, + error: Option, + }, /// An error occurred. Error(String), /// Identity update from the dialog IdentityUpdate(String), - /// An update from the network manager daemon - NetworkManager(network_manager::Event), - /// Successfully connected to the system dbus. - NetworkManagerConnect(zbus::Connection), + /// An update from NetworkManager. + NetworkEvent(NetworkEvent), /// Update the password from the dialog PasswordUpdate(SecureString), - /// Update NetworkManagerState - UpdateState(NetworkManagerState), - /// Update the devices lists - UpdateDevices(Vec), + /// Update applet state from NetworkManager. + Snapshot(AppletSnapshot), /// Toggle WiFi access WiFiEnable(bool), /// Refresh state @@ -525,176 +1069,7 @@ pub(crate) enum Message { VPNPasswordUpdate(SecureString), CancelVPNConnection, /// Selects a device to display connections from - SelectDevice(Option>), -} - -fn connection_settings(conn: zbus::Connection) -> Task { - let settings = async move { - let settings = network_manager::dbus::settings::NetworkManagerSettings::new(&conn).await?; - - _ = settings.load_connections(&[]).await; - - let settings = settings - // Get a list of known connections. - .list_connections() - .await? - // Prepare for wrapping in a concurrent stream. - .into_iter() - .map(|conn| async move { conn }) - // Create a concurrent stream for each connection. - .apply(futures::stream::FuturesOrdered::from_iter) - // Concurrently fetch settings for each connection. - .filter_map(|conn| async move { - conn.get_settings() - .await - .map(network_manager::Settings::new) - .ok() - }) - // Reduce the settings list into a SSID->UUID map. - .fold(BTreeMap::new(), |mut set, settings| async move { - if let Some(ref wifi) = settings.wifi - && let Some(ssid) = wifi - .ssid - .clone() - .and_then(|ssid| String::from_utf8(ssid).ok()) - && let Some(ref connection) = settings.connection - && let Some(uuid) = connection.uuid.clone() - { - set.insert(ssid.into(), uuid.into()); - return set; - } - - set - }) - .await; - - Ok::<_, zbus::Error>(settings) - }; - - cosmic::task::future(async move { - settings - .await - .context("failed to get connection settings") - .map_or_else( - |why| Message::Error(why.to_string()), - Message::ConnectionSettings, - ) - }) -} - -pub fn update_state(conn: zbus::Connection) -> Task { - cosmic::task::future(async move { - match NetworkManagerState::new(&conn).await { - Ok(state) => Message::UpdateState(state), - Err(why) => Message::Error(why.to_string()), - } - }) -} - -pub fn update_devices(conn: zbus::Connection) -> Task { - cosmic::task::future(async move { - let filter = - |device_type| matches!(device_type, network_manager::devices::DeviceType::Wifi); - match network_manager::devices::list(&conn, filter).await { - Ok(devices) => Message::UpdateDevices(devices), - Err(why) => Message::Error(why.to_string()), - } - }) -} - -impl CosmicNetworkApplet { - fn connect(&mut self, conn: zbus::Connection) -> Task { - if self.nm_task.is_none() { - let popup = self.popup; - let (canceller, task) = crate::utils::forward_event_loop(move |emitter| async move { - let (tx, mut rx) = futures::channel::mpsc::channel(1); - - if popup.is_some() { - let watchers = std::pin::pin!(async move { - futures::join!( - network_manager::watch(conn.clone(), tx.clone()), - network_manager::active_conns::watch(conn.clone(), tx.clone(),), - network_manager::wireless_enabled::watch(conn.clone(), tx.clone()), - network_manager::watch_connections_changed(conn, tx,) - ); - }); - let forwarder = std::pin::pin!(async move { - while let Some(message) = rx.next().await { - _ = emitter.emit(Message::NetworkManager(message)).await; - } - }); - - futures::future::select(watchers, forwarder).await; - } else { - let watchers = std::pin::pin!(async move { - futures::join!( - network_manager::watch(conn.clone(), tx.clone()), - network_manager::active_conns::watch(conn.clone(), tx.clone(),), - network_manager::wireless_enabled::watch(conn.clone(), tx.clone()), - ); - }); - let forwarder = std::pin::pin!(async move { - while let Some(message) = rx.next().await { - _ = emitter.emit(Message::NetworkManager(message)).await; - } - }); - - futures::future::select(watchers, forwarder).await; - }; - }); - - self.nm_task = Some(canceller); - return task.map(Message::from); - } - - Task::none() - } -} - -fn load_vpns(_conn: zbus::Connection) -> Task { - cosmic::task::future(async move { - let nm = match NmrsManager::new().await { - Ok(nm) => nm, - Err(e) => return Message::Error(format!("nmrs init: {e}")), - }; - - let saved = match nm.list_saved_connections().await { - Ok(saved) => saved, - Err(e) => return Message::Error(format!("list saved connections: {e}")), - }; - - let mut map: IndexMap = IndexMap::new(); - for c in saved { - // Skip in-memory-only NM connections — assumed connections that NM - // auto-generated from externally-managed interfaces (e.g. one - // brought up by wg-quick@wg0.service) report unsaved=true and - // evaporate on deactivate, leaving the applet's toggle dead. - if c.unsaved { - continue; - } - let uuid: UUID = Arc::from(c.uuid.as_str()); - let entry = match c.summary { - SettingsSummary::WireGuard { .. } => ConnectionSettings::Wireguard { id: c.id }, - SettingsSummary::Vpn { .. } => ConnectionSettings::Vpn { id: c.id }, - _ => continue, - }; - map.insert(uuid, entry); - } - - Message::KnownConnections(map) - }) -} - -fn system_conn() -> Task { - cosmic::Task::future(async move { - zbus::Connection::system() - .await - .context("failed to create system dbus connection") - .map_or_else( - |why| Message::Error(why.to_string()), - Message::NetworkManagerConnect, - ) - }) + SelectDevice(Option>), } impl cosmic::Application for CosmicNetworkApplet { @@ -711,7 +1086,23 @@ impl cosmic::Application for CosmicNetworkApplet { ..Default::default() }; - (applet, system_conn().map(cosmic::Action::App)) + let uuid = uuid::Uuid::new_v4().to_string().replace("-", "_"); + let my_id = + format!("com.system76.CosmicSettings.Applet._{uuid}.NetworkManager.SecretAgent",); + let (secret_agent_reregister_tx, secret_agent_reregister_rx) = unbounded(); + + ( + Self { + secret_agent_reregister_tx: Some(secret_agent_reregister_tx), + ..applet + }, + Task::batch(vec![ + snapshot_task(), + network_events_task(), + secret_agent_task(my_id, secret_agent_reregister_rx).map(Message::SecretAgent), + ]) + .map(cosmic::Action::App), + ) } fn core(&self) -> &cosmic::app::Core { @@ -730,33 +1121,28 @@ impl cosmic::Application for CosmicNetworkApplet { return destroy_popup(p); } else { let mut tasks = Vec::with_capacity(2); - if let Some(conn) = self.conn.clone() { - tasks.push(update_state(conn.clone())); - tasks.push(update_devices(conn.clone())); - tasks.push(load_vpns(conn)); - let uuid = uuid::Uuid::new_v4().to_string().replace("-", "_"); + tasks.push(snapshot_task().map(cosmic::Action::App)); + tasks.push(cosmic::surface::surface_task( + cosmic::surface::action::app_popup( + |_| Default::default(), + |app: &mut Self| { + let new_id = window::Id::unique(); + app.popup.replace(new_id); - let my_id = format!( - "com.system76.CosmicSettings.Applet._{uuid}.NetworkManager.SecretAgent", - ); - tasks.push(secret_agent_task(my_id).map(Message::SecretAgent)); - } - // TODO request update of state maybe - let new_id = window::Id::unique(); - self.popup.replace(new_id); + let popup_settings = app.core.applet.get_popup_settings( + app.core.main_window_id().unwrap(), + new_id, + None, + None, + None, + ); + popup_settings + }, + None, + ), + )); - let popup_settings = self.core.applet.get_popup_settings( - self.core.main_window_id().unwrap(), - new_id, - None, - None, - None, - ); - - tasks.push(system_conn()); - tasks.push(get_popup(popup_settings)); - - return Task::batch(tasks).map(cosmic::Action::App); + return Task::batch(tasks); } } Message::ToggleAirplaneMode(enabled) => { @@ -777,45 +1163,20 @@ impl cosmic::Application for CosmicNetworkApplet { .map(cosmic::Action::App); } Message::SelectWirelessAccessPoint(access_point) => { - let Some(tx) = self.nm_sender.as_ref() else { - return Task::none(); - }; - if matches!(access_point.network_type, NetworkType::Open) { - if let Err(err) = - tx.unbounded_send(network_manager::Request::SelectAccessPoint( - access_point.ssid.clone(), - access_point.network_type, - None, - self.active_device.as_ref().map(|d| d.interface.clone()), - )) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); - } - self.new_connection = Some(NewConnectionState::Waiting(access_point)); + self.new_connection = Some(NewConnectionState::Waiting(access_point.clone())); + return connect_access_point_task(access_point, None, None); } else { - if self + let known = self .nm_state .nm_state .known_access_points - .contains(&access_point) - && let Err(err) = - tx.unbounded_send(network_manager::Request::SelectAccessPoint( - access_point.ssid.clone(), - access_point.network_type, - None, - self.active_device.as_ref().map(|d| d.interface.clone()), - )) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + .iter() + .any(|known| same_access_point(known, &access_point)); + if known { + self.new_connection = + Some(NewConnectionState::Waiting(access_point.clone())); + return connect_access_point_task(access_point, None, None); } self.new_connection = Some(NewConnectionState::EnterPassword { access_point, @@ -850,11 +1211,6 @@ impl cosmic::Application for CosmicNetworkApplet { Message::CloseRequested(id) => { if Some(id) == self.popup { self.popup = None; - if let Some(cancel) = self.nm_task.take() { - _ = cancel.send(()); - } - - return system_conn().map(cosmic::Action::App); } } Message::OpenSettings => { @@ -934,7 +1290,7 @@ impl cosmic::Application for CosmicNetworkApplet { } }) .map(cosmic::Action::App); - let reconnect_task = self.update(Message::SelectWirelessAccessPoint(ap)); + let reconnect_task = connect_access_point_task(ap, None, None); return Task::batch(vec![forget_task, reconnect_task]); } Message::Surface(a) => { @@ -943,59 +1299,75 @@ impl cosmic::Application for CosmicNetworkApplet { )); } Message::ActivateVpn(uuid) => { - return self.connect_vpn(uuid.clone()); + self.nm_state.pending_vpn = Some(PendingVpn { + uuid: uuid.clone(), + action: PendingVpnAction::Activate, + }); + self.update_icon_name(); + return Task::batch(vec![ + snapshot_task().map(cosmic::Action::App), + self.connect_vpn(uuid.clone()), + ]); } Message::DeactivateVpn(uuid) => { - return cosmic::task::future(async move { - match NmrsManager::new().await { - Ok(nm) => match nm.disconnect_vpn_by_uuid(&uuid).await { - Ok(()) => Message::Refresh, - Err(e) => Message::Error(format!("disconnect VPN {uuid}: {e}")), - }, - Err(e) => Message::Error(format!("nmrs init: {e}")), + self.nm_state.pending_vpn = Some(PendingVpn { + uuid: uuid.clone(), + action: PendingVpnAction::Deactivate, + }); + self.update_icon_name(); + let disconnect_task = cosmic::task::future(async move { + let error = match NmrsManager::new().await { + Ok(nm) => nm + .disconnect_vpn_by_uuid(&uuid) + .await + .err() + .map(|e| format!("disconnect VPN {uuid}: {e}")), + Err(e) => Some(format!("nmrs init: {e}")), + }; + Message::VpnOperationFinished { + uuid, + action: PendingVpnAction::Deactivate, + error, } }) .map(cosmic::Action::App); + return Task::batch(vec![ + snapshot_task().map(cosmic::Action::App), + disconnect_task, + ]); + } + Message::VpnOperationFinished { + uuid, + action, + error, + } => { + if self.nm_state.pending_vpn.as_ref().is_some_and(|pending| { + pending.uuid.as_ref() == uuid.as_ref() && pending.action == action + }) { + self.nm_state.pending_vpn = None; + self.update_icon_name(); + } + if let Some(error) = error { + tracing::error!("{error}"); + } + return snapshot_task().map(cosmic::Action::App); } Message::ToggleVpnList => { self.show_available_vpns = !self.show_available_vpns; } Message::Connect(ssid, hw_address) => { - let mut network_type = NetworkType::Open; - let tx = if let Some(tx) = self.nm_sender.as_ref() { - if let Some(ap) = self - .nm_state - .nm_state - .known_access_points - .iter_mut() - .find(|c| c.ssid == ssid && c.hw_address == hw_address) - { - network_type = ap.network_type; - ap.working = true; - } - tx - } else { - return Task::none(); - }; - if let Err(err) = tx.unbounded_send(network_manager::Request::SelectAccessPoint( - ssid, - network_type, - None, - self.active_device.as_ref().map(|d| d.interface.clone()), - )) { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + if let Some(ap) = self + .nm_state + .nm_state + .known_access_points + .iter_mut() + .find(|c| c.ssid == ssid && c.hw_address == hw_address) + { + ap.working = true; + return connect_access_point_task(ap.clone(), None, None); } } Message::ConnectWithPassword => { - // save password - let Some(tx) = self.nm_sender.as_ref() else { - return Task::none(); - }; - if let Some(NewConnectionState::EnterPassword { password, access_point, @@ -1003,55 +1375,44 @@ impl cosmic::Application for CosmicNetworkApplet { .. }) = self.new_connection.take() { - let is_enterprise: bool = matches!(access_point.network_type, NetworkType::EAP); - - if let Err(err) = tx.unbounded_send(network_manager::Request::Authenticate { - ssid: access_point.ssid.to_string(), - identity: is_enterprise.then(|| identity.clone()), - password, - secret_tx: None, - interface: self.active_device.as_ref().map(|d| d.interface.clone()), - }) { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - tracing::error!("Failed to authenticate with network manager"); - } self.new_connection - .replace(NewConnectionState::Waiting(access_point)); + .replace(NewConnectionState::Waiting(access_point.clone())); + return connect_access_point_task(access_point, Some(identity), Some(password)); } } - Message::ConnectionSettings(btree_map) => { - self.nm_state.ssid_to_uuid = btree_map; - } Message::Disconnect(ssid, hw_address) => { self.new_connection = None; - let tx = if let Some(tx) = self.nm_sender.as_ref() { - if let Some(ActiveConnectionInfo::WiFi { state, .. }) = - self.nm_state.nm_state.active_conns.iter_mut().find(|c| { - let c_hw_address = match c { - ActiveConnectionInfo::Wired { hw_address, .. } - | ActiveConnectionInfo::WiFi { hw_address, .. } => { - HwAddress::from_str(hw_address).unwrap() - } - ActiveConnectionInfo::Vpn { .. } => HwAddress::default(), - }; - c.name().as_str() == ssid.as_ref() && c_hw_address == hw_address - }) - { - *state = ActiveConnectionState::Deactivating; - } - tx - } else { - return Task::none(); - }; - if let Err(err) = tx.unbounded_send(network_manager::Request::Disconnect(ssid)) { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + let interface = self + .nm_state + .nm_state + .known_access_points + .iter() + .find(|ap| ap.ssid == ssid && ap.hw_address == hw_address) + .and_then(|ap| ap.interface.clone()); + if let Some(ActiveConnectionInfo::WiFi { state, .. }) = + self.nm_state.nm_state.active_conns.iter_mut().find(|c| { + let c_hw_address = match c { + ActiveConnectionInfo::Wired { hw_address, .. } + | ActiveConnectionInfo::WiFi { hw_address, .. } => { + HwAddress::from_str(hw_address).unwrap_or_default() + } + ActiveConnectionInfo::Vpn { .. } => HwAddress::default(), + }; + c.name() == ssid.as_ref() && c_hw_address == hw_address + }) + { + *state = ActiveConnectionState::Deactivating; } + return cosmic::task::future(async move { + match NmrsManager::new().await { + Ok(nm) => match nm.disconnect(interface.as_deref()).await { + Ok(()) => Message::Refresh, + Err(e) => Message::Error(format!("disconnect {ssid}: {e}")), + }, + Err(e) => Message::Error(format!("nmrs init: {e}")), + } + }) + .map(cosmic::Action::App); } Message::Error(error) => { tracing::error!("error: {error:?}") @@ -1063,132 +1424,37 @@ impl cosmic::Application for CosmicNetworkApplet { *identity = new_identity; } } - Message::NetworkManager(event) => match event { - network_manager::Event::Init { - conn, - sender, - state, - } => { - self.nm_sender = Some(sender); - self.update_nm_state(state); - self.conn = Some(conn); - } - network_manager::Event::WiFiEnabled(_) - | network_manager::Event::WirelessAccessPoints - | network_manager::Event::ActiveConns => { - if let Some(conn) = self.conn.clone() { - return Task::future(async move { - let conn = conn.clone(); - NetworkManagerState::new(&conn).await - }) - .map(|res| match res { - Ok(s) => Message::UpdateState(s), - Err(err) => Message::Error(err.to_string()), - }) - .map(cosmic::Action::App); + Message::ConnectionAttemptFinished { + access_point, + success, + error, + } => { + if success { + self.failed_known_ssids.remove(access_point.ssid.as_ref()); + self.new_connection = None; + self.show_visible_networks = false; + } else { + if let Some(error) = error { + tracing::warn!("connect {} failed: {error}", access_point.ssid); } + self.failed_known_ssids.insert(access_point.ssid.clone()); + self.new_connection = Some(NewConnectionState::Failure(access_point)); } - network_manager::Event::RequestResponse { - mut state, - success, - req, - } => { - if let network_manager::Request::SelectAccessPoint( - ssid, - _hw_address, - _network_type, - _secret_tx, - ) = &req - { - let conn_match = self - .new_connection - .as_ref() - .is_some_and(|c| c.ssid() == ssid.as_ref() ); - - if conn_match && success { - if let Some(ActiveConnectionInfo::WiFi { state, .. }) = state - .active_conns - .iter_mut() - .find(|ap| ap.name().as_str() == ssid.as_ref()) - { - *state = ActiveConnectionState::Activated; - } - self.failed_known_ssids.remove(ssid); - self.new_connection = None; - self.show_visible_networks = false; - } else if !matches!( - &self.new_connection, - Some(NewConnectionState::EnterPassword { .. }) - ) && !success { - self.failed_known_ssids.insert(ssid.clone()); + return snapshot_task().map(cosmic::Action::App); + } + Message::NetworkEvent(event) => { + if matches!(event, NetworkEvent::NetworkManagerRestarted) { + tracing::debug!( + "NetworkManager restarted; refreshing network snapshot and secret agent" + ); + if let Some(mut tx) = self.secret_agent_reregister_tx.clone() { + if let Err(e) = tx.unbounded_send(()) { + tracing::warn!("secret agent re-registration task stopped: {e}"); + self.secret_agent_reregister_tx = None; } - } else if let network_manager::Request::Authenticate { - ssid, - identity: _, - password: _, - secret_tx: _, - interface: _, - } = &req - { - if let Some(NewConnectionState::Waiting(access_point)) = - self.new_connection.as_ref() - { - if !success - && ssid.as_str() == access_point.ssid.as_ref() - { - self.new_connection = - Some(NewConnectionState::Failure(access_point.clone())); - } else { - self.show_visible_networks = false; - } - } else if let Some(NewConnectionState::EnterPassword { access_point, .. }) = - self.new_connection.as_ref() - && success - && ssid.as_str() == access_point.ssid.as_ref() - { - self.new_connection = None; - self.show_visible_networks = false; - } - } else if self - .new_connection - .as_ref() - .map(NewConnectionState::ssid).is_some_and(|ssid| { - state.active_conns.iter().any(|c| - matches!(c, ActiveConnectionInfo::WiFi { name, state: ActiveConnectionState::Activated, .. } if ssid == name) - ) - }) { - self.new_connection = None; - self.show_visible_networks = false; - } - - if !matches!(req, network_manager::Request::Reload) - && matches!(state.connectivity, NmConnectivityState::Portal) - { - let mut browser = std::process::Command::new("xdg-open"); - browser.arg("http://204.pop-os.org/"); - - tokio::spawn(cosmic::process::spawn(browser)); - } - - self.update_nm_state(state); - } - - cosmic_settings_network_manager_subscription::Event::Devices => { - if let Some(conn) = self.conn.clone() { - return update_devices(conn).map(cosmic::Action::App); } } - cosmic_settings_network_manager_subscription::Event::WiFiCredentials { - ssid: _, - password: _, - security_type: _, - } => {} - }, - Message::NetworkManagerConnect(connection) => { - return cosmic::task::batch(vec![ - self.connect(connection.clone()), - connection_settings(connection), - ]); + return snapshot_task().map(cosmic::Action::App); } Message::PasswordUpdate(entered_pw) => { if let Some(NewConnectionState::EnterPassword { password, .. }) = @@ -1197,11 +1463,8 @@ impl cosmic::Application for CosmicNetworkApplet { *password = entered_pw; } } - Message::UpdateState(network_manager_state) => { - self.update_nm_state(network_manager_state); - } - Message::UpdateDevices(device_infos) => { - self.nm_state.devices = device_infos.into_iter().map(Arc::new).collect(); + Message::Snapshot(snapshot) => { + self.apply_snapshot(snapshot); } Message::WiFiEnable(enable) => { self.nm_state.nm_state.wifi_enabled = enable; @@ -1291,18 +1554,8 @@ impl cosmic::Application for CosmicNetworkApplet { tracing::error!("Error from secret agent: {error}"); } }, - Message::KnownConnections(index_map) => { - self.nm_state.known_vpns = index_map; - } Message::Refresh => { - if let Some(conn) = self.conn.clone() { - return Task::batch(vec![ - update_state(conn.clone()), - update_devices(conn.clone()), - load_vpns(conn), - ]) - .map(cosmic::Action::App); - } + return snapshot_task().map(cosmic::Action::App); } Message::ToggleVPNPasswordVisibility => { if let Some(requested_vpn) = self.nm_state.requested_vpn.as_mut() { @@ -1378,16 +1631,20 @@ impl cosmic::Application for CosmicNetworkApplet { let mut known_wifi = Vec::new(); for conn in &self.nm_state.nm_state.active_conns { match conn { - ActiveConnectionInfo::Vpn { name, ip_addresses } => { + ActiveConnectionInfo::Vpn { + name, + ip4_address, + ip6_address, + } => { if self.active_device.as_ref().is_some_and(|d| { d.active_connection.as_ref().is_none_or(|a| a.0.id != *name) }) { continue; } - let mut ipv4 = Vec::with_capacity(ip_addresses.len() + 1); - ipv4.push(text::body(name).into()); - for addr in ip_addresses { - ipv4.push(text::caption(format!("{}: {}", fl!("ipv4"), addr)).into()); + let mut info_col = Vec::with_capacity(3); + info_col.push(text::body(name).into()); + for elem in ip_address_elements(ip4_address, ip6_address) { + info_col.push(elem); } vpn_ethernet_col = vpn_ethernet_col.push( column::with_capacity::(2) @@ -1395,13 +1652,13 @@ impl cosmic::Application for CosmicNetworkApplet { row::with_children([ Element::from( icon::icon( - icon::from_name(self.icon_name.clone()) + icon::from_name("network-vpn-symbolic") .symbolic(true) .into(), ) .size(40), ), - column::with_children(ipv4).into(), + column::with_children(info_col).into(), text::body(fl!("connected")) .width(Length::Fill) .align_x(Alignment::End) @@ -1421,18 +1678,17 @@ impl cosmic::Application for CosmicNetworkApplet { name, hw_address: _, speed, - ip_addresses, + ip4_address, + ip6_address, } => { if self.active_device.as_ref().is_some_and(|d| { d.active_connection.as_ref().is_none_or(|a| a.0.id != *name) }) { continue; } - let mut ipv4 = Vec::with_capacity(ip_addresses.len() + 1); - ipv4.push(text::body(name).into()); - for addr in ip_addresses { - ipv4.push(text(format!("{}: {}", fl!("ipv4"), addr)).size(12).into()); - } + let mut info_col = Vec::with_capacity(3); + info_col.push(text::body(name).into()); + info_col.extend(ip_address_elements(ip4_address, ip6_address)); let mut right_column = vec![text::body(fl!("connected")).into()]; @@ -1464,13 +1720,13 @@ impl cosmic::Application for CosmicNetworkApplet { row::with_children([ Element::from( icon::icon( - icon::from_name(self.icon_name.clone()) + icon::from_name("network-wired-symbolic") .symbolic(true) .into(), ) .size(40), ), - column::with_children(ipv4).into(), + column::with_children(info_col).into(), column::with_children(right_column) .width(Length::Fill) .align_x(Alignment::End) @@ -1488,7 +1744,8 @@ impl cosmic::Application for CosmicNetworkApplet { } ActiveConnectionInfo::WiFi { name, - ip_addresses, + ip4_address, + ip6_address, state, strength, hw_address, @@ -1498,10 +1755,7 @@ impl cosmic::Application for CosmicNetworkApplet { }) { continue; } - let mut ipv4 = Vec::with_capacity(ip_addresses.len()); - for addr in ip_addresses { - ipv4.push(text(format!("{}: {}", fl!("ipv4"), addr)).size(12).into()); - } + let ip_elements = ip_address_elements(ip4_address, ip6_address); let mut btn_content = vec![ icon::from_name(wifi_icon(*strength)) .size(24) @@ -1509,7 +1763,7 @@ impl cosmic::Application for CosmicNetworkApplet { .into(), column::with_children([ text::body(name).into(), - column::with_children(ipv4).into(), + column::with_children(ip_elements).into(), ]) .width(Length::Fill) .into(), @@ -1534,7 +1788,7 @@ impl cosmic::Application for CosmicNetworkApplet { .icon_size(16) .on_press(Message::ResetFailedKnownSsid( name.clone(), - HwAddress::from_str(hw_address).unwrap(), + HwAddress::from_str(hw_address).unwrap_or_default(), )) .into(), ); @@ -1549,7 +1803,7 @@ impl cosmic::Application for CosmicNetworkApplet { ) .on_press(Message::Disconnect( Arc::from(name.as_str()), - HwAddress::from_str(hw_address).unwrap(), + HwAddress::from_str(hw_address).unwrap_or_default(), )), )]) .align_x(Alignment::Center), @@ -1662,7 +1916,7 @@ impl cosmic::Application for CosmicNetworkApplet { .nm_state .devices .iter() - .filter(|d| matches!(d.device_type, network_manager::devices::DeviceType::Wifi)) + .filter(|d| matches!(d.device_type, DeviceType::Wifi)) .collect::>(); if wireless_hw_devices.len() > 1 && self.active_device.is_none() { @@ -1706,6 +1960,9 @@ impl cosmic::Application for CosmicNetworkApplet { } for known in &self.nm_state.nm_state.known_access_points { + if matches!(known.state, DeviceState::Activated) { + continue; + } if let Some(active_device) = self.active_device.as_ref() && active_device .known_connections @@ -1749,7 +2006,7 @@ impl cosmic::Application for CosmicNetworkApplet { .icon_size(16) .on_press(Message::ResetFailedKnownSsid( known.ssid.to_string(), - known.hw_address, + known.hw_address.clone(), )) .into(), ); @@ -1761,6 +2018,8 @@ impl cosmic::Application for CosmicNetworkApplet { .spacing(8), ); btn = match known.state { + // Activated entries are skipped above (shown in the active + // connections section instead), so no Disconnect arm is needed here. DeviceState::Failed | DeviceState::Unknown | DeviceState::Unmanaged @@ -1768,9 +2027,6 @@ impl cosmic::Application for CosmicNetworkApplet { | DeviceState::NeedAuth => { btn.on_press(Message::Connect(known.ssid.clone(), known.hw_address)) } - DeviceState::Activated => { - btn.on_press(Message::Disconnect(known.ssid.clone(), known.hw_address)) - } _ => btn, }; known_wifi.push(Element::from( @@ -1838,7 +2094,7 @@ impl cosmic::Application for CosmicNetworkApplet { ); content = content.push(id); - let is_enterprise = matches!(access_point.network_type, NetworkType::EAP); + let is_enterprise = matches!(access_point.network_type, NetworkType::Eap); let enter_password_col = cosmic::widget::column::with_capacity(4) .push_maybe(is_enterprise.then(|| text::body(fl!("identity")))) .push_maybe(is_enterprise.then(|| { @@ -2018,7 +2274,9 @@ impl cosmic::Application for CosmicNetworkApplet { fn active_conn_hw_address(conn: &ActiveConnectionInfo) -> HwAddress { match conn { ActiveConnectionInfo::Wired { hw_address, .. } - | ActiveConnectionInfo::WiFi { hw_address, .. } => HwAddress::from_str(hw_address).unwrap(), + | ActiveConnectionInfo::WiFi { hw_address, .. } => { + HwAddress::from_str(hw_address).unwrap_or_default() + } ActiveConnectionInfo::Vpn { .. } => HwAddress::default(), } } diff --git a/cosmic-applet-network/src/lib.rs b/cosmic-applet-network/src/lib.rs index 7d5414a5..f1ce1c6e 100644 --- a/cosmic-applet-network/src/lib.rs +++ b/cosmic-applet-network/src/lib.rs @@ -3,7 +3,6 @@ mod app; mod config; mod localize; -mod utils; use crate::localize::localize; diff --git a/cosmic-applet-network/src/utils.rs b/cosmic-applet-network/src/utils.rs deleted file mode 100644 index f802010f..00000000 --- a/cosmic-applet-network/src/utils.rs +++ /dev/null @@ -1,18 +0,0 @@ -use futures_util::future::select; - -/// Spawn a background tasks and forward its messages -pub fn forward_event_loop + Send + 'static>( - event_loop: impl FnOnce(async_fn_stream::StreamEmitter) -> T + Send + 'static, -) -> (tokio::sync::oneshot::Sender<()>, cosmic::Task) { - let (cancel_tx, cancel_rx) = tokio::sync::oneshot::channel::<()>(); - - let task = cosmic::Task::stream(async_fn_stream::fn_stream(|emitter| async move { - select( - std::pin::pin!(cancel_rx), - std::pin::pin!(event_loop(emitter)), - ) - .await; - })); - - (cancel_tx, task) -}