diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 754b859e..f4f19141 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,11 @@ jobs: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.90.0 + toolchain: 1.93.1 components: clippy - name: install dependencies run: sudo apt update && sudo apt install -y libxkbcommon-dev libwayland-dev libdbus-1-dev libpulse-dev libpipewire-0.3-dev libinput-dev - uses: actions-rs-plus/clippy-check@v2 with: - toolchain: 1.90.0 + toolchain: 1.93.1 args: --all --all-targets --all-features diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 00000000..2cc7b98d --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,15 @@ +{ + "format_on_save": "on", + "lsp": { + "rust-analyzer": { + "initialization_options": { + "check": { + "command": "clippy", + }, + "rustfmt": { + "extraArgs": ["+nightly"], + }, + }, + }, + }, +} diff --git a/Cargo.lock b/Cargo.lock index 958673fa..61fb6d5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,7 +1198,6 @@ dependencies = [ "anyhow", "async-fn-stream", "cosmic-dbus-networkmanager", - "cosmic-settings-airplane-mode-subscription", "cosmic-settings-network-manager-subscription", "futures", "futures-util", @@ -1206,7 +1205,7 @@ dependencies = [ "i18n-embed-fl", "indexmap 2.14.0", "libcosmic-yoda", - "nm-secret-agent-manager", + "nmrs", "rust-embed", "rustc-hash 2.1.2", "secure-string", @@ -1539,17 +1538,6 @@ dependencies = [ "zbus", ] -[[package]] -name = "cosmic-settings-airplane-mode-subscription" -version = "1.0.7" -dependencies = [ - "futures", - "iced_futures", - "log", - "rustix 1.1.4", - "tokio", -] - [[package]] name = "cosmic-settings-config" version = "0.1.0" @@ -2543,6 +2531,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" + [[package]] name = "futures-util" version = "0.3.32" @@ -4497,6 +4491,26 @@ dependencies = [ "zbus", ] +[[package]] +name = "nmrs" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d907d6da103106d84189d3fd229d9aac921f9131b8ba38b40341c53d24409077" +dependencies = [ + "async-trait", + "base64", + "bitflags 2.11.1", + "futures", + "futures-timer", + "log", + "serde", + "thiserror 2.0.18", + "tokio", + "uuid", + "zbus", + "zvariant", +] + [[package]] name = "nom" version = "7.1.3" @@ -5973,6 +5987,12 @@ dependencies = [ "syn", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.9" @@ -6886,6 +6906,7 @@ dependencies = [ "getrandom 0.4.2", "js-sys", "serde_core", + "sha1_smol", "wasm-bindgen", ] @@ -8578,6 +8599,10 @@ dependencies = [ "winnow", ] +[[patch.unused]] +name = "cosmic-settings-airplane-mode-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 5dd5cd88..098b9507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,10 +63,9 @@ cosmic-config = { path = "../libcosmic/cosmic-config" } serde = { version = "1.0.228", features = ["derive"] } [profile.release] -# opt-level = 3 -# panic = "abort" -# lto = "thin" -opt-level = 1 +opt-level = 3 +panic = "abort" +lto = "thin" [workspace.metadata.cargo-machete] ignored = ["libcosmic"] diff --git a/cosmic-app-list/i18n/ca/cosmic_app_list.ftl b/cosmic-app-list/i18n/ca/cosmic_app_list.ftl index e69de29b..340e296c 100644 --- a/cosmic-app-list/i18n/ca/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/ca/cosmic_app_list.ftl @@ -0,0 +1,8 @@ +new-window = Nova Finestra +quit = Surt +run = Executa +run-on = Executa a { $gpu } +quit-all = Surt de totes +run-on-default = (Per defecte) +cosmic-app-list = Safata d'Aplicacions +pin = Ancora a la safata diff --git a/cosmic-app-list/i18n/el/cosmic_app_list.ftl b/cosmic-app-list/i18n/el/cosmic_app_list.ftl index 6a425d48..e77f522a 100644 --- a/cosmic-app-list/i18n/el/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/el/cosmic_app_list.ftl @@ -1 +1,8 @@ new-window = Νέο παράθυρο +quit = Έξοδος +cosmic-app-list = Περιοχή εφαρμογών +run = Εκτέλεση +run-on = Εκτέλεση με { $gpu } +quit-all = Έξοδος από όλα +run-on-default = (Προεπιλογή) +pin = Καρφίτσωμα στην περιοχή εφαρμογών diff --git a/cosmic-app-list/i18n/fr/cosmic_app_list.ftl b/cosmic-app-list/i18n/fr/cosmic_app_list.ftl index a065b203..39cac491 100644 --- a/cosmic-app-list/i18n/fr/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/fr/cosmic_app_list.ftl @@ -3,6 +3,6 @@ pin = Épingler à la barre d'applis quit = Quitter quit-all = Tout quitter new-window = Nouvelle fenêtre -run = Lancer +run = Exécuter run-on = Lancer avec { $gpu } run-on-default = (Défaut) diff --git a/cosmic-app-list/i18n/kk/cosmic_app_list.ftl b/cosmic-app-list/i18n/kk/cosmic_app_list.ftl index c0e5a033..a1b070a2 100644 --- a/cosmic-app-list/i18n/kk/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/kk/cosmic_app_list.ftl @@ -1,5 +1,5 @@ quit = Шығу -run = Іске қосу +run = Орындау run-on = { $gpu } арқылы іске қосу run-on-default = (Әдепкі) cosmic-app-list = Қолданбалар сөресі diff --git a/cosmic-app-list/i18n/lo/cosmic_app_list.ftl b/cosmic-app-list/i18n/lo/cosmic_app_list.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-app-list/i18n/ru/cosmic_app_list.ftl b/cosmic-app-list/i18n/ru/cosmic_app_list.ftl index a7d98a5b..c1195520 100644 --- a/cosmic-app-list/i18n/ru/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/ru/cosmic_app_list.ftl @@ -3,6 +3,6 @@ pin = Закрепить на панели приложений quit = Выйти quit-all = Завершить все new-window = Новое окно -run = Запустить +run = Выполнить run-on = Запустить на { $gpu } run-on-default = (По умолчанию) diff --git a/cosmic-app-list/i18n/sr/cosmic_app_list.ftl b/cosmic-app-list/i18n/sr/cosmic_app_list.ftl index e69de29b..4cf077b9 100644 --- a/cosmic-app-list/i18n/sr/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/sr/cosmic_app_list.ftl @@ -0,0 +1,8 @@ +new-window = Нови прозор +quit = Изађи +run = Покрени +run-on = Покрени на { $gpu } +quit-all = Изађи из свега +run-on-default = (подразумевано) +cosmic-app-list = Системска касета +pin = Закачи у системску касету diff --git a/cosmic-app-list/i18n/uk/cosmic_app_list.ftl b/cosmic-app-list/i18n/uk/cosmic_app_list.ftl index aed01bf2..ec1833cd 100644 --- a/cosmic-app-list/i18n/uk/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/uk/cosmic_app_list.ftl @@ -3,6 +3,6 @@ pin = Закріпити quit = Вийти quit-all = Закрити всі new-window = Нове вікно -run = Запустити +run = Виконати run-on = Запустити на { $gpu } run-on-default = (Основна) diff --git a/cosmic-applet-a11y/i18n/el/cosmic_applet_a11y.ftl b/cosmic-applet-a11y/i18n/el/cosmic_applet_a11y.ftl index e69de29b..609965b5 100644 --- a/cosmic-applet-a11y/i18n/el/cosmic_applet_a11y.ftl +++ b/cosmic-applet-a11y/i18n/el/cosmic_applet_a11y.ftl @@ -0,0 +1,6 @@ +screen-reader = Ανάγνωση οθόνης +invert-colors = Αναστροφή χρωμάτων +high-contrast = Υψηλή αντίθεση +settings = Ρυθμίσεις προσβασιμότητας... +magnifier = Μεγεθυντικός φακός +filter-colors = Φίλτρο χρωμάτων diff --git a/cosmic-applet-a11y/i18n/lo/cosmic_applet_a11y.ftl b/cosmic-applet-a11y/i18n/lo/cosmic_applet_a11y.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-a11y/i18n/sr/cosmic_applet_a11y.ftl b/cosmic-applet-a11y/i18n/sr/cosmic_applet_a11y.ftl index e69de29b..76d163eb 100644 --- a/cosmic-applet-a11y/i18n/sr/cosmic_applet_a11y.ftl +++ b/cosmic-applet-a11y/i18n/sr/cosmic_applet_a11y.ftl @@ -0,0 +1,6 @@ +screen-reader = Читач екрана +invert-colors = Обрни боје +high-contrast = Високи контраст +filter-colors = Филтрирај боје +settings = Подешавања приступачности... +magnifier = Увеличавач diff --git a/cosmic-applet-audio/i18n/el/cosmic_applet_audio.ftl b/cosmic-applet-audio/i18n/el/cosmic_applet_audio.ftl index e69de29b..1bdfccf1 100644 --- a/cosmic-applet-audio/i18n/el/cosmic_applet_audio.ftl +++ b/cosmic-applet-audio/i18n/el/cosmic_applet_audio.ftl @@ -0,0 +1,7 @@ +output = Έξοδος +show-media-controls = Εμφάνιση στοιχείων ελέγχου πολυμέσων στη γραμμή συστήματος +disconnected = Το PulseAudio αποσυνδέθηκε +no-device = Καμία επιλεγμένη συσκευή +input = Είσοδος +unknown-artist = Άγνωστος +sound-settings = Ρυθμίσεις ήχου... diff --git a/cosmic-applet-audio/i18n/lo/cosmic_applet_audio.ftl b/cosmic-applet-audio/i18n/lo/cosmic_applet_audio.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-audio/i18n/sr/cosmic_applet_audio.ftl b/cosmic-applet-audio/i18n/sr/cosmic_applet_audio.ftl index e69de29b..9ddf8185 100644 --- a/cosmic-applet-audio/i18n/sr/cosmic_applet_audio.ftl +++ b/cosmic-applet-audio/i18n/sr/cosmic_applet_audio.ftl @@ -0,0 +1,7 @@ +show-media-controls = Прикажи управљања медијима на траци +disconnected = Пулс-аудио откачен +no-device = Ниједан уређај није изабран +input = Улаз +output = Излаз +unknown-artist = Непознато +sound-settings = Подешавања звука... diff --git a/cosmic-applet-battery/i18n/el/cosmic_applet_battery.ftl b/cosmic-applet-battery/i18n/el/cosmic_applet_battery.ftl index e69de29b..06eca770 100644 --- a/cosmic-applet-battery/i18n/el/cosmic_applet_battery.ftl +++ b/cosmic-applet-battery/i18n/el/cosmic_applet_battery.ftl @@ -0,0 +1,14 @@ +battery = Μπαταρία +power-settings = Ρυθμίσεις ενέργειας και μπαταρίας... +hours = ώ +until-empty = μέχρι την αποφόρτιση +battery-desc = Μειωμένη χρήση ενέργειας και επιδόσεις. +max-charge = Επεκτείνετε τη διάρκεια ζωής της μπαταρίας σας ορίζοντας ως μέγιστη τιμή φόρτισης το 80% +balanced = Ισορροπημένη +seconds = δ +dgpu-running = Η ανεξάρτητη GPU είναι ενεργή και μπορεί να μειώσει τη διάρκεια ζωής της μπαταρίας +performance = Υψηλές επιδόσεις +performance-desc = Υψηλές επιδόσεις και χρήση ενέργειας. +minutes = λ +balanced-desc = Τυπικές επιδόσεις και χρήση μπαταρίας. +dgpu-applications = Εφαρμογές που χρησιμοποιούν την ανεξάρτητη GPU { $gpu_name } diff --git a/cosmic-applet-battery/i18n/lo/cosmic_applet_battery.ftl b/cosmic-applet-battery/i18n/lo/cosmic_applet_battery.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-battery/i18n/sr/cosmic_applet_battery.ftl b/cosmic-applet-battery/i18n/sr/cosmic_applet_battery.ftl index e69de29b..3d242270 100644 --- a/cosmic-applet-battery/i18n/sr/cosmic_applet_battery.ftl +++ b/cosmic-applet-battery/i18n/sr/cosmic_applet_battery.ftl @@ -0,0 +1,14 @@ +power-settings = Подешавања напајања и батерије... +hours = ч +until-empty = до празне +battery-desc = Смањен учинак и употреба струје. +balanced = Уравнотежено +battery = Батерија +seconds = с +performance = Најбрже +performance-desc = Висок учинак и употреба струје. +minutes = м +balanced-desc = Уобичајени учинак и употреба батерије. +max-charge = Повећајте век трајања батерије подешавањем највише вредности пуњења на 80% +dgpu-running = Засебна графичка је покренута и може умањити век трајања батерије +dgpu-applications = Програми који користе засебну графичку { $gpu_name } diff --git a/cosmic-applet-battery/i18n/zh-TW/cosmic_applet_battery.ftl b/cosmic-applet-battery/i18n/zh-TW/cosmic_applet_battery.ftl index 33c18ba3..f5378e27 100644 --- a/cosmic-applet-battery/i18n/zh-TW/cosmic_applet_battery.ftl +++ b/cosmic-applet-battery/i18n/zh-TW/cosmic_applet_battery.ftl @@ -1,4 +1,4 @@ -battery = 省電 +battery = 電池 battery-desc = 降低效能與耗電量。 balanced = 平衡 balanced-desc = 標準效能與耗電量。 diff --git a/cosmic-applet-battery/src/app.rs b/cosmic-applet-battery/src/app.rs index 5bc70e70..f927bde3 100644 --- a/cosmic-applet-battery/src/app.rs +++ b/cosmic-applet-battery/src/app.rs @@ -369,6 +369,10 @@ impl cosmic::Application for CosmicBatteryApplet { let _ = tx.send(()); } let mut tasks = vec![get_popup(popup_settings)]; + if let Some(tx) = &self.settings_daemon_sender { + let _ = tx.send(settings_daemon::Request::GetDisplayBrightness); + let _ = tx.send(settings_daemon::Request::GetMaxDisplayBrightness); + } // Try again every time a popup is opened if self.charging_limit.is_none() { tasks.push(Task::perform(get_charging_limit(), |limit| { diff --git a/cosmic-applet-bluetooth/i18n/ca/cosmic_applet_bluetooth.ftl b/cosmic-applet-bluetooth/i18n/ca/cosmic_applet_bluetooth.ftl index e69de29b..b069b4bf 100644 --- a/cosmic-applet-bluetooth/i18n/ca/cosmic_applet_bluetooth.ftl +++ b/cosmic-applet-bluetooth/i18n/ca/cosmic_applet_bluetooth.ftl @@ -0,0 +1,12 @@ +confirm-pin = Si us plau, verifiqueu que el següent PIN coincideix amb el mostrat a { $deviceName } +bluetooth = Bluetooth +unsuccessful = Error d'Emparellament +pairable = Emparellable +try-again = Reintentar +check-device = Si us plau, verifiqueu que { $deviceName } estigui encès, a l'abast i llest per emparellar-se. +other-devices = Altres dispositius Bluetooth +cancel = Cancel·lar +connected = Connectat +confirm = Confirmar +settings = Configuració del Bluetooth... +discoverable = Descobrible diff --git a/cosmic-applet-bluetooth/i18n/el/cosmic_applet_bluetooth.ftl b/cosmic-applet-bluetooth/i18n/el/cosmic_applet_bluetooth.ftl index 98df71af..84134b90 100644 --- a/cosmic-applet-bluetooth/i18n/el/cosmic_applet_bluetooth.ftl +++ b/cosmic-applet-bluetooth/i18n/el/cosmic_applet_bluetooth.ftl @@ -1,2 +1,12 @@ cancel = Ακύρωση confirm = Επιβεβαίωση +bluetooth = Bluetooth +confirm-pin = Επιβεβαιώστε ότι το ακόλουθο PIN είναι ίδιο με αυτό που εμφανίζεται στο { $deviceName } +unsuccessful = Ανεπιτυχής σύζευξη +pairable = Συνδέσιμο +try-again = Δοκιμή ξανά +check-device = Βεβαιωθείτε ότι το { $deviceName } είναι ενεργοποιημένο, βρίσκεται εντός εμβέλειας και είναι έτοιμο για σύζευξη. +other-devices = Άλλες συσκευές Bluetooth +connected = Συνδέθηκε +settings = Ρυθμίσεις Bluetooth... +discoverable = Ορατό diff --git a/cosmic-applet-bluetooth/i18n/lo/cosmic_applet_bluetooth.ftl b/cosmic-applet-bluetooth/i18n/lo/cosmic_applet_bluetooth.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-bluetooth/i18n/sr/cosmic_applet_bluetooth.ftl b/cosmic-applet-bluetooth/i18n/sr/cosmic_applet_bluetooth.ftl index e69de29b..b6515b52 100644 --- a/cosmic-applet-bluetooth/i18n/sr/cosmic_applet_bluetooth.ftl +++ b/cosmic-applet-bluetooth/i18n/sr/cosmic_applet_bluetooth.ftl @@ -0,0 +1,12 @@ +confirm-pin = Потврдите да се овај ПИН подудара са оним приказаним на { $deviceName } +bluetooth = Блутут +unsuccessful = Неуспешно упаривање +pairable = Упарив +try-again = Покушај поново +check-device = Постарајте се да је { $deviceName } укључен, у домету и спреман за упаривање. +other-devices = Други блутут уређаји +cancel = Откажи +connected = Повезано +confirm = Потврди +settings = Подешавања блутута... +discoverable = Откривљив diff --git a/cosmic-applet-input-sources/i18n/el/cosmic_applet_input_sources.ftl b/cosmic-applet-input-sources/i18n/el/cosmic_applet_input_sources.ftl index e69de29b..546be28d 100644 --- a/cosmic-applet-input-sources/i18n/el/cosmic_applet_input_sources.ftl +++ b/cosmic-applet-input-sources/i18n/el/cosmic_applet_input_sources.ftl @@ -0,0 +1,2 @@ +show-keyboard-layout = Εμφάνιση διάταξης πληκτρολογίου... +keyboard-settings = Ρυθμίσεις πληκτρολογίου... diff --git a/cosmic-applet-input-sources/i18n/lo/cosmic_applet_input_sources.ftl b/cosmic-applet-input-sources/i18n/lo/cosmic_applet_input_sources.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-input-sources/i18n/sr/cosmic_applet_input_sources.ftl b/cosmic-applet-input-sources/i18n/sr/cosmic_applet_input_sources.ftl index e69de29b..4d552b47 100644 --- a/cosmic-applet-input-sources/i18n/sr/cosmic_applet_input_sources.ftl +++ b/cosmic-applet-input-sources/i18n/sr/cosmic_applet_input_sources.ftl @@ -0,0 +1,2 @@ +show-keyboard-layout = Прикажи распоред тастатуре... +keyboard-settings = Подешавања тастатуре... diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index 91f59a75..ea265d4e 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -26,14 +26,12 @@ tracing-log.workspace = true tracing-subscriber.workspace = true tracing.workspace = true zbus.workspace = true -nm-secret-agent-manager = { path = "../../dbus-settings-bindings/nm-secret-agent-manager" } 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" - -[dependencies.cosmic-settings-airplane-mode-subscription] -path = "../../cosmic-settings/subscriptions/airplane-mode" diff --git a/cosmic-applet-network/i18n/ca/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/ca/cosmic_applet_network.ftl index e69de29b..ae3bd5dd 100644 --- a/cosmic-applet-network/i18n/ca/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/ca/cosmic_applet_network.ftl @@ -0,0 +1,4 @@ +cancel = Cancel·lar +connected = Connectat +wifi = Wi-Fi +identity = Identitat diff --git a/cosmic-applet-network/i18n/el/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/el/cosmic_applet_network.ftl index c7ed802d..8eac3a7a 100644 --- a/cosmic-applet-network/i18n/el/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/el/cosmic_applet_network.ftl @@ -1 +1,24 @@ cancel = Ακύρωση +connect = Σύνδεση +network = Δίκτυο +check-wifi-connection = Βεβαιωθείτε ότι το Wi-Fi είναι συνδεδεμένο στο διαδίκτυο και ότι ο κωδικός πρόσβασης είναι σωστός +reset = Επαναφορά +visible-wireless-networks = Ορατά ασύρματα δίκτυα +enter-password = Εισαγάγετε τον κωδικό πρόσβασης ή το κλειδί κρυπτογράφησης +ipv6 = Διεύθυνση IPv6 +airplane-mode-on = Η λειτουργία πτήσης είναι ενεργή +connecting = Σύνδεση +airplane-mode = Λειτουργία πτήσης +wifi = Wi-Fi +ipv4 = Διεύθυνση IPv4 +identity = Ταυτότητα +unable-to-connect = Δεν είναι δυνατή η σύνδεση στο δίκτυο +turn-off-airplane-mode = Απενεργοποιήστε τη για ενεργοποίηση του Wi-Fi, του Bluetooth και της κινητής ευρυζωνικής σύνδεσης. +connected = Συνδέθηκε +vpn-connections = Συνδέσεις VPN +mac = MAC +router-wps-button = Μπορείτε επίσης να συνδεθείτε πατώντας το κουμπί «WPS» του δρομολογητή +settings = Ρυθμίσεις δικτύου... +megabits-per-second = Mbps +gigabits-per-second = Gbps +terabits-per-second = Tbps diff --git a/cosmic-applet-network/i18n/lo/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/lo/cosmic_applet_network.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-network/i18n/sr/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/sr/cosmic_applet_network.ftl index e69de29b..b79b0ddd 100644 --- a/cosmic-applet-network/i18n/sr/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/sr/cosmic_applet_network.ftl @@ -0,0 +1,24 @@ +cancel = Откажи +connected = Повезано +connect = Повежи +identity = Идентитет +wifi = Бежична +check-wifi-connection = Уверите се да је бежична мрежа повезана са интернетом и да је лозинка тачна +reset = Врати +visible-wireless-networks = Видљиве бежичне мреже +enter-password = Унесите лозинку или кључ за шифровање +ipv6 = ИПв6 адреса +airplane-mode-on = Авионски режим је укључен +connecting = Повезује се +airplane-mode = Авио режим +ipv4 = ИПв4 адреса +unable-to-connect = Немогуће повезати се са мрежом +turn-off-airplane-mode = Искључите да бисте омогућили Блутут, бежичну и мобилни интернет. +network = Мрежа +vpn-connections = ВПН везе +mac = МАК +router-wps-button = Такође се можете повезати притиском на дугме „WPS“ на рутеру +settings = Подешавања мреже... +megabits-per-second = Mbps +gigabits-per-second = Gbps +terabits-per-second = Tbps diff --git a/cosmic-applet-network/i18n/uk/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/uk/cosmic_applet_network.ftl index 687539ca..cebc8087 100644 --- a/cosmic-applet-network/i18n/uk/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/uk/cosmic_applet_network.ftl @@ -8,15 +8,15 @@ ipv6 = IPv6-адреса mac = MAC megabits-per-second = Мбіт/с connected = З'єднано -connecting = Підключення -connect = З'єднати +connecting = З’єднання +connect = З’єднати cancel = Скасувати settings = Налаштування мережі... visible-wireless-networks = Видимі бездротові мережі enter-password = Введіть пароль або ключ шифрування -router-wps-button = Також можна підключитися, натиснувши кнопку «WPS» на маршрутизаторі -unable-to-connect = Не вдалося підключитися до мережі -check-wifi-connection = Переконайтеся, що Wi-Fi підключено до Інтернету, а пароль — правильний +router-wps-button = Також можна під’єднатися, натиснувши кнопку «WPS» на маршрутизаторі +unable-to-connect = Не вдалося під’єднатися до мережі +check-wifi-connection = Переконайтеся, що Wi-Fi під’єднано до Інтернету, а пароль — правильний reset = Скинути identity = Ідентичність vpn-connections = VPN-з'єднання diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 908d1d3e..6939f5e3 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -1,18 +1,20 @@ use anyhow::Context; -use cosmic_dbus_networkmanager::settings::{NetworkManagerSettings, connection::Settings}; use cosmic_settings_network_manager_subscription::{ self as network_manager, NetworkManagerState, UUID, available_wifi::{AccessPoint, NetworkType}, current_networks::ActiveConnectionInfo, hw_address::HwAddress, - nm_secret_agent::{self, PasswordFlag, SecretSender}, }; use indexmap::IndexMap; +use nmrs::{ + NetworkManager as NmrsManager, SettingsSummary, + agent::{SecretAgent, SecretAgentCapabilities, SecretRequest, SecretResponder, SecretSetting}, +}; use rustc_hash::FxHashSet; use secure_string::SecureString; use std::{ borrow::Cow, - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, HashMap}, sync::{Arc, LazyLock}, }; @@ -36,10 +38,12 @@ use cosmic::{ row, scrollable, secure_input, text, text_input, toggler, }, }; -use cosmic_dbus_networkmanager::interface::enums::{ActiveConnectionState, DeviceState, NmConnectivityState}; +use cosmic_dbus_networkmanager::interface::enums::{ + ActiveConnectionState, DeviceState, NmConnectivityState, +}; -use futures::StreamExt; -use zbus::{Connection, zvariant::ObjectPath}; +use futures::{StreamExt, lock::Mutex as AsyncMutex}; +use zbus::Connection; use crate::{config, fl}; @@ -69,15 +73,6 @@ impl NewConnectionState { } .ssid } - #[allow(dead_code)] - pub fn hw_address(&self) -> HwAddress { - match self { - Self::EnterPassword { access_point, .. } => access_point, - Self::Waiting(ap) => ap, - Self::Failure(ap) => ap, - } - .hw_address - } } impl From for AccessPoint { @@ -92,60 +87,58 @@ impl From for AccessPoint { pub static SECURE_INPUT_WIFI: LazyLock = LazyLock::new(Id::unique); -#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct MyNetworkState { pub known_vpns: IndexMap, pub ssid_to_uuid: BTreeMap, Box>, pub devices: Vec>, - pub password: Option, - pub connecting: BTreeSet, pub nm_state: NetworkManagerState, pub requested_vpn: Option, } -#[allow(dead_code)] +/// Shared, take-once handle to an `nmrs` [`SecretResponder`]. Cloned freely +/// across `Message` boundaries; the first consumer to `lock().take()` it owns +/// the reply to NetworkManager. +pub type SecretResponderHandle = Arc>>; + #[derive(Debug, Clone)] pub struct RequestedVpn { - name: String, uuid: Arc, description: Option, password: SecureString, password_hidden: bool, - tx: SecretSender, + responder: SecretResponderHandle, + /// VPN secret keys NM hinted as needed (e.g. `["password"]`). When empty, + /// `"password"` is used as a fallback. + secret_keys: Vec, } #[derive(Clone, Debug)] pub enum ConnectionSettings { - Vpn(VpnConnectionSettings), + Vpn { id: String }, Wireguard { id: String }, } -#[allow(dead_code)] -#[derive(Clone, Debug, Default)] -pub struct VpnConnectionSettings { - id: String, - username: Option, - connection_type: Option, - password_flag: Option, +/// Local mirror of the secret-agent events the applet cares about. Sourced +/// from `nmrs::agent` instead of the previous `nm_secret_agent` subscription. +#[derive(Debug, Clone)] +pub enum NmAgentEvent { + RequestSecret { + connection_uuid: String, + connection_id: String, + setting: AgentSetting, + responder: SecretResponderHandle, + }, + CancelGetSecrets, + Failed(String), } -#[derive(Clone, Debug, Eq, PartialEq)] -enum ConnectionType { - Password, -} - -#[allow(dead_code)] -impl VpnConnectionSettings { - fn password_flag(&self) -> Option { - self.connection_type - .as_ref() - .is_some_and(|ct| match ct { - ConnectionType::Password => true, - }) - .then_some(self.password_flag) - .flatten() - } +#[derive(Debug, Clone)] +pub enum AgentSetting { + WifiPsk { ssid: String }, + WifiEap, + Vpn { secret_keys: Vec }, + Other, } #[derive(Default)] @@ -157,7 +150,6 @@ struct CosmicNetworkApplet { // NM state nm_sender: Option>, nm_task: Option>, - secret_tx: Option>, nm_state: MyNetworkState, // UI state @@ -264,8 +256,9 @@ fn vpn_section<'a>( if show_available_vpns { for (uuid, connection) in &nm_state.known_vpns { let id = match connection { - ConnectionSettings::Vpn(connection) => connection.id.as_str(), - ConnectionSettings::Wireguard { id } => id.as_str(), + ConnectionSettings::Vpn { id } | ConnectionSettings::Wireguard { id } => { + id.as_str() + } }; // Check if this VPN is currently active let is_active = nm_state.nm_state.active_conns.iter().any( @@ -394,57 +387,91 @@ impl CosmicNetworkApplet { } fn connect_vpn(&mut self, uuid: Arc) -> Task> { - if let Some((tx, conn)) = self.nm_sender.clone().zip(self.conn.clone()) { - cosmic::task::future(async move { - // Find the connection by UUID - if let Ok(nm_settings) = NetworkManagerSettings::new(&conn).await { - if let Ok(connections) = nm_settings.list_connections().await { - for connection in connections { - if let Ok(settings) = connection.get_settings().await { - let settings = Settings::new(settings); - if let Some(conn_settings) = &settings.connection { - if conn_settings.uuid.as_ref().is_some_and(|conn_uuid| { - conn_uuid.as_str() == uuid.as_ref() - }) { - let path = connection.inner().path().clone().to_owned(); - if let Err(err) = - tx.unbounded_send(network_manager::Request::Activate( - ObjectPath::try_from("/").unwrap(), - path, - )) - { - if err.is_disconnected() { - return zbus::Connection::system() - .await - .context( - "failed to create system dbus connection", - ) - .map_or_else( - |why| Message::Error(why.to_string()), - Message::NetworkManagerConnect, - ); - } - - tracing::error!("{err:?}"); - } - break; - } - } - } - } - } - } - Message::Refresh - }) - } else { - tracing::warn!("No sender available to activate VPN."); - Task::none() - } + 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}")), + } + }) } } +/// 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 { + cosmic::Task::stream(async_fn_stream::fn_stream(move |emitter| async move { + let registration = SecretAgent::builder() + .with_identifier(identifier) + .with_capabilities(SecretAgentCapabilities::VPN_HINTS) + .register() + .await; + + let (mut handle, mut requests) = match registration { + Ok(pair) => pair, + Err(e) => { + let _ = emitter.emit(NmAgentEvent::Failed(e.to_string())).await; + return; + } + }; + + loop { + tokio::select! { + req = requests.next() => match req { + Some(req) => { + let event = secret_request_to_event(req); + let _ = emitter.emit(event).await; + } + None => break, + }, + cancel = handle.cancellations().next() => match cancel { + Some(_reason) => { + let _ = emitter.emit(NmAgentEvent::CancelGetSecrets).await; + } + None => break, + }, + } + } + + if let Err(e) = handle.unregister().await { + tracing::warn!("failed to unregister secret agent: {e}"); + } + })) +} + +fn secret_request_to_event(req: SecretRequest) -> NmAgentEvent { + let setting = match req.setting { + SecretSetting::WifiPsk { ssid } => AgentSetting::WifiPsk { ssid }, + SecretSetting::WifiEap { .. } => AgentSetting::WifiEap, + SecretSetting::Vpn { .. } => AgentSetting::Vpn { + secret_keys: req.hints.clone(), + }, + _ => AgentSetting::Other, + }; + + NmAgentEvent::RequestSecret { + connection_uuid: req.connection_uuid, + connection_id: req.connection_id, + setting, + responder: Arc::new(AsyncMutex::new(Some(req.responder))), + } +} + +/// Reply with [`NoSecrets`](nmrs::agent::SecretResponder::no_secrets) to free +/// NetworkManager when the applet decides not to use the responder. Dropping +/// it would also auto-reply, but doing it explicitly keeps the log clean. +fn release_responder(responder: SecretResponderHandle) -> Task> { + cosmic::task::future(async move { + if let Some(r) = responder.lock().await.take() { + let _ = r.no_secrets().await; + } + Message::NoOp + }) +} + #[derive(Debug, Clone)] -#[allow(dead_code)] pub(crate) enum Message { TogglePopup, CloseRequested(window::Id), @@ -458,12 +485,13 @@ pub(crate) enum Message { TogglePasswordVisibility, FocusSecureInput, NoOp, + #[allow(dead_code)] // required by `cosmic::applet` surface path; not always emitted Surface(surface::Action), ActivateVpn(Arc), // UUID of VPN to activate DeactivateVpn(Arc), // UUID of VPN to deactivate ToggleVpnList, // Show/hide available VPNs /// An update from the secret agent - SecretAgent(network_manager::nm_secret_agent::Event), + SecretAgent(NmAgentEvent), /// Connect to a WiFi network access point. Connect(network_manager::SSID, HwAddress), /// Connect with a password @@ -499,17 +527,6 @@ pub(crate) enum Message { SelectDevice(Option>), } -#[allow(dead_code)] -#[derive(Debug, Clone)] -pub(crate) struct Password { - ssid: network_manager::SSID, - hw_address: HwAddress, - identity: Option, - password: SecureString, - password_hidden: bool, - tx: SecretSender, -} - fn connection_settings(conn: zbus::Connection) -> Task { let settings = async move { let settings = network_manager::dbus::settings::NetworkManagerSettings::new(&conn).await?; @@ -633,109 +650,30 @@ impl CosmicNetworkApplet { } } -fn load_vpns(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, and filter for VPN. - .filter_map(|conn| async move { - let settings = conn.get_settings().await.ok()?; - - let connection = settings.get("connection")?; - - match connection - .get("type")? - .downcast_ref::() - .ok()? - .as_str() - { - "vpn" => (), - - "wireguard" => { - let id = connection.get("id")?.downcast_ref::().ok()?; - let uuid = connection.get("uuid")?.downcast_ref::().ok()?; - return Some((Arc::from(uuid), ConnectionSettings::Wireguard { id })); - } - - _ => return None, - } - - let vpn = settings.get("vpn")?; - let id = connection.get("id")?.downcast_ref::().ok()?; - let uuid = connection.get("uuid")?.downcast_ref::().ok()?; - - let (connection_type, username, password_flag) = vpn - .get("data") - .and_then(|data| data.downcast_ref::().ok()) - .map(|dict| { - let (mut connection_type, mut password_flag) = (None, None); - let mut username = vpn - .get("user-name") - .and_then(|u| u.downcast_ref::().ok()); - if dict - .get::(&String::from("connection-type")) - .ok() - .flatten() - .as_deref() - // may be "password" or "password-tls" - .is_some_and(|p| p.starts_with("password")) - { - connection_type = Some(ConnectionType::Password); - username = Some(username.unwrap_or_default()); - - password_flag = dict - .get::(&String::from("password-flags")) - .ok() - .flatten() - .and_then(|value| match value.as_str() { - "0" => Some(PasswordFlag::None), - "1" => Some(PasswordFlag::AgentOwned), - "2" => Some(PasswordFlag::NotSaved), - "4" => Some(PasswordFlag::NotRequired), - _ => None, - }); - } - - (connection_type, username, password_flag) - }) - .unwrap_or_default(); - - Some(( - Arc::from(uuid), - ConnectionSettings::Vpn(VpnConnectionSettings { - id, - connection_type, - password_flag, - username, - }), - )) - }) - // Reduce the settings list into - .fold(IndexMap::new(), |mut set, (uuid, data)| async move { - set.insert(uuid, data); - set - }) - .await; - - Ok::<_, zbus::Error>(settings) - }; - +fn load_vpns(_conn: zbus::Connection) -> Task { cosmic::task::future(async move { - settings.await.map_or_else( - |why| Message::Error(why.to_string()), - Message::KnownConnections, - ) + 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 { + 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) }) } @@ -788,19 +726,11 @@ impl cosmic::Application for CosmicNetworkApplet { tasks.push(update_state(conn.clone())); tasks.push(update_devices(conn.clone())); tasks.push(load_vpns(conn)); - let (tx, rx) = tokio::sync::mpsc::channel(4); - self.secret_tx = Some(tx); let my_id = format!( "com.system76.CosmicSettings.Applet.{}.NetworkManager.SecretAgent", uuid::Uuid::new_v4() ); - tasks.push( - cosmic::Task::stream(nm_secret_agent::secret_agent_stream( - my_id.clone(), - rx, - )) - .map(Message::SecretAgent), - ); + tasks.push(secret_agent_task(my_id).map(Message::SecretAgent)); } // TODO request update of state maybe let new_id = window::Id::unique(); @@ -822,17 +752,20 @@ impl cosmic::Application for CosmicNetworkApplet { } Message::ToggleAirplaneMode(enabled) => { self.toggle_wifi_ctr += 1; - if let Some(tx) = self.nm_sender.as_mut() { - if let Err(err) = - tx.unbounded_send(network_manager::Request::SetAirplaneMode(enabled)) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + self.nm_state.nm_state.airplane_mode = enabled; + return cosmic::task::future(async move { + match NmrsManager::new().await { + Ok(nm) => match nm.set_airplane_mode(enabled).await { + Ok(()) => Message::Refresh, + Err(e) => { + tracing::warn!("set_airplane_mode partial failure: {e}"); + Message::Refresh + } + }, + Err(e) => Message::Error(format!("nmrs init: {e}")), } - } + }) + .map(cosmic::Action::App); } Message::SelectWirelessAccessPoint(access_point) => { let Some(tx) = self.nm_sender.as_ref() else { @@ -844,7 +777,7 @@ impl cosmic::Application for CosmicNetworkApplet { tx.unbounded_send(network_manager::Request::SelectAccessPoint( access_point.ssid.clone(), access_point.network_type, - self.secret_tx.clone(), + None, self.active_device.as_ref().map(|d| d.interface.clone()), )) { @@ -861,21 +794,19 @@ impl cosmic::Application for CosmicNetworkApplet { .nm_state .known_access_points .contains(&access_point) - { - if let Err(err) = + && let Err(err) = tx.unbounded_send(network_manager::Request::SelectAccessPoint( access_point.ssid.clone(), access_point.network_type, - self.secret_tx.clone(), + 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 err.is_disconnected() { + return system_conn().map(cosmic::Action::App); } + + tracing::error!("{err:?}"); } self.new_connection = Some(NewConnectionState::EnterPassword { access_point, @@ -914,7 +845,6 @@ impl cosmic::Application for CosmicNetworkApplet { _ = cancel.send(()); } - self.secret_tx = None; return system_conn().map(cosmic::Action::App); } } @@ -980,19 +910,23 @@ impl cosmic::Application for CosmicNetworkApplet { tracing::warn!("Failed to find known access point with ssid: {}", ssid); return Task::none(); }; - if let Some(tx) = self.nm_sender.as_ref() { - if let Err(err) = - tx.unbounded_send(network_manager::Request::Forget(ssid.into())) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + self.show_visible_networks = true; + let ssid_for_task = ssid.clone(); + let forget_task = cosmic::task::future(async move { + match NmrsManager::new().await { + Ok(nm) => match nm.forget(&ssid_for_task).await { + Ok(()) => Message::Refresh, + Err(e) => { + tracing::warn!("forget {ssid_for_task} failed: {e}"); + Message::Refresh + } + }, + Err(e) => Message::Error(format!("nmrs init: {e}")), } - self.show_visible_networks = true; - return self.update(Message::SelectWirelessAccessPoint(ap)); - } + }) + .map(cosmic::Action::App); + let reconnect_task = self.update(Message::SelectWirelessAccessPoint(ap)); + return Task::batch(vec![forget_task, reconnect_task]); } Message::Surface(a) => { return cosmic::task::message(cosmic::Action::Cosmic( @@ -1002,17 +936,17 @@ impl cosmic::Application for CosmicNetworkApplet { Message::ActivateVpn(uuid) => { return self.connect_vpn(uuid.clone()); } - Message::DeactivateVpn(name) => { - if let Some(tx) = self.nm_sender.as_ref() { - if let Err(err) = tx.unbounded_send(network_manager::Request::Deactivate(name)) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + 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}")), } - } + }) + .map(cosmic::Action::App); } Message::ToggleVpnList => { self.show_available_vpns = !self.show_available_vpns; @@ -1037,7 +971,7 @@ impl cosmic::Application for CosmicNetworkApplet { if let Err(err) = tx.unbounded_send(network_manager::Request::SelectAccessPoint( ssid, network_type, - self.secret_tx.clone(), + None, self.active_device.as_ref().map(|d| d.interface.clone()), )) { if err.is_disconnected() { @@ -1066,7 +1000,7 @@ impl cosmic::Application for CosmicNetworkApplet { ssid: access_point.ssid.to_string(), identity: is_enterprise.then(|| identity.clone()), password, - secret_tx: self.secret_tx.clone(), + secret_tx: None, interface: self.active_device.as_ref().map(|d| d.interface.clone()), }) { if err.is_disconnected() { @@ -1166,15 +1100,7 @@ impl cosmic::Application for CosmicNetworkApplet { if let Some(ActiveConnectionInfo::WiFi { state, .. }) = state .active_conns .iter_mut() - .find(|ap| { - let _ap_hw_address = match ap { - ActiveConnectionInfo::Wired { hw_address, .. } - | ActiveConnectionInfo::WiFi { hw_address, .. } => { - HwAddress::from_str(&hw_address).unwrap() - } - ActiveConnectionInfo::Vpn { .. } => HwAddress::default(), - }; - ap.name().as_str() == ssid.as_ref()}) + .find(|ap| ap.name().as_str() == ssid.as_ref()) { *state = ActiveConnectionState::Activated; } @@ -1192,7 +1118,7 @@ impl cosmic::Application for CosmicNetworkApplet { identity: _, password: _, secret_tx: _, - interface: _ + interface: _, } = &req { if let Some(NewConnectionState::Waiting(access_point)) = @@ -1206,14 +1132,13 @@ impl cosmic::Application for CosmicNetworkApplet { } else { self.show_visible_networks = false; } - } else if let Some(NewConnectionState::EnterPassword { - access_point, .. - }) = self.new_connection.as_ref() + } else if let Some(NewConnectionState::EnterPassword { access_point, .. }) = + self.new_connection.as_ref() + && success + && ssid.as_str() == access_point.ssid.as_ref() { - if success && ssid.as_str() == access_point.ssid.as_ref() { - self.new_connection = None; - self.show_visible_networks = false; - } + self.new_connection = None; + self.show_visible_networks = false; } } else if self .new_connection @@ -1270,72 +1195,91 @@ impl cosmic::Application for CosmicNetworkApplet { self.nm_state.devices = device_infos.into_iter().map(Arc::new).collect(); } Message::WiFiEnable(enable) => { - if let Some(sender) = self.nm_sender.as_mut() { - if let Err(err) = - sender.unbounded_send(network_manager::Request::SetWiFi(enable)) - { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); + self.nm_state.nm_state.wifi_enabled = enable; + return cosmic::task::future(async move { + match NmrsManager::new().await { + Ok(nm) => match nm.set_wireless_enabled(enable).await { + Ok(()) => Message::Refresh, + Err(e) => Message::Error(format!("set_wireless_enabled: {e}")), + }, + Err(e) => Message::Error(format!("nmrs init: {e}")), } - if let Err(err) = sender.unbounded_send(network_manager::Request::Reload) { - if err.is_disconnected() { - return system_conn().map(cosmic::Action::App); - } - - tracing::error!("{err:?}"); - } - } + }) + .map(cosmic::Action::App); } Message::SecretAgent(agent_event) => match agent_event { - nm_secret_agent::Event::RequestSecret { - uuid, - name, - description, - previous, - tx, - .. + NmAgentEvent::RequestSecret { + connection_uuid, + connection_id, + setting, + responder, } => { + let description = (!connection_id.is_empty()).then_some(connection_id); + let known_vpn = self + .nm_state + .known_vpns + .contains_key(connection_uuid.as_str()); + + let mut consumed = false; + if let Some(state) = self.new_connection.as_mut() { match state { NewConnectionState::EnterPassword { access_point, .. } | NewConnectionState::Waiting(access_point) | NewConnectionState::Failure(access_point) => { - if self + let matches_ssid = matches!( + &setting, + AgentSetting::WifiPsk { ssid } + if ssid == access_point.ssid.as_ref() + ); + let matches_uuid = self .nm_state .ssid_to_uuid .get(access_point.ssid.as_ref()) - .is_some_and(|ap_uuid| ap_uuid.as_ref() == uuid.as_str()) - { + .is_some_and(|ap_uuid| { + ap_uuid.as_ref() == connection_uuid.as_str() + }); + + if matches_ssid || matches_uuid { *state = NewConnectionState::EnterPassword { access_point: access_point.clone(), - description, + description: description.clone(), identity: String::new(), password: String::new().into(), password_hidden: true, - } + }; } } } - } else if self.nm_state.known_vpns.contains_key(uuid.as_str()) { + } else if known_vpn { + let secret_keys = match &setting { + AgentSetting::Vpn { secret_keys } => secret_keys.clone(), + _ => Vec::new(), + }; self.nm_state.requested_vpn = Some(RequestedVpn { - name, - uuid: uuid.into(), + uuid: connection_uuid.into(), description, - password: previous, + password: SecureString::from(String::new()), password_hidden: true, - tx, + responder: responder.clone(), + secret_keys, }); + consumed = true; + } + + // The applet's Wi-Fi flow re-issues the password through + // `Authenticate` rather than the agent. Free NM with + // `NoSecrets` so it doesn't sit on a stalled GetSecrets call. + if !consumed { + return release_responder(responder); } } - nm_secret_agent::Event::CancelGetSecrets { .. } => { + NmAgentEvent::CancelGetSecrets => { self.new_connection = None; self.nm_state.requested_vpn = None; } - nm_secret_agent::Event::Failed(error) => { - tracing::error!("Error from secret agent: {error:?}"); + NmAgentEvent::Failed(error) => { + tracing::error!("Error from secret agent: {error}"); } }, Message::KnownConnections(index_map) => { @@ -1357,12 +1301,30 @@ impl cosmic::Application for CosmicNetworkApplet { } } Message::ConnectVPNWithPassword => { - if let Some(RequestedVpn { password, tx, .. }) = self.nm_state.requested_vpn.take() + if let Some(RequestedVpn { + password, + responder, + secret_keys, + .. + }) = self.nm_state.requested_vpn.take() { return Task::future(async move { - let mut guard = tx.lock().await; - if let Some(tx) = guard.take() { - let _ = tx.send(password); + let Some(responder) = responder.lock().await.take() else { + return Message::Refresh; + }; + + let mut secrets: HashMap = HashMap::new(); + let value = password.unsecure().to_owned(); + if secret_keys.is_empty() { + secrets.insert("password".to_owned(), value); + } else { + for key in secret_keys { + secrets.insert(key, value.clone()); + } + } + + if let Err(e) = responder.vpn_secrets(secrets).await { + tracing::error!("vpn secret reply failed: {e}"); } Message::Refresh }) @@ -1375,7 +1337,15 @@ impl cosmic::Application for CosmicNetworkApplet { } } Message::CancelVPNConnection => { - self.nm_state.requested_vpn = None; + if let Some(req) = self.nm_state.requested_vpn.take() { + return Task::future(async move { + if let Some(responder) = req.responder.lock().await.take() { + let _ = responder.cancel().await; + } + Message::NoOp + }) + .map(cosmic::Action::App); + } } } Task::none() @@ -1560,7 +1530,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(), )) .into(), ); @@ -1575,7 +1545,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(), )), )]) .align_x(Alignment::Center), @@ -1732,14 +1702,13 @@ impl cosmic::Application for CosmicNetworkApplet { } for known in &self.nm_state.nm_state.known_access_points { - if let Some(active_device) = self.active_device.as_ref() { - if active_device + if let Some(active_device) = self.active_device.as_ref() + && active_device .known_connections .iter() - .all(|c| &c.id != known.ssid.as_ref()) - { - continue; - } + .all(|c| c.id != *known.ssid) + { + continue; } let mut btn_content = Vec::with_capacity(2); let ssid = text::body(known.ssid.as_ref()).width(Length::Fill); @@ -1871,43 +1840,43 @@ impl cosmic::Application for CosmicNetworkApplet { content = content.push(id); 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(|| { - text_input::text_input("", identity) - .on_input(|i| Message::IdentityUpdate(i)) - })) - .push(text::body(fl!("enter-password"))) - .push_maybe(description.as_ref().map(|d| text::body(d.clone()))) - .push( - text_input::secure_input( - "", - password.unsecure(), - Some(Message::TogglePasswordVisibility), - *password_hidden, - ) - .id(SECURE_INPUT_WIFI.clone()) - .on_input(|s| Message::PasswordUpdate(SecureString::from(s))) - .on_paste(|s| Message::PasswordUpdate(SecureString::from(s))) - .on_submit(|_| Message::ConnectWithPassword), + let enter_password_col = cosmic::widget::column::with_capacity(4) + .push_maybe(is_enterprise.then(|| text::body(fl!("identity")))) + .push_maybe(is_enterprise.then(|| { + text_input::text_input("", identity).on_input(Message::IdentityUpdate) + })) + .push(text::body(fl!("enter-password"))) + .push_maybe(description.as_ref().map(|d| text::body(d.clone()))) + .push( + text_input::secure_input( + "", + password.unsecure(), + Some(Message::TogglePasswordVisibility), + *password_hidden, ) - .push_maybe(access_point.wps_push.then(|| { + .id(SECURE_INPUT_WIFI.clone()) + .on_input(|s| Message::PasswordUpdate(SecureString::from(s))) + .on_paste(|s| Message::PasswordUpdate(SecureString::from(s))) + .on_submit(|_| Message::ConnectWithPassword), + ) + .push_maybe( + access_point.wps_push.then(|| { container(text::body(fl!("router-wps-button"))).padding(8) - })) - .push( - row::with_children([ - Element::from( - button::standard(fl!("cancel")) - .on_press(Message::CancelNewConnection), - ), - Element::from( - button::suggested(fl!("connect")) - .on_press(Message::ConnectWithPassword), - ), - ]) - .spacing(24), - ); + }), + ) + .push( + row::with_children([ + Element::from( + button::standard(fl!("cancel")) + .on_press(Message::CancelNewConnection), + ), + Element::from( + button::suggested(fl!("connect")) + .on_press(Message::ConnectWithPassword), + ), + ]) + .spacing(24), + ); let col = padded_control(enter_password_col.spacing(8).align_x(Alignment::Center)) .align_x(Alignment::Center); @@ -1986,7 +1955,7 @@ impl cosmic::Application for CosmicNetworkApplet { .filter(|ap| { let among_active = self.nm_state.nm_state.active_conns.iter().any(|a| { let hw_address = active_conn_hw_address(a); - ap.ssid.as_ref() == &a.name() && ap.hw_address == hw_address + ap.ssid.as_ref() == a.name() && ap.hw_address == hw_address }); let among_known = self.nm_state diff --git a/cosmic-applet-notifications/i18n/el/cosmic_applet_notifications.ftl b/cosmic-applet-notifications/i18n/el/cosmic_applet_notifications.ftl index e69de29b..56feb284 100644 --- a/cosmic-applet-notifications/i18n/el/cosmic_applet_notifications.ftl +++ b/cosmic-applet-notifications/i18n/el/cosmic_applet_notifications.ftl @@ -0,0 +1,19 @@ +hours-ago = + { $duration -> + [0] Μόλις τώρα + [one] Πριν από 1 ώρα + *[other] Πριν από { $duration } ώρες + } +show-more = Εμφάνιση { $more } ακόμη +clear-all = Απαλοιφή όλων των ειδοποιήσεων +notification-settings = Ρυθμίσεις ειδοποιήσεων... +no-notifications = Καμία ειδοποίηση +do-not-disturb = Μην ενοχλείτε +show-less = Εμφάνιση λιγότερων +clear-group = Απαλοιφή ομάδας +minutes-ago = + { $duration -> + [0] Μόλις τώρα + [one] Πριν από 1 λεπτό + *[other] Πριν από { $duration } λεπτά + } diff --git a/cosmic-applet-notifications/i18n/lo/cosmic_applet_notifications.ftl b/cosmic-applet-notifications/i18n/lo/cosmic_applet_notifications.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-notifications/i18n/sr/cosmic_applet_notifications.ftl b/cosmic-applet-notifications/i18n/sr/cosmic_applet_notifications.ftl index e69de29b..39408d17 100644 --- a/cosmic-applet-notifications/i18n/sr/cosmic_applet_notifications.ftl +++ b/cosmic-applet-notifications/i18n/sr/cosmic_applet_notifications.ftl @@ -0,0 +1,19 @@ +show-more = Прикажи још { $more } +clear-all = Очисти сва обавештења +notification-settings = Подешавања обавештења... +no-notifications = Без обавештења +do-not-disturb = Не узнемиравај +show-less = Прикажи мање +clear-group = Очисти групу +hours-ago = + { $duration -> + [0] Управо сада + [one] Пре 1 сата + *[other] Пре { $duration } сати + } +minutes-ago = + { $duration -> + [0] Управо сада + [one] Пре 1 минута + *[other] Пре { $duration } минута + } diff --git a/cosmic-applet-notifications/src/lib.rs b/cosmic-applet-notifications/src/lib.rs index b122988b..438696b9 100644 --- a/cosmic-applet-notifications/src/lib.rs +++ b/cosmic-applet-notifications/src/lib.rs @@ -16,18 +16,18 @@ use cosmic::{ Alignment, Length, Subscription, advanced::text::{Ellipsize, EllipsizeHeightLimit}, platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup}, - widget::{self, column, row}, + widget::{self, column, rich_text, row}, window, }, surface, theme, - widget::{Column, button, cards, container, divider, icon, scrollable, text, toggler}, + widget::{Column, button, cards, container, divider, icon, scrollable, space, text, toggler}, }; use cosmic::iced::futures::executor::block_on; use cosmic_notifications_config::NotificationsConfig; -use cosmic_notifications_util::{ActionId, Image, Notification}; -use std::{borrow::Cow, collections::HashMap}; +use cosmic_notifications_util::{ActionId, Image, Notification, markup}; +use std::{borrow::Cow, collections::HashMap, path::PathBuf, sync::LazyLock}; use subscriptions::notifications::{self, NotificationsAppletProxy}; use tokio::sync::mpsc::Sender; use tracing::info; @@ -65,7 +65,6 @@ impl Notifications { } #[derive(Debug, Clone)] -#[allow(dead_code)] enum Message { TogglePopup, CloseRequested(window::Id), @@ -280,7 +279,7 @@ impl cosmic::Application for Notifications { } } Message::CardsToggled(name, expanded) => { - let _id = if let Some((id, _, n_expanded, ..)) = self + let id = if let Some((id, _, n_expanded, ..)) = self .cards .iter_mut() .find(|c| c.1.iter().any(|notif| name == notif.app_name)) @@ -457,8 +456,11 @@ impl cosmic::Application for Notifications { column![ text::body(n.summary.lines().next().unwrap_or_default()) .width(Length::Fill), - text::caption(n.body.lines().next().unwrap_or_default()) - .width(Length::Fill) + Element::from( + rich_text(markup::html_to_spans(&n.body)) + .size(12.0) + .width(Length::Fill) + ) ] ) .width(Length::Fill), diff --git a/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl index e69de29b..2c45ddba 100644 --- a/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl +++ b/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl @@ -0,0 +1,2 @@ +cancel = Cancel·lar +confirm = Confirmar diff --git a/cosmic-applet-power/i18n/el/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/el/cosmic_applet_power.ftl index 41e6b281..bc5a945c 100644 --- a/cosmic-applet-power/i18n/el/cosmic_applet_power.ftl +++ b/cosmic-applet-power/i18n/el/cosmic_applet_power.ftl @@ -4,3 +4,33 @@ log-out = Αποσύνδεση restart = Επανεκκίνηση suspend = Αναστολή confirm = Επιβεβαίωση +confirm-button = + { $action -> + [restart] { restart } + [suspend] { suspend } + [shutdown] Τερματισμός + [log-out] { log-out } + *[other] { confirm } + } +power = Ενέργεια +confirm-body = + Θα εκτελεστεί αυτόματα { $action -> + [restart] επανεκκίνηση + [suspend] αναστολή + [shutdown] τερματισμός + [lock-screen] κλείδωμα της οθόνης + [log-out] αποσύνδεση + *[other] η επιλεγμένη ενέργεια + } του συστήματος σε { $countdown } δευτερόλεπτα. +lock-screen = Κλείδωμα οθόνης +log-out-shortcut = Super + Shift + Escape +settings = Ρυθμίσεις... +lock-screen-shortcut = Super + Escape +confirm-title = + { $action -> + [restart] { restart } + [suspend] { suspend } + [shutdown] { shutdown } + [log-out] Έξοδος από όλες τις εφαρμογές και αποσύνδεση + *[other] Εφαρμογή της επιλεγμένης ενέργειας + } τώρα; diff --git a/cosmic-applet-power/i18n/lo/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/lo/cosmic_applet_power.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-power/i18n/sr/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/sr/cosmic_applet_power.ftl index e69de29b..800b2900 100644 --- a/cosmic-applet-power/i18n/sr/cosmic_applet_power.ftl +++ b/cosmic-applet-power/i18n/sr/cosmic_applet_power.ftl @@ -0,0 +1,36 @@ +power = Напајање +lock-screen = Закључај екран +shutdown = Угаси +log-out = Одјава +restart = Поново покрени +log-out-shortcut = Супер + Shift + Esc +cancel = Откажи +suspend = Обустави +confirm = Потврди +settings = Подешавања... +lock-screen-shortcut = Супер + Esc +confirm-button = + { $action -> + [restart] { restart } + [suspend] { suspend } + [shutdown] Искључи + [log-out] { log-out } + *[other] { confirm } + } +confirm-body = + Систем ће { $action -> + [restart] поново покренути + [suspend] обуставити + [shutdown] искључити + [lock-screen] закључати екран + [log-out] одјавити се + *[other] применити изабрану радњу + } самостално за { $countdown } секунде. +confirm-title = + { $action -> + [restart] { restart } + [suspend] { suspend } + [shutdown] { shutdown } + [log-out] Затвори све програме и одјави се + *[other] Примени изабрану радњу + } сада? diff --git a/cosmic-applet-tiling/i18n/el/cosmic_applet_tiling.ftl b/cosmic-applet-tiling/i18n/el/cosmic_applet_tiling.ftl index e69de29b..9c9d7e68 100644 --- a/cosmic-applet-tiling/i18n/el/cosmic_applet_tiling.ftl +++ b/cosmic-applet-tiling/i18n/el/cosmic_applet_tiling.ftl @@ -0,0 +1,20 @@ +arrow-keys = βέλη +move-window = Μετακίνηση παραθύρου +shift = Shift +super = Super +new-workspace = Συμπεριφορά νέων χώρων εργασίας +tiled = Παράθεση +active-hint = Ένδειξη ενεργού παραθύρου +navigate-windows = Πλοήγηση στα παράθυρα +toggle-floating-window = Εναλλαγή αιώρησης παραθύρων +all-workspaces = Όλοι οι χώροι εργασίας +per-workspace = Ανά χώρο εργασίας +autotile-behavior = Παράθεση παραθύρων στους χώρους εργασίας +tile-current = Παράθεση στον τρέχοντα χώρο εργασίας +floating = Αιώρηση +gaps = Κενά +tile-windows = Αυτόματη παράθεση παραθύρων +view-all-shortcuts = Προβολή όλων των συντομεύσεων... +shortcuts = Συντομεύσεις +floating-window-exceptions = Εξαιρέσεις αιωρούμενων παραθύρων... +window-management-settings = Ρυθμίσεις διαχείρισης παραθύρων... diff --git a/cosmic-applet-tiling/i18n/lo/cosmic_applet_tiling.ftl b/cosmic-applet-tiling/i18n/lo/cosmic_applet_tiling.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-tiling/i18n/sr/cosmic_applet_tiling.ftl b/cosmic-applet-tiling/i18n/sr/cosmic_applet_tiling.ftl index e69de29b..394e8fd9 100644 --- a/cosmic-applet-tiling/i18n/sr/cosmic_applet_tiling.ftl +++ b/cosmic-applet-tiling/i18n/sr/cosmic_applet_tiling.ftl @@ -0,0 +1,20 @@ +arrow-keys = стрелице +tiled = Поплочано +active-hint = Активна помоћ +navigate-windows = Крећите се прозорима +toggle-floating-window = Окини пловни прозор +all-workspaces = Сви радни простори +per-workspace = По радном простору +autotile-behavior = Поплочај прозоре на радним просторима +tile-current = Поплочај тренутни радни простор +floating = Плутајуће +gaps = Размаци +move-window = Премести прозор +tile-windows = Самостално поплочај прозоре +view-all-shortcuts = Прикажи све пречице... +shortcuts = Пречице +shift = Shift +floating-window-exceptions = Изузеци за пловне прозоре... +super = Супер +window-management-settings = Подешавања за управљање прозорима... +new-workspace = Понашање новог радног простора diff --git a/cosmic-applet-time/i18n/el/cosmic_applet_time.ftl b/cosmic-applet-time/i18n/el/cosmic_applet_time.ftl index e69de29b..1e7405f3 100644 --- a/cosmic-applet-time/i18n/el/cosmic_applet_time.ftl +++ b/cosmic-applet-time/i18n/el/cosmic_applet_time.ftl @@ -0,0 +1 @@ +datetime-settings = Ρυθμίσεις ημερομηνίας, ώρας και ημερολογίου... diff --git a/cosmic-applet-time/i18n/lo/cosmic_applet_time.ftl b/cosmic-applet-time/i18n/lo/cosmic_applet_time.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-time/i18n/sr/cosmic_applet_time.ftl b/cosmic-applet-time/i18n/sr/cosmic_applet_time.ftl index e69de29b..014ee726 100644 --- a/cosmic-applet-time/i18n/sr/cosmic_applet_time.ftl +++ b/cosmic-applet-time/i18n/sr/cosmic_applet_time.ftl @@ -0,0 +1 @@ +datetime-settings = Датум, време и подешавања календара... diff --git a/cosmic-applet-workspaces/i18n/el/cosmic_applet_workspaces.ftl b/cosmic-applet-workspaces/i18n/el/cosmic_applet_workspaces.ftl index e69de29b..84c57d03 100644 --- a/cosmic-applet-workspaces/i18n/el/cosmic_applet_workspaces.ftl +++ b/cosmic-applet-workspaces/i18n/el/cosmic_applet_workspaces.ftl @@ -0,0 +1 @@ +cosmic-applet-workspaces = Χώροι εργασίας COSMIC diff --git a/cosmic-applet-workspaces/i18n/lo/cosmic_applet_workspaces.ftl b/cosmic-applet-workspaces/i18n/lo/cosmic_applet_workspaces.ftl new file mode 100644 index 00000000..e69de29b diff --git a/cosmic-applet-workspaces/i18n/sr/cosmic_applet_workspaces.ftl b/cosmic-applet-workspaces/i18n/sr/cosmic_applet_workspaces.ftl index e69de29b..98c21cf2 100644 --- a/cosmic-applet-workspaces/i18n/sr/cosmic_applet_workspaces.ftl +++ b/cosmic-applet-workspaces/i18n/sr/cosmic_applet_workspaces.ftl @@ -0,0 +1 @@ +cosmic-applet-workspaces = КОСМИК радни простори diff --git a/cosmic-panel-button/src/lib.rs b/cosmic-panel-button/src/lib.rs index cb882d5d..132e5dd5 100644 --- a/cosmic-panel-button/src/lib.rs +++ b/cosmic-panel-button/src/lib.rs @@ -123,11 +123,15 @@ impl cosmic::Application for Button { fn update(&mut self, message: Msg) -> app::Task { match message { Msg::Press => { - let _ = Command::new("sh") + if let Ok(mut child) = Command::new("sh") .arg("-c") - .arg(&self.desktop.exec) + .arg(format!("exec {}", self.desktop.exec)) .spawn() - .unwrap(); + { + std::thread::spawn(move || { + let _ = child.wait(); + }); + } } Msg::ConfigUpdated(conf) => { self.config = conf diff --git a/debian/changelog b/debian/changelog index e3d8e02e..147363a2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cosmic-applets (1.0.12) noble; urgency=medium + + * Update changelog + + -- Michael Murphy Tue, 28 Apr 2026 15:11:17 +0200 + cosmic-applets (1.0.2) noble; urgency=medium [ Ashley Wulber ] diff --git a/i18n/ca/desktop_entries.ftl b/i18n/ca/desktop_entries.ftl index e69de29b..8e680471 100644 --- a/i18n/ca/desktop_entries.ftl +++ b/i18n/ca/desktop_entries.ftl @@ -0,0 +1 @@ +cosmic-app-list = Safata d'Aplicacions diff --git a/i18n/el/desktop_entries.ftl b/i18n/el/desktop_entries.ftl index e69de29b..d5257105 100644 --- a/i18n/el/desktop_entries.ftl +++ b/i18n/el/desktop_entries.ftl @@ -0,0 +1,51 @@ +cosmic-app-list = Περιοχή εφαρμογών +cosmic-app-list-comment = Εκκίνηση καρφιτσωμένων εφαρμογών και διαχείριση ανοικτών παραθύρων +cosmic-applet-a11y = Προσβασιμότητα +cosmic-applet-audio = Ήχος +cosmic-applet-bluetooth = Bluetooth +cosmic-applet-bluetooth-comment = Διαχείριση συσκευών Bluetooth +cosmic-applet-minimize = Ελαχιστοποιημένα παράθυρα +cosmic-applet-minimize-comment = Διαχείριση ελαχιστοποιημένων παραθύρων +cosmic-applet-network = Δίκτυο +cosmic-applet-network-comment = Διαχείριση συνδέσεων δικτύου +cosmic-applet-time = Ημερομηνία, ώρα και ημερολόγιο +cosmic-applet-workspaces = Αριθμημένοι χώροι εργασίας +cosmic-panel-workspaces-button = Κουμπί χώρων εργασίας +cosmic-applet-audio-comment = Επιλογή συσκευής ήχου, έλεγχος έντασης και στοιχεία ελέγχου πολυμέσων MPRIS +cosmic-applet-audio-keywords = Μικροεφαρμογή;Ήχος;COSMIC;Applet;Sound;Audio;MPRIS; +cosmic-applet-bluetooth-keywords = Μικροεφαρμογή;COSMIC;Applet;Bluetooth; +cosmic-applet-input-sources = Πηγές εισόδου +cosmic-applet-input-sources-comment = Εναλλαγή μεταξύ πηγών εισόδου +cosmic-applet-input-sources-keywords = Μικροεφαρμογή;Πηγή;Είσοδος;COSMIC;Applet;Input;Source; +cosmic-applet-minimize-keywords = Μικροεφαρμογή;Ελαχιστοποίηση;COSMIC;Applet;Minimize; +cosmic-applet-network-keywords = Μικροεφαρμογή;Δίκτυο;COSMIC;Applet;Network; +cosmic-applet-notifications = Κέντρο ειδοποιήσεων +cosmic-applet-notifications-comment = Διαχείριση ειδοποιήσεων και λειτουργία «Μην ενοχλείτε» +cosmic-applet-notifications-keywords = Μικροεφαρμογή;Ειδοποίηση;COSMIC;Applet;Notification; +cosmic-applet-power = Συνεδρία χρήστη +cosmic-applet-power-comment = Κλείδωμα οθόνης, αποσύνδεση, αναστολή, επανεκκίνηση και τερματισμός +cosmic-applet-power-keywords = Μικροεφαρμογή;Χρήστης;Συνεδρία;Κλείδωμα;Αποσύνδεση;Επανεκκίνηση;Τερματισμός;Αναστολή;COSMIC;Applet;User;Session;Lock;Log;Reboot;Shutdown;Suspend; +cosmic-applet-status-area = Περιοχή ειδοποιήσεων +cosmic-applet-workspaces-keywords = Μικροεφαρμογή;Χώρος;Εργασίας;COSMIC;Applet;Workspace; +cosmic-panel-app-button = Κουμπί βιβλιοθήκης εφαρμογών +cosmic-panel-workspaces-button-keywords = Μικροεφαρμογή;Χώρος;Εργασίας;Επισκόπηση;COSMIC;Applet;Workspace;Overview; +cosmic-app-list-keywords = Μικροεφαρμογή;Εφαρμογή;Περιοχή;Λίστα;Εργασία;Γραμμή;COSMIC;Applet;App;Tray;List;Task;Bar; +cosmic-applet-a11y-keywords = Μικροεφαρμογή;Προσβασιμότητα;Προσιτότητα;Οθόνη;Ανάγνωση;Αναγνώστης;Μεγεθυντικός;Φακός;Αντίθεση;Χρώμα;COSMIC;Applet;Accessibility;A11y;Screen;Reader;Magnifier;Contrast;Color; +cosmic-applet-battery = Ενέργεια και μπαταρία +cosmic-applet-battery-comment = Λειτουργίες ενέργειας και επιλογές εξοικονόμησης ενέργειας +cosmic-applet-battery-keywords = Μικροεφαρμογή;Ενέργεια;Ισχύς;Μπαταρία;COSMIC;Applet;Power;Battery; +cosmic-applet-status-area-keywords = Μικροεφαρμογή;Εφαρμογή;Ένδειξη;Ειδοποίηση;Περιοχή;Κατάσταση;COSMIC;Applet;App;Indicator;Notification;Tray;Status; +cosmic-applet-time-keywords = Μικροεφαρμογή;Ημερομηνία;Ώρα;Ημερολόγιο;COSMIC;Applet;Date;Time;Calendar; +cosmic-panel-app-button-comment = Άνοιγμα της βιβλιοθήκης εφαρμογών για εκκίνηση εγκατεστημένων εφαρμογών +cosmic-panel-app-button-keywords = Μικροεφαρμογή;Εφαρμογή;Βιβλιοθήκη;Περιοχή;COSMIC;Applet;App;Library;Tray; +cosmic-applet-a11y-comment = Διαμόρφωση των ρυθμίσεων προσβασιμότητας από τη γραμμή συστήματος +cosmic-applet-status-area-comment = Ενδείξεις εφαρμογών που ενδέχεται να εξάγουν μενού στη γραμμή συστήματος +cosmic-applet-tiling = Παράθεση +cosmic-applet-tiling-comment = Διαχείριση της ένδειξης ενεργού παραθύρου, αυτόματη παράθεση παραθύρων στον τρέχοντα χώρο εργασίας και ανά χώρο εργασίας +cosmic-applet-tiling-keywords = Μικροεφαρμογή;Παράθεση;Ένδειξη;Χώρος;Εργασίας;COSMIC;Applet;Tiling;Hint;Workspace; +cosmic-applet-time-comment = Προβολή της τρέχουσας ώρας στη γραμμή συστήματος με αναδυόμενο ημερολόγιο +cosmic-applet-workspaces-comment = Εναλλαγή μεταξύ των αριθμημένων χώρων εργασίας στη γραμμή συστήματος +cosmic-panel-launcher-button = Κουμπί μενού εκκίνησης +cosmic-panel-launcher-button-comment = Άνοιγμα του μενού εκκίνησης για αναζήτηση εφαρμογών και εκτέλεση εντολών +cosmic-panel-launcher-button-keywords = Μικροεφαρμογή;Μενού;Εκκίνηση;Εκτέλεση;COSMIC;Applet;Launcher;Runner; +cosmic-panel-workspaces-button-comment = Άνοιγμα των χώρων εργασίας για διαχείριση και εναλλαγή χώρων εργασίας diff --git a/i18n/hu/desktop_entries.ftl b/i18n/hu/desktop_entries.ftl index 8dd220f7..637e262e 100644 --- a/i18n/hu/desktop_entries.ftl +++ b/i18n/hu/desktop_entries.ftl @@ -15,20 +15,20 @@ cosmic-applet-workspaces = Számozott Munkaterületek cosmic-panel-app-button = Alkalmazáskönyvtár gomb cosmic-panel-launcher-button = Indító gomb cosmic-panel-workspaces-button = Munkaterületek gomb -cosmic-app-list-keywords = COSMIC;Kisalkalmazás;Alkalmazás;App;Tálca;Lista;Sáv; -cosmic-applet-a11y-keywords = COSMIC;Kisalkalmazás;Akadálymentesség;Akadálymentesítés;Képernyő;Olvasó;Nagyító;Szín; -cosmic-applet-audio-keywords = COSMIC;Kisalkalmazás;Hang;MPRIS; -cosmic-applet-battery-keywords = COSMIC;Kisalkalmazás;Energia;Akkumulátor; +cosmic-app-list-keywords = COSMIC;kisalkalmazás;alkalmazás;app;tálca;lista;sáv; +cosmic-applet-a11y-keywords = COSMIC;kisalkalmazás;akadálymentesség;akadálymentesítés;képernyő;olvasó;nagyító;szín; +cosmic-applet-audio-keywords = COSMIC;kisalkalmazás;hang;MPRIS; +cosmic-applet-battery-keywords = COSMIC;kisalkalmazás;energia;akkumulátor; cosmic-applet-bluetooth-comment = Bluetooth-eszközök kezelése -cosmic-applet-bluetooth-keywords = COSMIC;Kisalkalmazás;Bluetooth; -cosmic-applet-input-sources-keywords = COSMIC;Kisalkalmazás;Beviteli;Forrás; -cosmic-applet-minimize-keywords = COSMIC;Kisalkalmazás;Minimizálás; -cosmic-applet-network-keywords = COSMIC;Kisalkalmazás;Hálózat;Internet; -cosmic-applet-notifications-keywords = COSMIC;Kisalkalmazás;Értesítések; -cosmic-applet-power-keywords = COSMIC;Kisalkalmazás;Felhasználói munkamenet;Zárolás;Kijelentkezés;Újraindítás;Leállítás;Felfüggesztés; -cosmic-panel-app-button-keywords = COSMIC;Kisalkalmazás;Alkalmazás;Könyvtár;Tálca; -cosmic-panel-launcher-button-keywords = COSMIC;Kisalkalmazás;Indító;Futtató; -cosmic-panel-workspaces-button-keywords = COSMIC;Kisalkalmazás;Munkaterületek;Áttekintés; +cosmic-applet-bluetooth-keywords = COSMIC;kisalkalmazás;bluetooth; +cosmic-applet-input-sources-keywords = COSMIC;kisalkalmazás;beviteli forrás; +cosmic-applet-minimize-keywords = COSMIC;kisalkalmazás;minimizálás; +cosmic-applet-network-keywords = COSMIC;kisalkalmazás;hálózat;internet; +cosmic-applet-notifications-keywords = COSMIC;kisalkalmazás;értesítések; +cosmic-applet-power-keywords = COSMIC;kisalkalmazás;felhasználói munkamenet;zárolás;kijelentkezés;újraindítás;leállítás;felfüggesztés; +cosmic-panel-app-button-keywords = COSMIC;kisalkalmazás;alkalmazás;könyvtár;tálca; +cosmic-panel-launcher-button-keywords = COSMIC;kisalkalmazás;indító;futtató; +cosmic-panel-workspaces-button-keywords = COSMIC;kisalkalmazás;munkaterületek;áttekintés; cosmic-applet-a11y-comment = Akadálymentességi beállítások kezelése a panelen cosmic-applet-audio-comment = Hangeszköz kiválasztása, hangerőszabályozás és MPRIS médiavezérlés cosmic-applet-battery-comment = Energiamódok és energiagazdálkodási beállítások @@ -39,13 +39,13 @@ cosmic-applet-notifications-comment = Értesítések és a Ne zavarjanak kezelé cosmic-applet-power-comment = Képernyő zárolása, kijelentkezés, felfüggesztés, újraindítás és leállítás cosmic-app-list-comment = Rögzített alkalmazások indítása és a megnyitott ablakok kezelése cosmic-applet-status-area-comment = Alkalmazásjelzők, melyek menüt is megjeleníthetnek a panelen -cosmic-applet-status-area-keywords = COSMIC;Kisalkalmazás;Alkalmazás;App;Jelző;Értesítések;Tálca;Állapot; +cosmic-applet-status-area-keywords = COSMIC;kisalkalmazás;alkalmazás;app;jelző;értesítések;tálca;állapot; cosmic-applet-tiling-comment = Az aktív ablak kiemelésének, valamint az aktuális és munkaterületenkénti automatikus csempézés kezelése -cosmic-applet-tiling-keywords = COSMIC;Kisalkalmazás;Csempézés;Kiemelés;Munkaterületek; +cosmic-applet-tiling-keywords = COSMIC;kisalkalmazás;csempézés;kiemelés;munkaterületek; cosmic-applet-time-comment = Az aktuális idő megjelenítése a panelen, felugró naptárral -cosmic-applet-time-keywords = COSMIC;Kisalkalmazás;Dátum;Idő;Naptár; +cosmic-applet-time-keywords = COSMIC;kisalkalmazás;dátum;idő;naptár; cosmic-applet-workspaces-comment = Váltás számozott munkaterületek között a panelen -cosmic-applet-workspaces-keywords = COSMIC;Kisalkalmazás;Munkaterületek; +cosmic-applet-workspaces-keywords = COSMIC;kisalkalmazás;munkaterületek; cosmic-panel-app-button-comment = Az alkalmazáskönyvtár megnyitása a telepített alkalmazások indításához cosmic-panel-launcher-button-comment = Az indító megnyitása alkalmazások kereséséhez és parancsok futtatásához cosmic-panel-workspaces-button-comment = A munkaterületek áttekintőjének megnyitása munkaterületek kezeléséhez és váltásához diff --git a/i18n/lo/desktop_entries.ftl b/i18n/lo/desktop_entries.ftl new file mode 100644 index 00000000..e69de29b diff --git a/i18n/sr/desktop_entries.ftl b/i18n/sr/desktop_entries.ftl index e69de29b..10c8d1eb 100644 --- a/i18n/sr/desktop_entries.ftl +++ b/i18n/sr/desktop_entries.ftl @@ -0,0 +1,51 @@ +cosmic-app-list = Системска касета +cosmic-app-list-comment = Покрени закачене програме и управљај отвореним прозорима +cosmic-app-list-keywords = COSMIC;Applet;App;Tray;List;Task;Bar;Космик;Програмчић;Програм;Касета;Списак;Задатак;Трака;kosmik;programčić;program;kaseta;spisak;zadatak;traka; +cosmic-applet-a11y = Приступачност +cosmic-applet-a11y-comment = Подеси подешавања приступачности из траке +cosmic-applet-a11y-keywords = COSMIC;Applet;Accessibility;A11y;Screen;Reader;Magnifier;Contrast;Color;Космик;Програмчић;Приступачност;А11ј;Екран;Читач;Лупа;Контраст;Боја;kosmik;programčić;pristupačnost;a11j;ekran;čitač;lupa;kontrast;boja; +cosmic-applet-audio = Звук +cosmic-applet-audio-comment = Избор уређаја звука, управљање јачином звука и MPRIS контроле медија +cosmic-applet-audio-keywords = COSMIC;Applet;Sound;Audio;MPRIS;Космик;Програмчић;Аудио;Звук;Јачина звука;МПРИС;Медија;kosmik;programčić;audio;zvuk;jačina zvuka;medija; +cosmic-applet-battery = Напајање и батерија +cosmic-applet-battery-comment = Режими напајања и могућности уштеде енергије +cosmic-applet-battery-keywords = COSMIC;Applet;Power;Battery;Космик;Програмчић;Напајање;Батерија;kosmik;programčić;napajanje;baterija; +cosmic-applet-bluetooth = Блутут +cosmic-applet-bluetooth-comment = Управљај Блутут уређајима +cosmic-applet-bluetooth-keywords = COSMIC;Applet;Bluetooth;Космик;Програмчић;Блутут;kosmik;programčić;blutut; +cosmic-applet-input-sources = Извори уноса +cosmic-applet-input-sources-comment = Пребацивање између извора уноса +cosmic-applet-input-sources-keywords = COSMIC;Applet;Input;Source;Космик;Програмчић;Унос;Извор;kosmik;programčić;unos;izvor; +cosmic-applet-minimize = Умањени прозори +cosmic-applet-minimize-comment = Управљај умањеним прозорима +cosmic-applet-minimize-keywords = COSMIC;Applet;Minimize;Космик;Програмчић;Умањи;kosmik;programčić;umanji; +cosmic-applet-network = Мрежа +cosmic-applet-network-comment = Управљај мрежним везама +cosmic-applet-network-keywords = COSMIC;Applet;Network;Космик;Програмчић;Мрежа;kosmik;programčić;mreža; +cosmic-applet-notifications = Центар за обавештења +cosmic-applet-notifications-comment = Управљај обавештењима и режимом „Не узнемиравај“ +cosmic-applet-notifications-keywords = COSMIC;Applet;Notification;Космик;Програмчић;Обавештење;kosmik;programčić;obaveštenje; +cosmic-applet-power = Корисничка сесија +cosmic-applet-power-comment = Закључај екран, одјави се, обустави, поново покрени и искључи +cosmic-applet-power-keywords = COSMIC;Applet;User;Session;Lock;Log;Reboot;Shutdown;Suspend;Космик;Програмчић;Корисник;Сесија;Закључавање;Одјава;Поновно покретање;Искључивање;Обустава;kosmik;programčić;korisnik;sesija;zaključavanje;odjava;ponovno pokretanje;isključivanje;obustava; +cosmic-applet-status-area = Обавештајна касета +cosmic-applet-status-area-comment = Показивачи програма који могу извести изборнике у површ +cosmic-applet-status-area-keywords = COSMIC;Applet;App;Indicator;Notification;Tray;Status;Космик;Програмчић;Програм;Показатељ;Обавештење;Пољце;Статус;kosmik;programčić;program;pokazatelj;obaveštenje;poljce;status; +cosmic-applet-tiling = Поплочавање +cosmic-applet-tiling-comment = Управљај активним саветом, тренутним и самопоплочавањем по радном простору +cosmic-applet-tiling-keywords = COSMIC;Applet;Tiling;Hint;Workspace;Космик;Програмчић;Поплочавање;Помоћ;Радни простор;kosmik;programčić;popločavanje;pomoć;radni prostor; +cosmic-applet-time = Датум, време и календар +cosmic-applet-time-comment = Приказује тренутно време у површи са искакућим календаром +cosmic-applet-time-keywords = COSMIC;Applet;Date;Time;Calendar;Космик;Програмчић;Датум;Време;Календар;kosmik;programčić;datum;vreme;kalendar; +cosmic-applet-workspaces = Радни простори обележени бројевима +cosmic-applet-workspaces-comment = Пребаците између радних простора обележених бројевима у траци +cosmic-applet-workspaces-keywords = COSMIC;Applet;Workspace;Космик;Програмчић;радни простор;kosmik;programčić;radni prostor; +cosmic-panel-app-button = Дугме за библиотеку програма +cosmic-panel-app-button-comment = Отвори библиотеку програма за покретање инсталираних програма +cosmic-panel-app-button-keywords = COSMIC;Applet;App;Library;Tray;Космик;Програмчић;Програм;Библиотека;Касета;kosmik;programčić;program;biblioteka;kaseta; +cosmic-panel-launcher-button = Дугме покретача +cosmic-panel-launcher-button-comment = Отвори покретач да бисте претражили програме и покренули наредбе +cosmic-panel-launcher-button-keywords = COSMIC;Applet;Launcher;Runner;Космик;Програмчић;Покретач;Покретач;kosmik;programčić;pokretač;pokretač; +cosmic-panel-workspaces-button = Дугме радних простора +cosmic-panel-workspaces-button-comment = Отвори преглед радних простора за управљање и пребацивање радних простора +cosmic-panel-workspaces-button-keywords = COSMIC;Applet;Workspace;Overview;Космик;Програмчић;радни простор;Преглед;kosmik;programčić;radni prostor;pregled; diff --git a/i18n/uk/desktop_entries.ftl b/i18n/uk/desktop_entries.ftl index b6b177b5..c6088440 100644 --- a/i18n/uk/desktop_entries.ftl +++ b/i18n/uk/desktop_entries.ftl @@ -30,9 +30,9 @@ cosmic-applet-input-sources-comment = Перемикання джерел вве cosmic-applet-input-sources-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Джерело;Введення;Розкладка;Клавіатура; cosmic-applet-minimize-comment = Керування згорнутими вікнами cosmic-applet-minimize-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Згорнути;Згорнуті;Вікна;Вікно; -cosmic-applet-network-comment = Керування мережевими підключеннями +cosmic-applet-network-comment = Керування мережевими з’єднаннями cosmic-applet-network-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Мережа;Інтернет; -cosmic-applet-notifications-comment = Керування сповіщеннями та режимом Не турбувати +cosmic-applet-notifications-comment = Керування сповіщеннями та режимом «Не турбувати» cosmic-applet-notifications-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Сповіщення; cosmic-applet-power-comment = Блокування екрана, вихід із сеансу, призупинення, перезапуск і вимкнення cosmic-applet-power-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Сеанс;Користувач;Блокування;Вихід;Перезапуск;Вимкнення;Призупинення;Сон; diff --git a/redeploy.sh b/redeploy.sh index 7138a806..686bf3cb 100755 --- a/redeploy.sh +++ b/redeploy.sh @@ -11,7 +11,7 @@ set -euo pipefail -REPO="/home/lionel/Devels/cosmic-applets" +REPO="/home/lionel/Projets/COSMIC/cosmic-applets" TARGETS=( "cosmic-applets" "cosmic-app-list"