From 91daff1453dad3506e3d9c3d7591ec2921823f0f Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Fri, 22 Nov 2024 00:42:00 +0100 Subject: [PATCH] feat: add default applications page --- Cargo.lock | 220 ++++++---- Cargo.toml | 2 +- cosmic-settings/Cargo.toml | 4 + cosmic-settings/src/app.rs | 21 +- cosmic-settings/src/main.rs | 3 + cosmic-settings/src/pages/bluetooth/mod.rs | 33 +- .../src/pages/desktop/appearance/mod.rs | 46 +- .../src/pages/desktop/panel/applets_inner.rs | 2 +- .../src/pages/desktop/wallpaper/mod.rs | 14 +- cosmic-settings/src/pages/display/mod.rs | 20 +- .../src/pages/input/keyboard/mod.rs | 4 +- .../pages/input/keyboard/shortcuts/common.rs | 2 +- .../pages/input/keyboard/shortcuts/custom.rs | 2 +- .../src/pages/input/keyboard/shortcuts/mod.rs | 20 +- cosmic-settings/src/pages/mod.rs | 2 + cosmic-settings/src/pages/networking/mod.rs | 4 +- .../src/pages/networking/vpn/mod.rs | 20 +- cosmic-settings/src/pages/networking/wifi.rs | 6 +- cosmic-settings/src/pages/networking/wired.rs | 10 +- cosmic-settings/src/pages/sound.rs | 8 +- .../src/pages/system/default_apps.rs | 414 ++++++++++++++++++ cosmic-settings/src/pages/system/mod.rs | 6 + cosmic-settings/src/pages/time/date.rs | 6 +- cosmic-settings/src/pages/time/region.rs | 6 +- i18n/en/cosmic_settings.ftl | 14 + 25 files changed, 683 insertions(+), 206 deletions(-) create mode 100644 cosmic-settings/src/pages/system/default_apps.rs diff --git a/Cargo.lock b/Cargo.lock index 8537900b..a694bb8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -575,7 +575,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -610,7 +610,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -760,7 +760,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -885,7 +885,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -956,7 +956,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -979,9 +979,9 @@ checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "calendrical_calculations" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec493b209a1b81fa32312d7ceca1b547d341c7b5f16a3edbf32b1d8b455bbdf" +checksum = "f27ca2b6e2f7d75f43e001ded6f25e79b80bded5abbe764cbdf78c25a3051f4b" dependencies = [ "core_maths", "displaydoc", @@ -1135,7 +1135,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -1169,7 +1169,7 @@ version = "0.2.2" source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-0.13#a83bf83784276aaa882ef13555295a2ad9edd265" dependencies = [ "dnd", - "mime", + "mime 0.1.0", "smithay-clipboard", ] @@ -1471,7 +1471,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1493,7 +1493,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "quote", "syn 1.0.109", @@ -1522,6 +1522,17 @@ dependencies = [ "serde", ] +[[package]] +name = "cosmic-mime-apps" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-mime-apps#3ac0e3d926f26c6f777111f530e613d3dfc75ac4" +dependencies = [ + "freedesktop-desktop-entry", + "mime 0.3.17", + "quick-xml 0.37.1", + "xdg", +] + [[package]] name = "cosmic-panel-config" version = "0.1.0" @@ -1595,6 +1606,7 @@ dependencies = [ "cosmic-config", "cosmic-dbus-networkmanager", "cosmic-idle-config", + "cosmic-mime-apps", "cosmic-panel-config", "cosmic-randr", "cosmic-randr-shell", @@ -1623,6 +1635,7 @@ dependencies = [ "itoa", "libcosmic", "locale1", + "mime 0.3.17", "notify", "once_cell", "regex", @@ -1651,7 +1664,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-daemon#2f17f33875315a4cf463f82c5dceca4d83a75bfd" +source = "git+https://github.com/pop-os/cosmic-settings-daemon#f079ab7f98132787de385934915547f333dfbddc" dependencies = [ "cosmic-config", "serde", @@ -1764,7 +1777,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "almost", "cosmic-config", @@ -1780,9 +1793,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1945,7 +1958,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -1967,7 +1980,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2051,7 +2064,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2109,7 +2122,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2136,7 +2149,7 @@ version = "0.1.0" source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-0.13#a83bf83784276aaa882ef13555295a2ad9edd265" dependencies = [ "bitflags 2.6.0", - "mime", + "mime 0.1.0", "raw-window-handle", "smithay-client-toolkit", "smithay-clipboard", @@ -2231,7 +2244,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2549,7 +2562,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2706,7 +2719,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -2974,9 +2987,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hassle-rs" @@ -3096,7 +3109,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.89", "unic-langid", ] @@ -3110,7 +3123,7 @@ dependencies = [ "i18n-config", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -3139,7 +3152,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "dnd", "iced_accessibility", @@ -3149,7 +3162,7 @@ dependencies = [ "iced_widget", "iced_winit", "image 0.24.9", - "mime", + "mime 0.1.0", "thiserror", "window_clipboard", ] @@ -3157,7 +3170,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "accesskit", "accesskit_winit", @@ -3166,7 +3179,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "bitflags 2.6.0", "bytes", @@ -3174,7 +3187,7 @@ dependencies = [ "glam", "iced_accessibility", "log", - "mime", + "mime 0.1.0", "num-traits", "once_cell", "palette", @@ -3191,7 +3204,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "futures", "iced_core", @@ -3217,7 +3230,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "bitflags 2.6.0", "bytemuck", @@ -3239,7 +3252,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -3251,7 +3264,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "bytes", "dnd", @@ -3267,7 +3280,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "bytemuck", "cosmic-text", @@ -3283,7 +3296,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "as-raw-xcb-connection", "bitflags 2.6.0", @@ -3314,7 +3327,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "dnd", "iced_accessibility", @@ -3333,7 +3346,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "dnd", "iced_accessibility", @@ -3706,7 +3719,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -3875,7 +3888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "serde", ] @@ -3944,7 +3957,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -4316,7 +4329,7 @@ checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#525a14cfb1a735779a9fe970ff1726c8dbf1b217" +source = "git+https://github.com/pop-os/libcosmic#a9c7c3cdbfd586b090437647e3d380977780d520" dependencies = [ "apply", "ashpd 0.9.2", @@ -4476,9 +4489,9 @@ checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "litrs" @@ -4708,7 +4721,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -4719,6 +4732,12 @@ dependencies = [ "smithay-clipboard", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4965,7 +4984,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5026,7 +5045,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5333,7 +5352,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5379,7 +5398,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5478,7 +5497,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5513,7 +5532,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5682,14 +5701,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -5702,7 +5721,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "version_check", "yansi", ] @@ -5746,7 +5765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -5793,6 +5812,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f22f29bdff3987b4d8632ef95fd6424ec7e4e0a57e2f4fc63e489e75357f6a03" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.37" @@ -6157,7 +6185,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.87", + "syn 2.0.89", "walkdir", ] @@ -6365,7 +6393,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -6389,7 +6417,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -6428,7 +6456,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -6733,7 +6761,7 @@ dependencies = [ [[package]] name = "superblock" version = "0.1.0" -source = "git+https://github.com/serpent-os/blsforme.git#77c30adbfbc09cb54cd9f781fb7e5e5a563de3bf" +source = "git+https://github.com/serpent-os/blsforme.git#3c1ca74c220b2297338a2c4be8da55dcf3f438e8" dependencies = [ "log", "thiserror", @@ -6780,9 +6808,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -6797,7 +6825,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -6826,7 +6854,7 @@ dependencies = [ [[package]] name = "system" version = "0.1.0" -source = "git+https://github.com/serpent-os/lichen#f44a7c9e6faf48407d5d60b836517f40bae7b98b" +source = "git+https://github.com/serpent-os/lichen#ea0ed88d444068aeffbf505f1379dbc3d9757975" dependencies = [ "fs-err", "futures", @@ -6939,7 +6967,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -7102,7 +7130,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -7203,7 +7231,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -7408,9 +7436,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -7570,7 +7598,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "wasm-bindgen-shared", ] @@ -7604,7 +7632,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7725,7 +7753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.36.2", "quote", ] @@ -7934,7 +7962,7 @@ dependencies = [ "clipboard_wayland", "clipboard_x11", "dnd", - "mime", + "mime 0.1.0", "raw-window-handle", "thiserror", ] @@ -8019,7 +8047,7 @@ checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -8030,7 +8058,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -8041,7 +8069,7 @@ checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -8052,7 +8080,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -8512,9 +8540,9 @@ checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -8524,13 +8552,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "synstructure", ] @@ -8632,7 +8660,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "zvariant_utils 2.1.0", ] @@ -8682,27 +8710,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "synstructure", ] @@ -8742,7 +8770,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] [[package]] @@ -8819,7 +8847,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", "zvariant_utils 2.1.0", ] @@ -8842,5 +8870,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.89", ] diff --git a/Cargo.toml b/Cargo.toml index 5f149b5c..626a5af9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ inherits = "release" debug = true [profile.release] -lto = "thin" +# lto = "thin" # [patch.'https://github.com/smithay/client-toolkit/'] # smithay-client-toolkit = { git = "https://github.com/smithay/client-toolkit//", rev = "c583de8" } diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index cc2f7ea3..6ec003d3 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -42,6 +42,7 @@ itertools = "0.13.0" itoa = "1.0.11" libcosmic.workspace = true locale1 = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true } +mime-apps = { package = "cosmic-mime-apps", git = "https://github.com/pop-os/cosmic-mime-apps", optional = true } notify = "6.1.1" once_cell = "1.19.0" regex = "1.10.6" @@ -67,6 +68,7 @@ zbus = { version = "4.4.0", features = ["tokio"], optional = true } ustr = "1.0.0" fontdb = "0.16.2" fixed_decimal = "0.5.6" +mime = "0.3.17" [dependencies.cosmic-settings-subscriptions] git = "https://github.com/pop-os/cosmic-settings-subscriptions" @@ -96,6 +98,7 @@ linux = [ "page-about", "page-bluetooth", "page-date", + "page-default-apps", "page-input", "page-networking", "page-power", @@ -111,6 +114,7 @@ linux = [ page-about = ["dep:cosmic-settings-system", "dep:hostname1-zbus", "dep:zbus"] page-bluetooth = ["dep:bluez-zbus", "dep:zbus"] page-date = ["dep:timedate-zbus", "dep:zbus"] +page-default-apps = ["dep:mime-apps"] page-input = [ "dep:cosmic-comp-config", "dep:cosmic-settings-config", diff --git a/cosmic-settings/src/app.rs b/cosmic-settings/src/app.rs index affa96ea..612de777 100644 --- a/cosmic-settings/src/app.rs +++ b/cosmic-settings/src/app.rs @@ -51,7 +51,6 @@ use desktop::{ use event::wayland; use page::Entity; use std::collections::BTreeSet; -use std::time::Duration; use std::{borrow::Cow, str::FromStr}; #[allow(clippy::struct_excessive_bools)] @@ -82,6 +81,8 @@ impl SettingsApp { PageCommands::Bluetooth => self.pages.page_id::(), #[cfg(feature = "page-date")] PageCommands::DateTime => self.pages.page_id::(), + #[cfg(feature = "page-default-apps")] + PageCommands::DefaultApps => self.pages.page_id::(), PageCommands::Desktop => self.pages.page_id::(), PageCommands::Displays => self.pages.page_id::(), #[cfg(feature = "wayland")] @@ -212,10 +213,7 @@ impl cosmic::Application for SettingsApp { } .unwrap_or(desktop_id); - ( - app, - cosmic::command::message(Message::DelayedInit(active_id)), - ) + (app, cosmic::task::message(Message::DelayedInit(active_id))) } fn nav_model(&self) -> Option<&nav_bar::Model> { @@ -389,6 +387,13 @@ impl cosmic::Application for SettingsApp { } } + #[cfg(feature = "page-default-apps")] + crate::pages::Message::DefaultApps(message) => { + if let Some(page) = self.pages.page_mut::() { + return page.update(message).map(Into::into); + } + } + crate::pages::Message::Desktop(message) => { page::update!(self.pages, message, desktop::Page); } @@ -718,7 +723,7 @@ impl cosmic::Application for SettingsApp { // It is necessary to delay init to allow time for the page sender to be initialized Message::DelayedInit(active_id) => { if self.page_sender.is_none() { - return cosmic::command::message(Message::DelayedInit(active_id)); + return cosmic::task::message(Message::DelayedInit(active_id)); } return self.activate_page(active_id); @@ -832,7 +837,7 @@ impl SettingsApp { Task::batch(vec![ leave_task, page_task, - cosmic::command::future(async { Message::SetWindowTitle }), + cosmic::task::future(async { Message::SetWindowTitle }), ]) } @@ -1005,7 +1010,7 @@ impl SettingsApp { if tasks.is_empty() { Task::none() } else { - cosmic::command::batch(tasks) + cosmic::task::batch(tasks) .map(Message::PageMessage) .map(Into::into) } diff --git a/cosmic-settings/src/main.rs b/cosmic-settings/src/main.rs index 0433c810..0f95bb37 100644 --- a/cosmic-settings/src/main.rs +++ b/cosmic-settings/src/main.rs @@ -49,6 +49,9 @@ pub enum PageCommands { /// Date & Time settings page #[cfg(feature = "page-date")] DateTime, + /// Default application associations + #[cfg(feature = "page-default-apps")] + DefaultApps, /// Desktop settings page Desktop, /// Displays settings page diff --git a/cosmic-settings/src/pages/bluetooth/mod.rs b/cosmic-settings/src/pages/bluetooth/mod.rs index 02588cb7..e5e421a3 100644 --- a/cosmic-settings/src/pages/bluetooth/mod.rs +++ b/cosmic-settings/src/pages/bluetooth/mod.rs @@ -78,7 +78,7 @@ impl page::Page for Page { sender: tokio::sync::mpsc::Sender, ) -> cosmic::Task { // TODO start stream for new device - cosmic::command::future(async move { + cosmic::task::future(async move { match zbus::Connection::system().await { Ok(connection) => Message::DBusConnect(connection, sender), Err(why) => Message::DBusError(why.to_string()), @@ -261,7 +261,7 @@ impl Page { Active::Disabling }; self.update_status(); - return cosmic::command::future(change_adapter_status( + return cosmic::task::future(change_adapter_status( connection.clone(), path, active, @@ -276,7 +276,7 @@ impl Page { } else { Active::Disabling }; - cosmic::command::future(change_adapter_status( + cosmic::task::future(change_adapter_status( connection.clone(), path.clone(), active, @@ -284,7 +284,7 @@ impl Page { }) .collect(); self.update_status(); - return cosmic::command::batch(tasks); + return cosmic::task::batch(tasks); } tracing::warn!("No DBus connection ready"); } @@ -306,7 +306,7 @@ impl Page { )); } - return cosmic::command::future(async move { + return cosmic::task::future(async move { let result: zbus::Result> = async { futures::future::join_all( bluez_zbus::get_adapters(&connection) @@ -342,7 +342,7 @@ impl Page { self.update_status(); if self.selected_adapter.is_none() && self.adapters.len() == 1 { - return cosmic::command::message(Message::SelectAdapter( + return cosmic::task::message(Message::SelectAdapter( self.adapters.keys().next().cloned(), )); } @@ -365,7 +365,7 @@ impl Page { tracing::debug!("Adapter {} added", adapter.address); self.adapters.insert(path.clone(), adapter); if self.selected_adapter.is_none() { - return cosmic::command::message(Message::SelectAdapter(Some(path))); + return cosmic::task::message(Message::SelectAdapter(Some(path))); } } Message::UpdatedAdapter(path, update) => { @@ -381,7 +381,7 @@ impl Page { && existing.scanning == Active::Disabled => { existing.scanning = Active::Enabling; - return cosmic::command::future(start_discovery(connection, path)); + return cosmic::task::future(start_discovery(connection, path)); } _ => {} } @@ -412,19 +412,20 @@ impl Page { if let Some(connection) = self.connection.as_ref() { let connection = connection.clone(); if let Some((path, adapter)) = self.get_selected_adapter_mut() { - let mut fut: Vec> = vec![cosmic::command::future( - get_devices(connection.clone(), path.clone()), - )]; + let mut fut: Vec> = vec![cosmic::task::future(get_devices( + connection.clone(), + path.clone(), + ))]; if adapter.enabled == Active::Enabled && adapter.scanning == Active::Disabled { - fut.push(cosmic::command::future(start_discovery( + fut.push(cosmic::task::future(start_discovery( connection, path.clone(), ))); } - return cosmic::command::batch(fut); + return cosmic::task::batch(fut); } } else { tracing::warn!("No DBus connection ready"); @@ -440,7 +441,7 @@ impl Page { let connection = connection.clone(); if let Some(device) = self.devices.get_mut(&path) { device.enabled = Active::Disabling; - return cosmic::command::future(forget_device(connection, path.clone())); + return cosmic::task::future(forget_device(connection, path.clone())); } } else { tracing::warn!("No DBus connection ready"); @@ -458,7 +459,7 @@ impl Page { return cosmic::Task::none(); } device.enabled = Active::Enabling; - return cosmic::command::future(connect_device(connection, path)); + return cosmic::task::future(connect_device(connection, path)); } } else { tracing::warn!("No DBus connection ready"); @@ -474,7 +475,7 @@ impl Page { return cosmic::Task::none(); } device.enabled = Active::Disabling; - return cosmic::command::future(disconnect_device(connection, path)); + return cosmic::task::future(disconnect_device(connection, path)); } } else { tracing::warn!("No DBus connection ready"); diff --git a/cosmic-settings/src/pages/desktop/appearance/mod.rs b/cosmic-settings/src/pages/desktop/appearance/mod.rs index 05c53392..3938746d 100644 --- a/cosmic-settings/src/pages/desktop/appearance/mod.rs +++ b/cosmic-settings/src/pages/desktop/appearance/mod.rs @@ -22,7 +22,7 @@ use cosmic::iced_widget::scrollable::{Direction, Scrollbar}; use cosmic::widget::icon::{from_name, icon}; use cosmic::widget::{ button, color_picker::ColorPickerUpdate, container, flex_row, horizontal_space, radio, row, - scrollable, settings, spin_button, text, ColorPickerModel, + scrollable, settings, text, ColorPickerModel, }; use cosmic::{widget, Apply, Element, Task}; #[cfg(feature = "wayland")] @@ -387,7 +387,7 @@ impl Page { ) ), // Icon theme previews - cosmic::widget::column::with_children(vec![ + widget::column::with_children(vec![ text::heading(&*ICON_THEME).into(), flex_row( self.icon_themes @@ -424,7 +424,7 @@ impl Page { self.context_view = Some(ContextView::MonospaceFont); self.font_search.clear(); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("monospace-font").into(), )); @@ -434,7 +434,7 @@ impl Page { self.context_view = Some(ContextView::SystemFont); self.font_search.clear(); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("interface-font").into(), )); @@ -781,7 +781,7 @@ impl Page { } Message::Left => { - tasks.push(cosmic::command::message(app::Message::SetTheme( + tasks.push(cosmic::task::message(app::Message::SetTheme( cosmic::theme::system_preference(), ))); } @@ -865,7 +865,7 @@ impl Page { #[cfg(feature = "ashpd")] Message::StartImport => { - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { let res = SelectedFiles::open_file() .modal(true) .filter(FileFilter::glob(FileFilter::new("ron"), "*.ron")) @@ -888,7 +888,7 @@ impl Page { let is_dark = self.theme_mode.is_dark; let name = format!("{}.ron", if is_dark { fl!("dark") } else { fl!("light") }); - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { let res = SelectedFiles::save_file() .modal(true) .current_name(Some(name.as_str())) @@ -918,7 +918,7 @@ impl Page { return Task::none(); }; - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { let res = tokio::fs::read_to_string(path).await; if let Some(b) = res.ok().and_then(|s| ron::de::from_str(&s).ok()) { Message::ImportSuccess(Box::new(b)) @@ -944,7 +944,7 @@ impl Page { let theme_builder = self.theme_builder.clone(); - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { let Ok(builder) = ron::ser::to_string_pretty(&theme_builder, PrettyConfig::default()) else { @@ -1062,7 +1062,7 @@ impl Page { Message::IconsAndToolkit => { self.context_view = Some(ContextView::IconsAndToolkit); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, "".into(), )); @@ -1080,7 +1080,7 @@ impl Page { let is_dark = self.theme_mode.is_dark; let current_theme = self.theme.clone(); - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { let config = if is_dark { Theme::dark_config() } else { @@ -1180,7 +1180,7 @@ impl Page { let task = match message { ColorPickerUpdate::AppliedColor | ColorPickerUpdate::Reset => { needs_update = true; - cosmic::command::message(crate::app::Message::CloseContextDrawer) + cosmic::task::message(crate::app::Message::CloseContextDrawer) } ColorPickerUpdate::ActionFinished => { @@ -1189,12 +1189,12 @@ impl Page { } ColorPickerUpdate::Cancel => { - cosmic::command::message(crate::app::Message::CloseContextDrawer) + cosmic::task::message(crate::app::Message::CloseContextDrawer) } ColorPickerUpdate::ToggleColorPicker => { self.context_view = Some(context_view); - cosmic::command::message(crate::app::Message::OpenContextDrawer( + cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, context_title, )) @@ -1436,11 +1436,11 @@ impl page::Page for Page { &mut self, _sender: tokio::sync::mpsc::Sender, ) -> Task { - let (task, handle) = cosmic::command::batch(vec![ + let (task, handle) = cosmic::task::batch(vec![ // Load icon themes - cosmic::command::future(icon_themes::fetch()).map(crate::pages::Message::Appearance), + cosmic::task::future(icon_themes::fetch()).map(crate::pages::Message::Appearance), // Load font families - cosmic::command::future(async move { + cosmic::task::future(async move { let (mono, interface) = font_config::load_font_families(); Message::FontConfig(font_config::Message::LoadedFonts(mono, interface)) }) @@ -1457,7 +1457,7 @@ impl page::Page for Page { handle.abort(); } - cosmic::command::message(crate::pages::Message::Appearance(Message::Left)) + cosmic::task::message(crate::pages::Message::Appearance(Message::Left)) } fn context_drawer(&self) -> Option> { @@ -1971,7 +1971,7 @@ pub fn window_management() -> Section { settings::section() .title(§ion.title) .add(settings::item::builder(&descriptions[active_hint]).control( - cosmic::widget::spin_button( + widget::spin_button( page.theme_builder.active_hint.to_string(), page.theme_builder.active_hint, 1, @@ -1980,16 +1980,16 @@ pub fn window_management() -> Section { Message::WindowHintSize, ), )) - .add(settings::item::builder(&descriptions[gaps]).control( - cosmic::widget::spin_button( + .add( + settings::item::builder(&descriptions[gaps]).control(widget::spin_button( page.theme_builder.gaps.1.to_string(), page.theme_builder.gaps.1, 1, page.theme.active_hint, 500, Message::GapSize, - ), - )) + )), + ) .apply(Element::from) .map(crate::pages::Message::Appearance) }) diff --git a/cosmic-settings/src/pages/desktop/panel/applets_inner.rs b/cosmic-settings/src/pages/desktop/panel/applets_inner.rs index 59a951c9..eafdbf1f 100644 --- a/cosmic-settings/src/pages/desktop/panel/applets_inner.rs +++ b/cosmic-settings/src/pages/desktop/panel/applets_inner.rs @@ -442,7 +442,7 @@ impl Page { } Message::AddAppletDrawer => { self.context = Some(ContextDrawer::AddApplet); - return cosmic::command::message(app::Message::OpenContextDrawer( + return cosmic::task::message(app::Message::OpenContextDrawer( self.entity, Cow::Owned(fl!("add-applet")), )); diff --git a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs index d1b644fb..c80ef243 100644 --- a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs +++ b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs @@ -577,7 +577,7 @@ impl Page { Category::Wallpapers => { if self.config.current_folder.is_some() { let _ = self.config.set_current_folder(None); - task = cosmic::command::future(async move { + task = cosmic::task::future(async move { let folder = change_folder(Config::default_folder().to_owned(), true).await; Message::ChangeFolder(folder) }); @@ -597,7 +597,7 @@ impl Page { tracing::error!(?path, ?why, "failed to set current folder"); } - task = cosmic::command::future(async move { + task = cosmic::task::future(async move { Message::ChangeFolder(change_folder(path, false).await) }); } @@ -605,7 +605,7 @@ impl Page { Category::AddFolder => { #[cfg(feature = "xdg-portal")] - return cosmic::command::future(async { + return cosmic::task::future(async { let dialog_result = file_chooser::open::Dialog::new() .title(fl!("wallpaper", "folder-dialog")) .accept_label(fl!("dialog-add")) @@ -751,7 +751,7 @@ impl Page { Message::ColorAddContext => { self.context_view = Some(ContextView::AddColor); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("color-picker").into(), )); @@ -972,20 +972,20 @@ impl Page { } // Load preview images concurrently for each custom image stored in the on-disk config. - return cosmic::command::batch( + return cosmic::task::batch( self.config .custom_images() .iter() .cloned() .map(|path| { - cosmic::command::future(async move { + cosmic::task::future(async move { let result = wallpaper::load_image_with_thumbnail(path); Message::ImageAdd(result.map(Arc::new)) }) }) // Cache wallpaper preview early to prevent blank previews on reload - .chain(std::iter::once(cosmic::command::message::< + .chain(std::iter::once(cosmic::task::message::< _, crate::app::Message, >( diff --git a/cosmic-settings/src/pages/display/mod.rs b/cosmic-settings/src/pages/display/mod.rs index 90b116ff..edee50bd 100644 --- a/cosmic-settings/src/pages/display/mod.rs +++ b/cosmic-settings/src/pages/display/mod.rs @@ -277,7 +277,7 @@ impl page::Page for Page { })); } - cosmic::command::future(on_enter()) + cosmic::task::future(on_enter()) } fn on_leave(&mut self) -> Task { @@ -293,7 +293,7 @@ impl page::Page for Page { &mut self, sender: tokio::sync::mpsc::Sender, ) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { let mut randr = List::default(); let test_mode = randr.modes.insert(cosmic_randr_shell::Mode { @@ -380,7 +380,7 @@ impl Page { tracing::error!(?why, "cosmic-randr error"); } else { // Reload display info - return cosmic::command::future(async move { + return cosmic::task::future(async move { crate::Message::PageMessage(on_enter().await) }); } @@ -406,11 +406,11 @@ impl Page { Message::DialogCountdown => { if self.dialog_countdown == 0 { if self.dialog.is_some() { - return cosmic::command::message(app::Message::from(Message::DialogCancel)); + return cosmic::task::message(app::Message::from(Message::DialogCancel)); } } else { self.dialog_countdown -= 1; - return cosmic::command::future(async move { + return cosmic::task::future(async move { tokio::time::sleep(time::Duration::from_secs(1)).await; Message::DialogCountdown }); @@ -449,7 +449,7 @@ impl Page { // // Message::NightLightContext => { // self.context = Some(ContextDrawer::NightLight); - // return cosmic::command::message(app::Message::OpenContextDrawer( + // return cosmic::task::message(app::Message::OpenContextDrawer( // text::NIGHT_LIGHT.clone().into(), // )); // } @@ -473,7 +473,7 @@ impl Page { Message::Position(display, x, y) => return self.set_position(display, x, y), Message::Refresh => { - return cosmic::command::future(async move { + return cosmic::task::future(async move { crate::Message::PageMessage(on_enter().await) }); } @@ -583,7 +583,7 @@ impl Page { } self.dialog = Some(revert_request); self.dialog_countdown = 10; - cosmic::command::future(async { + cosmic::task::future(async { tokio::time::sleep(time::Duration::from_secs(1)).await; app::Message::from(Message::DialogCountdown) }) @@ -872,7 +872,7 @@ impl Page { // Removes the dialog if no change is being made if Some(request) == self.dialog { - tasks.push(cosmic::command::message(app::Message::from( + tasks.push(cosmic::task::message(app::Message::from( Message::DialogComplete, ))); } @@ -970,7 +970,7 @@ impl Page { } } - tasks.push(cosmic::command::future(async move { + tasks.push(cosmic::task::future(async move { tracing::debug!(?task, "executing"); app::Message::from(Message::RandrResult(Arc::new(task.status().await))) })); diff --git a/cosmic-settings/src/pages/input/keyboard/mod.rs b/cosmic-settings/src/pages/input/keyboard/mod.rs index 7ab15727..afcf7473 100644 --- a/cosmic-settings/src/pages/input/keyboard/mod.rs +++ b/cosmic-settings/src/pages/input/keyboard/mod.rs @@ -460,7 +460,7 @@ impl Page { Message::ShowInputSourcesContext => { self.context = Some(Context::ShowInputSourcesContext); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("keyboard-sources", "add").into(), )); @@ -472,7 +472,7 @@ impl Page { Message::OpenSpecialCharacterContext(key) => { self.context = Some(Context::SpecialCharacter(key)); - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, key.title().into(), )); diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs index 585bef21..0178b0b5 100644 --- a/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs @@ -393,7 +393,7 @@ impl Model { self.shortcut_context = Some(id); self.replace_dialog = None; - let mut tasks = vec![cosmic::command::message( + let mut tasks = vec![cosmic::task::message( crate::app::Message::OpenContextDrawer(self.entity, description.into()), )]; diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs index 2a38fdf6..3f9358f7 100644 --- a/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs @@ -212,7 +212,7 @@ impl Page { Message::ShortcutContext => { self.add_shortcut.enable(); return Task::batch(vec![ - cosmic::command::message(crate::app::Message::OpenContextDrawer( + cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("custom-shortcuts", "context").into(), )), diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs index 73b01fda..5bbaf8ba 100644 --- a/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs @@ -221,28 +221,28 @@ impl Page { match message { Message::Category(category) => match category { Category::Custom => { - cosmic::command::message(crate::app::Message::Page(self.sub_pages.custom)) + cosmic::task::message(crate::app::Message::Page(self.sub_pages.custom)) } - Category::ManageWindow => cosmic::command::message(crate::app::Message::Page( - self.sub_pages.manage_window, - )), + Category::ManageWindow => { + cosmic::task::message(crate::app::Message::Page(self.sub_pages.manage_window)) + } Category::MoveWindow => { - cosmic::command::message(crate::app::Message::Page(self.sub_pages.move_window)) + cosmic::task::message(crate::app::Message::Page(self.sub_pages.move_window)) } Category::Nav => { - cosmic::command::message(crate::app::Message::Page(self.sub_pages.nav)) + cosmic::task::message(crate::app::Message::Page(self.sub_pages.nav)) } Category::System => { - cosmic::command::message(crate::app::Message::Page(self.sub_pages.system)) + cosmic::task::message(crate::app::Message::Page(self.sub_pages.system)) } - Category::WindowTiling => cosmic::command::message(crate::app::Message::Page( - self.sub_pages.window_tiling, - )), + Category::WindowTiling => { + cosmic::task::message(crate::app::Message::Page(self.sub_pages.window_tiling)) + } }, Message::Search(input) => { diff --git a/cosmic-settings/src/pages/mod.rs b/cosmic-settings/src/pages/mod.rs index 1d619909..7b54e262 100644 --- a/cosmic-settings/src/pages/mod.rs +++ b/cosmic-settings/src/pages/mod.rs @@ -29,6 +29,8 @@ pub enum Message { CustomShortcuts(input::keyboard::shortcuts::custom::Message), #[cfg(feature = "page-date")] DateAndTime(time::date::Message), + #[cfg(feature = "page-default-apps")] + DefaultApps(system::default_apps::Message), Desktop(desktop::Message), DesktopWallpaper(desktop::wallpaper::Message), #[cfg(feature = "page-workspaces")] diff --git a/cosmic-settings/src/pages/networking/mod.rs b/cosmic-settings/src/pages/networking/mod.rs index e2f930d3..c4ca1ca2 100644 --- a/cosmic-settings/src/pages/networking/mod.rs +++ b/cosmic-settings/src/pages/networking/mod.rs @@ -289,10 +289,10 @@ impl Page { Message::OpenPage { page, device } => { let mut tasks = Vec::>::new(); - tasks.push(cosmic::command::message(crate::app::Message::Page(page))); + tasks.push(cosmic::task::message(crate::app::Message::Page(page))); if let Some(device) = device { - tasks.push(cosmic::command::message(crate::app::Message::PageMessage( + tasks.push(cosmic::task::message(crate::app::Message::PageMessage( match device { DeviceVariant::WiFi(device) => { crate::pages::Message::WiFi(wifi::Message::SelectDevice(device)) diff --git a/cosmic-settings/src/pages/networking/vpn/mod.rs b/cosmic-settings/src/pages/networking/vpn/mod.rs index b6d4afd9..4ecc6a1a 100644 --- a/cosmic-settings/src/pages/networking/vpn/mod.rs +++ b/cosmic-settings/src/pages/networking/vpn/mod.rs @@ -339,7 +339,7 @@ impl page::Page for Page { sender: tokio::sync::mpsc::Sender, ) -> cosmic::Task { if self.nm_task.is_none() { - return cosmic::command::future(async move { + return cosmic::task::future(async move { zbus::Connection::system() .await .context("failed to create system dbus connection") @@ -455,7 +455,7 @@ impl Page { Message::WireGuardConfig => { if let Some(VpnDialog::WireGuardName(device, filename, path)) = self.dialog.take() { - return cosmic::command::future(async move { + return cosmic::task::future(async move { let new_path = path.replace(&filename, &device); _ = std::fs::rename(&path, &new_path); match super::nm_add_vpn_file("wireguard", new_path).await { @@ -474,7 +474,7 @@ impl Page { ConnectionSettings::Vpn(ref settings) => settings, ConnectionSettings::Wireguard { id } => { let connection_name = id.clone(); - return cosmic::command::future(async move { + return cosmic::task::future(async move { if let Err(why) = nmcli::connect(&connection_name).await { return Message::Error( ErrorKind::Connect, @@ -501,7 +501,7 @@ impl Page { _ => { let connection_name = settings.id.clone(); - return cosmic::command::future(async move { + return cosmic::task::future(async move { if let Err(why) = nmcli::connect(&connection_name).await { return Message::Error( ErrorKind::Connect, @@ -546,7 +546,7 @@ impl Page { Message::Settings(uuid) => { self.close_popup_and_apply_updates(); - return cosmic::command::future(async move { + return cosmic::task::future(async move { super::nm_edit_connection(uuid.as_ref()) .then(|res| async move { match res { @@ -639,7 +639,7 @@ impl Page { username: String, password: SecureString, ) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { if let Err(why) = nmcli::set_username(&connection_name, &username).await { return Message::Error(ErrorKind::WithPassword("username"), why.to_string()); } @@ -866,7 +866,7 @@ fn popup_button(message: Message, text: &str) -> Element<'_, Message> { } fn update_state(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { match NetworkManagerState::new(&conn).await { Ok(state) => Message::UpdateState(state), Err(why) => Message::Error(ErrorKind::UpdatingState, why.to_string()), @@ -875,7 +875,7 @@ fn update_state(conn: zbus::Connection) -> Task { } fn update_devices(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { let filter = |device_type| matches!(device_type, network_manager::devices::DeviceType::WireGuard); @@ -938,7 +938,7 @@ fn add_network() -> Task { } } }) - .apply(cosmic::command::future) + .apply(cosmic::task::future) } fn connection_settings(conn: zbus::Connection) -> Task { @@ -1040,7 +1040,7 @@ fn connection_settings(conn: zbus::Connection) -> Task { Ok::<_, zbus::Error>(settings) }; - cosmic::command::future(async move { + cosmic::task::future(async move { settings.await.map_or_else( |why| Message::Error(ErrorKind::ConnectionSettings, why.to_string()), Message::KnownConnections, diff --git a/cosmic-settings/src/pages/networking/wifi.rs b/cosmic-settings/src/pages/networking/wifi.rs index 25aa74ad..a9b0a1b6 100644 --- a/cosmic-settings/src/pages/networking/wifi.rs +++ b/cosmic-settings/src/pages/networking/wifi.rs @@ -776,7 +776,7 @@ fn connection_settings(conn: zbus::Connection) -> Task { Ok::<_, zbus::Error>(settings) }; - cosmic::command::future(async move { + cosmic::task::future(async move { settings .await .context("failed to get connection settings") @@ -789,7 +789,7 @@ fn connection_settings(conn: zbus::Connection) -> Task { } pub fn update_state(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { match NetworkManagerState::new(&conn).await { Ok(state) => Message::UpdateState(state), Err(why) => Message::Error(why.to_string()), @@ -798,7 +798,7 @@ pub fn update_state(conn: zbus::Connection) -> Task { } pub fn update_devices(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + 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 { diff --git a/cosmic-settings/src/pages/networking/wired.rs b/cosmic-settings/src/pages/networking/wired.rs index bff5de1c..2ef24f16 100644 --- a/cosmic-settings/src/pages/networking/wired.rs +++ b/cosmic-settings/src/pages/networking/wired.rs @@ -161,7 +161,7 @@ impl page::Page for Page { sender: tokio::sync::mpsc::Sender, ) -> cosmic::Task { if self.nm_task.is_none() { - return cosmic::command::future(async move { + return cosmic::task::future(async move { zbus::Connection::system() .await .context("failed to create system dbus connection") @@ -265,7 +265,7 @@ impl Page { Message::NetworkManager(_event) => (), Message::AddNetwork => { - return cosmic::command::future(async move { + return cosmic::task::future(async move { _ = super::nm_add_wired().await; // TODO: Update when iced is rebased to use then method. Message::Refresh @@ -332,7 +332,7 @@ impl Page { Message::Settings(uuid) => { self.close_popup_and_apply_updates(); - return cosmic::command::future(async move { + return cosmic::task::future(async move { _ = super::nm_edit_connection(uuid.as_ref()).await; // TODO: Update when iced is rebased to use then method. Message::Refresh @@ -618,7 +618,7 @@ fn popup_button(message: Message, text: &str) -> Element<'_, Message> { } fn update_state(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { match NetworkManagerState::new(&conn).await { Ok(state) => Message::UpdateState(state), Err(why) => Message::Error(why.to_string()), @@ -627,7 +627,7 @@ fn update_state(conn: zbus::Connection) -> Task { } fn update_devices(conn: zbus::Connection) -> Task { - cosmic::command::future(async move { + cosmic::task::future(async move { let filter = |device_type| matches!(device_type, network_manager::devices::DeviceType::Ethernet); diff --git a/cosmic-settings/src/pages/sound.rs b/cosmic-settings/src/pages/sound.rs index fb262c02..d36ea006 100644 --- a/cosmic-settings/src/pages/sound.rs +++ b/cosmic-settings/src/pages/sound.rs @@ -308,7 +308,7 @@ impl Page { let mut command = None; if let Some(&node_id) = self.source_ids.get(self.active_source.unwrap_or(0)) { - command = Some(cosmic::command::future(async move { + command = Some(cosmic::task::future(async move { tokio::time::sleep(Duration::from_millis(64)).await; crate::pages::Message::Sound(Message::SourceVolumeApply(node_id)) })); @@ -338,7 +338,7 @@ impl Page { let mut command = None; if let Some(&node_id) = self.sink_ids.get(self.active_sink.unwrap_or(0)) { - command = Some(cosmic::command::future(async move { + command = Some(cosmic::task::future(async move { tokio::time::sleep(Duration::from_millis(64)).await; crate::pages::Message::Sound(Message::SinkVolumeApply(node_id)) })); @@ -542,7 +542,7 @@ impl Page { .insert(device_id.clone(), Some(profile.clone())); self.changing_sink_profile = true; - return cosmic::command::future(async move { + return cosmic::task::future(async move { pactl_set_card_profile(name, profile).await; Message::SinkProfileSelect(device_id) }) @@ -574,7 +574,7 @@ impl Page { .insert(device_id.clone(), Some(profile.clone())); self.changing_source_profile = true; - return cosmic::command::future(async move { + return cosmic::task::future(async move { pactl_set_card_profile(name, profile).await; Message::SourceProfileSelect(device_id) }) diff --git a/cosmic-settings/src/pages/system/default_apps.rs b/cosmic-settings/src/pages/system/default_apps.rs new file mode 100644 index 00000000..9a2a04fa --- /dev/null +++ b/cosmic-settings/src/pages/system/default_apps.rs @@ -0,0 +1,414 @@ +// Copyright 2024 System76 +// Copyright 2024 bbb651 +// SPDX-License-Identifier: GPL-3.0-only + +use std::{ + collections::{BTreeMap, BTreeSet}, + path::{Path, PathBuf}, + sync::Arc, +}; + +use cosmic::{ + widget::{self, dropdown, icon, settings}, + Apply, Element, Task, +}; +use cosmic_settings_page::{self as page, section, Section}; +use mime_apps::App; +use slotmap::SlotMap; +use tokio::sync::mpsc; + +const DROPDOWN_WEB_BROWSER: usize = 0; +const DROPDOWN_FILE_MANAGER: usize = 1; +const DROPDOWN_MAIL: usize = 2; +const DROPDOWN_MUSIC: usize = 3; +const DROPDOWN_VIDEO: usize = 4; +const DROPDOWN_PHOTO: usize = 5; +const DROPDOWN_CALENDAR: usize = 6; +// const DROPDOWN_TERMINAL: usize = 7; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Category { + Audio, + Calendar, + FileManager, + Image, + Mail, + Mime(&'static str), + // Terminal, + Video, + WebBrowser, +} + +#[derive(Clone, Debug)] +pub enum Message { + SetDefault(Category, usize), + Update(CachedMimeApps), +} + +impl From for crate::app::Message { + fn from(message: Message) -> Self { + crate::pages::Message::DefaultApps(message).into() + } +} + +impl From for crate::pages::Message { + fn from(message: Message) -> Self { + crate::pages::Message::DefaultApps(message) + } +} + +#[derive(Clone, Debug)] +pub struct CachedMimeApps { + pub list: mime_apps::List, + pub local_list: mime_apps::List, + pub apps: Vec, + pub known_mimes: BTreeSet, + pub config_path: Box, +} + +#[derive(Clone, Debug)] +pub struct AppMeta { + selected: Option, + app_ids: Vec, + apps: Vec, + icons: Vec, +} + +#[derive(Clone, Debug, Default)] +pub struct Page { + on_enter_handle: Option, + mime_apps: Option, +} + +impl page::AutoBind for Page {} + +impl page::Page for Page { + fn content( + &self, + sections: &mut SlotMap>, + ) -> Option { + Some(vec![sections.insert(apps())]) + } + + fn info(&self) -> page::Info { + page::Info::new("default-apps", "application-default-symbolic") + .title(fl!("default-apps")) + .description(fl!("default-apps", "desc")) + } + + fn on_enter( + &mut self, + _sender: mpsc::Sender, + ) -> Task { + let (task, on_enter_handle) = Task::future(async move { + let mut list = mime_apps::List::default(); + list.load_from_paths(&mime_apps::list_paths()); + + let mut local_list = mime_apps::List::default(); + + if let Some(path) = mime_apps::local_list_path() { + if let Ok(buffer) = std::fs::read_to_string(&path) { + local_list.load_from(&buffer); + } + } + + let assocs = mime_apps::associations::by_app(); + + let apps = vec![ + load_defaults(&assocs, "x-scheme-handler/http").await, + load_defaults(&assocs, "inode/directory").await, + load_defaults(&assocs, "x-scheme-handler/mailto").await, + load_defaults(&assocs, "audio/mp3").await, + load_defaults(&assocs, "video/mp4").await, + load_defaults(&assocs, "image/png").await, + load_defaults(&assocs, "text/calendar").await, + AppMeta { + selected: None, + app_ids: Vec::new(), + apps: Vec::new(), + icons: Vec::new(), + }, + ]; + + Message::Update(CachedMimeApps { + apps, + list, + local_list, + known_mimes: mime_apps::mime_info::mime_types(), + config_path: dirs::config_dir() + .expect("config dir not found") + .join("mimeapps.list") + .into(), + }) + .into() + }) + .abortable(); + + self.on_enter_handle = Some(on_enter_handle); + + task + } + + fn on_leave(&mut self) -> Task { + if let Some(handle) = self.on_enter_handle.take() { + handle.abort(); + } + + self.mime_apps = None; + + Task::none() + } +} + +impl Page { + pub fn update(&mut self, message: Message) -> Task { + match message { + Message::SetDefault(category, id) => { + let Some(mime_apps) = self.mime_apps.as_mut() else { + return Task::none(); + }; + + let mime_types: Vec<&str>; + let (category_id, mime_types): (usize, &[&str]) = match category { + Category::Audio => (DROPDOWN_MUSIC, { + mime_types = mime_apps + .known_mimes + .iter() + .map(|m| m.essence_str()) + .filter(|m| m.starts_with("audio")) + .chain( + [ + "application/ogg", + "application/x-cue", + "application/x-ogg", + "x-content/audio-cdda", + ] + .into_iter(), + ) + .collect(); + &mime_types + }), + Category::Calendar => (DROPDOWN_CALENDAR, &["text/calendar"]), + Category::FileManager => (DROPDOWN_FILE_MANAGER, &["inode/directory"]), + Category::Image => (DROPDOWN_PHOTO, { + mime_types = mime_apps + .known_mimes + .iter() + .map(|m| m.essence_str()) + .filter(|m| m.starts_with("image")) + .collect(); + &mime_types + }), + Category::Mail => (DROPDOWN_MAIL, &["x-scheme-handler/mailto"]), + // Category::Terminal => (DROPDOWN_TERMINAL, &[]), + Category::Video => (DROPDOWN_VIDEO, { + mime_types = mime_apps + .known_mimes + .iter() + .map(|m| m.essence_str()) + .filter(|m| m.starts_with("video")) + .collect(); + &mime_types + }), + Category::WebBrowser => ( + DROPDOWN_WEB_BROWSER, + &[ + "text/html", + "application/xhtml+xml", + "x-scheme-handler/chrome", + "x-scheme-handler/http", + "x-scheme-handler/https", + ], + ), + Category::Mime(_mime_type) => return Task::none(), + }; + + let meta = &mut mime_apps.apps[category_id]; + + if meta.selected != Some(id) { + meta.selected = Some(id); + let appid = &meta.app_ids[id]; + for mime in mime_types { + if let Ok(mime) = mime.parse() { + mime_apps + .local_list + .set_default_app(mime, [appid, ".desktop"].concat()); + }; + } + + let mut buffer = mime_apps.local_list.to_string(); + buffer.push('\n'); + + _ = std::fs::write(&mime_apps.config_path, buffer); + _ = std::process::Command::new("update-desktop-database").status(); + } + } + + Message::Update(mime_apps) => { + self.mime_apps = Some(mime_apps); + } + } + + Task::none() + } +} + +fn apps() -> Section { + Section::default().view::(move |_binder, page, section| { + let Some(mime_apps) = page.mime_apps.as_ref() else { + return widget::row().into(); + }; + + settings::section() + .title(§ion.title) + .add({ + let meta = &mime_apps.apps[DROPDOWN_WEB_BROWSER]; + settings::flex_item( + fl!("default-apps", "web-browser"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::WebBrowser, id) + }) + .icons(&meta.icons), + ) + .min_item_width(300.0) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_FILE_MANAGER]; + settings::flex_item( + fl!("default-apps", "file-manager"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::FileManager, id) + }) + .icons(&meta.icons), + ) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_MAIL]; + settings::flex_item( + fl!("default-apps", "mail-client"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::Mail, id) + }) + .icons(&meta.icons), + ) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_MUSIC]; + settings::flex_item( + fl!("default-apps", "music"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::Audio, id) + }) + .icons(&meta.icons), + ) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_VIDEO]; + settings::flex_item( + fl!("default-apps", "video"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::Video, id) + }) + .icons(&meta.icons), + ) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_PHOTO]; + settings::flex_item( + fl!("default-apps", "photos"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::Image, id) + }) + .icons(&meta.icons), + ) + }) + .add({ + let meta = &mime_apps.apps[DROPDOWN_CALENDAR]; + settings::flex_item( + fl!("default-apps", "calendar"), + dropdown(&meta.apps, meta.selected, |id| { + Message::SetDefault(Category::Calendar, id) + }) + .icons(&meta.icons), + ) + }) + // TODO: Decide on a mechanism for getting and setting the default terminal. + // .add({ + // let meta = &mime_apps.apps[DROPDOWN_TERMINAL]; + // settings::flex_item( + // fl!("default-apps", "terminal"), + // dropdown(&meta.apps, meta.selected, |id| { + // Message::SetDefault(Category::Terminal, id) + // }) + // .icons(&meta.icons), + // ) + // }) + .apply(Element::from) + .map(crate::pages::Message::DefaultApps) + }) +} + +async fn load_defaults(assocs: &BTreeMap, Arc>, for_mime: &str) -> AppMeta { + let Ok(mime) = for_mime.parse() else { + return AppMeta { + selected: None, + app_ids: Vec::new(), + apps: Vec::new(), + icons: Vec::new(), + }; + }; + + let current_app_entry = xdg_mime_query_default(for_mime).await; + let current_appid = current_app_entry + .as_ref() + .and_then(|entry| entry.strip_suffix(".desktop")); + + let current_app = current_appid.and_then(|appid| assocs.get(appid)); + + let mut unsorted = mime_apps::apps_for_mime(&mime, assocs).collect::>(); + unsorted.sort_unstable_by_key(|(_, app)| &app.name); + + let mut selected = None; + let mut app_ids = Vec::new(); + let mut apps = Vec::new(); + let mut icons = Vec::new(); + + for (id, (appid, app)) in unsorted.iter().enumerate() { + if let Some(current_app) = current_app { + if app.name.as_ref() == current_app.name.as_ref() { + selected = Some(id); + } + } + + app_ids.push(appid.as_ref().into()); + apps.push(app.name.as_ref().into()); + icons.push(if app.icon.starts_with('/') { + icon::from_path(PathBuf::from(app.icon.as_ref())) + } else { + icon::from_name(app.icon.as_ref()).size(20).handle() + }); + } + + AppMeta { + selected, + app_ids, + apps, + icons, + } +} + +async fn xdg_mime_query_default(mime_type: &str) -> Option { + let output = tokio::process::Command::new("xdg-mime") + .args(&["query", "default", mime_type]) + .output() + .await + .ok()?; + + if !output.status.success() { + return None; + } + + String::from_utf8(output.stdout) + .ok() + .map(|string| string.trim().to_owned()) +} diff --git a/cosmic-settings/src/pages/system/mod.rs b/cosmic-settings/src/pages/system/mod.rs index 81b11e66..d9cb2b86 100644 --- a/cosmic-settings/src/pages/system/mod.rs +++ b/cosmic-settings/src/pages/system/mod.rs @@ -3,6 +3,8 @@ #[cfg(feature = "page-about")] pub mod about; +#[cfg(feature = "page-default-apps")] +pub mod default_apps; pub mod firmware; pub mod users; @@ -33,6 +35,10 @@ impl page::AutoBind for Page { page = page.sub_page::(); } page = page.sub_page::(); + #[cfg(feature = "page-default-apps")] + { + page = page.sub_page::(); + } page } } diff --git a/cosmic-settings/src/pages/time/date.rs b/cosmic-settings/src/pages/time/date.rs index 5025f80f..dabc37f4 100644 --- a/cosmic-settings/src/pages/time/date.rs +++ b/cosmic-settings/src/pages/time/date.rs @@ -183,7 +183,7 @@ impl Page { Message::TimezoneContext => { self.timezone_search.clear(); self.timezone_context = true; - return cosmic::command::message(crate::app::Message::OpenContextDrawer( + return cosmic::task::message(crate::app::Message::OpenContextDrawer( self.entity, fl!("time-zone").into(), )); @@ -262,14 +262,14 @@ impl Page { Message::Error(why) => { tracing::error!(why, "failed to set timezone"); self.timezone_context = false; - return cosmic::command::message(crate::Message::CloseContextDrawer); + return cosmic::task::message(crate::Message::CloseContextDrawer); } Message::UpdateTime => { self.set_ntp(true); self.update_local_time(); self.timezone_context = false; - return cosmic::command::message(crate::Message::CloseContextDrawer); + return cosmic::task::message(crate::Message::CloseContextDrawer); } Message::Refresh(info) => { diff --git a/cosmic-settings/src/pages/time/region.rs b/cosmic-settings/src/pages/time/region.rs index 4406d8e3..2758bf93 100644 --- a/cosmic-settings/src/pages/time/region.rs +++ b/cosmic-settings/src/pages/time/region.rs @@ -139,7 +139,7 @@ impl page::Page for Page { &mut self, _sender: mpsc::Sender, ) -> cosmic::Task { - cosmic::command::future(async move { Message::Refresh(Arc::new(page_reload().await)) }) + cosmic::task::future(async move { Message::Refresh(Arc::new(page_reload().await)) }) } fn context_drawer(&self) -> Option> { @@ -175,7 +175,7 @@ impl Page { let lang = language.lang_code.clone(); let region = region.lang_code.clone(); - commands.push(cosmic::command::future(async move { + commands.push(cosmic::task::future(async move { _ = set_locale(lang, region).await; Message::Refresh(Arc::new(page_reload().await)) })); @@ -206,7 +206,7 @@ impl Page { } Message::InstallAdditionalLanguages => { - return cosmic::command::future(async move { + return cosmic::task::future(async move { _ = tokio::process::Command::new("gnome-language-selector") .status() .await; diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index 948f4f5f..ead8ab89 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -767,3 +767,17 @@ firmware = Firmware users = Users .desc = Authentication and user accounts. + +## System: Default Applications + +default-apps = Default Applications + .desc = Default applications and file associations. + .web-browser = Web browser + .file-manager = File manager + .mail-client = Mail client + .music = Music + .video = Video + .photos = Photos + .calendar = Calendar + .terminal = Terminal + .other-associations = Other Associations