Clean up mime app handling and make it possible to set default application, part of #325
This commit is contained in:
parent
691719ade7
commit
ceab7835ad
37 changed files with 306 additions and 114 deletions
89
Cargo.lock
generated
89
Cargo.lock
generated
|
|
@ -158,6 +158,12 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "almost"
|
||||
version = "0.2.0"
|
||||
|
|
@ -880,6 +886,39 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cached"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"cached_proc_macro",
|
||||
"cached_proc_macro_types",
|
||||
"hashbrown 0.14.5",
|
||||
"once_cell",
|
||||
"thiserror 1.0.69",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cached_proc_macro"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cached_proc_macro_types"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.13.0"
|
||||
|
|
@ -1229,6 +1268,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bzip2",
|
||||
"chrono",
|
||||
"cosmic-mime-apps",
|
||||
"dirs 5.0.1",
|
||||
"env_logger",
|
||||
"fastrand 2.3.0",
|
||||
|
|
@ -1299,6 +1339,17 @@ dependencies = [
|
|||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-mime-apps"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-mime-apps.git#a5aefbd2e914682c151f3b8054dd711e7f57941d"
|
||||
dependencies = [
|
||||
"freedesktop-desktop-entry 0.7.7",
|
||||
"mime 0.3.17",
|
||||
"quick-xml 0.37.2",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-protocols"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2138,6 +2189,23 @@ dependencies = [
|
|||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freedesktop-desktop-entry"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "016f6ee9509f11c985aa402451f4ee900d1fafeb501a4c3d734ebecfc1130e05"
|
||||
dependencies = [
|
||||
"cached",
|
||||
"dirs 5.0.1",
|
||||
"gettext-rs",
|
||||
"log",
|
||||
"memchr",
|
||||
"strsim 0.11.1",
|
||||
"textdistance",
|
||||
"thiserror 2.0.11",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freedesktop_entry_parser"
|
||||
version = "1.3.0"
|
||||
|
|
@ -2567,6 +2635,10 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
|
|
@ -3537,7 +3609,7 @@ dependencies = [
|
|||
"cosmic-theme",
|
||||
"css-color",
|
||||
"derive_setters",
|
||||
"freedesktop-desktop-entry",
|
||||
"freedesktop-desktop-entry 0.5.2",
|
||||
"iced",
|
||||
"iced_core",
|
||||
"iced_futures",
|
||||
|
|
@ -4923,6 +4995,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.37.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
|
|
@ -5881,6 +5962,12 @@ dependencies = [
|
|||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textdistance"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa672c55ab69f787dbc9126cc387dbe57fdd595f585e4524cf89018fa44ab819"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ vergen = { version = "8", features = ["git", "gitcl"] }
|
|||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", features = ["unstable-locales"] }
|
||||
cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true }
|
||||
dirs = "5.0.1"
|
||||
env_logger = "0.11"
|
||||
freedesktop_entry_parser = "1.3"
|
||||
|
|
@ -67,7 +68,7 @@ features = ["multi-window", "tokio", "winit"]
|
|||
|
||||
[features]
|
||||
default = ["bzip2", "desktop", "gvfs", "liblzma", "notify", "wgpu"]
|
||||
desktop = ["libcosmic/desktop", "dep:xdg"]
|
||||
desktop = ["libcosmic/desktop", "dep:cosmic-mime-apps", "dep:xdg"]
|
||||
gvfs = ["dep:gio", "dep:glib"]
|
||||
jemalloc = ["dep:tikv-jemallocator"]
|
||||
notify = ["dep:notify-rust"]
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ complete = انتهى
|
|||
copy_noun = ينسخ
|
||||
|
||||
## Open with
|
||||
open-with = افتح باستخدام
|
||||
menu-open-with = افتح باستخدام
|
||||
default-app = {$name} (المبدئي)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ restored = Адноўлена {$items} {$items ->
|
|||
unknown-folder = невядомая папка
|
||||
|
||||
## Open with
|
||||
open-with = Адкрыць з дапамогай
|
||||
menu-open-with = Адкрыць з дапамогай
|
||||
default-app = {$name} (па змаўчанні)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ complete = Hotovo
|
|||
copy_noun = Kopírovat
|
||||
|
||||
## Open with
|
||||
open-with = Otevřít v
|
||||
menu-open-with = Otevřít v
|
||||
default-app = {$name} (výchozí)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ restored = Genoprettet {$items} {$items ->
|
|||
unknown-folder = ukendt mappe
|
||||
|
||||
## Open with
|
||||
open-with = Åbn med...
|
||||
menu-open-with = Åbn med...
|
||||
default-app = {$name} (standardindstilling)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ restored = {$items} {$items ->
|
|||
unknown-folder = unbekannter Ordner
|
||||
|
||||
## Öffnen mit
|
||||
open-with = Öffnen mit
|
||||
menu-open-with = Öffnen mit
|
||||
default-app = {$name} (Standard)
|
||||
|
||||
## Details anzeigen
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ set-executable-and-launch-description = Do you want to set "{$name}" as executab
|
|||
set-and-launch = Set and launch
|
||||
|
||||
## Metadata Dialog
|
||||
open-with = Open with
|
||||
owner = Owner
|
||||
group = Group
|
||||
other = Other
|
||||
|
|
@ -196,7 +197,7 @@ restored = Restored {$items} {$items ->
|
|||
unknown-folder = unknown folder
|
||||
|
||||
## Open with
|
||||
open-with = Open with...
|
||||
menu-open-with = Open with...
|
||||
default-app = {$name} (default)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ restored = Se ha restaurado {$items} {$items ->
|
|||
unknown-folder = carpeta desconocida
|
||||
|
||||
## Open with
|
||||
open-with = Abrir con
|
||||
menu-open-with = Abrir con
|
||||
default-app = {$name} (predeterminado)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ complete = Completadas
|
|||
copy_noun = Copia
|
||||
|
||||
## Open with
|
||||
open-with = Abrir con
|
||||
menu-open-with = Abrir con
|
||||
default-app = {$name} (por defecto)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ restored = Palautettu {$items} {$items ->
|
|||
unknown-folder = Tuntematon kansio
|
||||
|
||||
## Open with
|
||||
open-with = Avaa ohjelmalla…
|
||||
menu-open-with = Avaa ohjelmalla…
|
||||
default-app = {$name} (oletus)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ restored = {$items} {$items ->
|
|||
unknown-folder = Dossier inconnu
|
||||
|
||||
## Open with
|
||||
open-with = Ouvrir avec
|
||||
menu-open-with = Ouvrir avec
|
||||
default-app = {$name} (défaut)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ restored = {$items} {$items ->
|
|||
unknown-folder = अज्ञात फ़ोल्डर
|
||||
|
||||
## Open with
|
||||
open-with = इसके साथ खोलें
|
||||
menu-open-with = इसके साथ खोलें
|
||||
default-app = {$name} (डिफ़ॉल्ट)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ undo = Visszavonás
|
|||
unknown-folder = ismeretlen mappa
|
||||
|
||||
## Open with
|
||||
open-with = Megnyitás ezzel
|
||||
menu-open-with = Megnyitás ezzel
|
||||
default-app = {$name} (alapértelmezett)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ restored = Ripristinato {$items} {$items ->
|
|||
unknown-folder = cartella sconosciuta
|
||||
|
||||
## Open with
|
||||
open-with = Apri con
|
||||
menu-open-with = Apri con
|
||||
default-app = {$name} (default)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ undo = 元に戻す
|
|||
unknown-folder = 不明なフォルダー
|
||||
|
||||
## Open with
|
||||
open-with = 別のアプリケーションで開く
|
||||
menu-open-with = 別のアプリケーションで開く
|
||||
default-app = {$name} (デフォルト)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ restored = {$items} {$items ->
|
|||
unknown-folder = ಅಜ್ಞಾತ ಫೋಲ್ಡರ್
|
||||
|
||||
## Open with
|
||||
open-with = ಇದರೊಂದಿಗೆ ತೆರೆಯಿರಿ
|
||||
menu-open-with = ಇದರೊಂದಿಗೆ ತೆರೆಯಿರಿ
|
||||
default-app = {$name} (ಸ್ಥೂಲ)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ failed = 실패
|
|||
complete = 완료
|
||||
|
||||
## Open with
|
||||
open-with = 다른 앱으로 열기
|
||||
menu-open-with = 다른 앱으로 열기
|
||||
default-app = {$name} (기본)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ restored = {$items} {$items ->
|
|||
unknown-folder = Onbekende map
|
||||
|
||||
## Open with
|
||||
open-with = Openen met...
|
||||
menu-open-with = Openen met...
|
||||
default-app = {$name} (standaard)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ restored = Przywrócono {$items} {$items ->
|
|||
unknown-folder = nieznany katalog
|
||||
|
||||
## Open with
|
||||
open-with = Otwórz za pomocą…
|
||||
menu-open-with = Otwórz za pomocą…
|
||||
default-app = {$name} (domyślnie)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ restored = Restaurado {$items} {$items ->
|
|||
unknown-folder = pasta desconhecida
|
||||
|
||||
## Open with
|
||||
open-with = Abrir com...
|
||||
menu-open-with = Abrir com...
|
||||
default-app = {$name} (padrão)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ undo = Desfazer
|
|||
unknown-folder = pasta desconhecida
|
||||
|
||||
## Open with
|
||||
open-with = Abrir com...
|
||||
menu-open-with = Abrir com...
|
||||
default-app = {$name} (predefinição)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ restored = Restaurat {$items} {$items ->
|
|||
unknown-folder = dosar necunoscut
|
||||
|
||||
## Open with
|
||||
open-with = Deschide cu...
|
||||
menu-open-with = Deschide cu...
|
||||
default-app = {$name} (implicit)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ restored = Восстановлено {$items} {$items ->
|
|||
unknown-folder = неизвестная папка
|
||||
|
||||
## Open with
|
||||
open-with = Открыть с помощью
|
||||
menu-open-with = Открыть с помощью
|
||||
default-app = {$name} (по умолчанию)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ undo = Späť
|
|||
unknown-folder = neznámy priečinok
|
||||
|
||||
## Open with
|
||||
open-with = Otvoriť s
|
||||
menu-open-with = Otvoriť s
|
||||
default-app = {$name} (Predvolené)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ restored = Återställt {$items} {$items ->
|
|||
unknown-folder = okänd katalog
|
||||
|
||||
## Öppna med
|
||||
open-with = Öppna med...
|
||||
menu-open-with = Öppna med...
|
||||
default-app = {$name} (default)
|
||||
|
||||
## Visa detaljer
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ restored = Restored {$items} {$items ->
|
|||
unknown-folder = แฟ้มที่ไม่รู้จัก
|
||||
|
||||
## Open with
|
||||
open-with = เปิดด้วย...
|
||||
menu-open-with = เปิดด้วย...
|
||||
default-app = {$name} (ค่าเริ่มต้น)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ restored = {$items} öge "{$trash}"ten "{$to}" dizinine geri yüklenildi ({$prog
|
|||
unknown-folder = bilinmeyen klasör
|
||||
|
||||
## Open with
|
||||
open-with = Birlikte aç...
|
||||
menu-open-with = Birlikte aç...
|
||||
default-app = {$name} (varsayılan)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ undo = Скасувати
|
|||
unknown-folder = невідома тека
|
||||
|
||||
## Open with
|
||||
open-with = Відкрити за допомогою
|
||||
menu-open-with = Відкрити за допомогою
|
||||
default-app = {$name} (типово)
|
||||
|
||||
## Properties
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ restored = 已从 {trash} 还原 {$items} 个项目
|
|||
unknown-folder = 未知文件夹
|
||||
|
||||
## Open with
|
||||
open-with = 打开方式...
|
||||
menu-open-with = 打开方式...
|
||||
default-app = {$name} (默认)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ restored = 已還原 {$items} 項目 {$items ->
|
|||
unknown-folder = 未知資料夾
|
||||
|
||||
## Open with
|
||||
open-with = 開啟方式...
|
||||
menu-open-with = 開啟方式...
|
||||
default-app = {$name} (預設)
|
||||
|
||||
## Show details
|
||||
|
|
|
|||
81
src/app.rs
81
src/app.rs
|
|
@ -444,7 +444,6 @@ pub enum DialogPage {
|
|||
OpenWith {
|
||||
path: PathBuf,
|
||||
mime: mime_guess::Mime,
|
||||
apps: Vec<mime_app::MimeApp>,
|
||||
selected: usize,
|
||||
store_opt: Option<mime_app::MimeApp>,
|
||||
},
|
||||
|
|
@ -514,6 +513,7 @@ pub struct App {
|
|||
dialog_text_input: widget::Id,
|
||||
key_binds: HashMap<KeyBind, Action>,
|
||||
margin: HashMap<window::Id, (f32, f32, f32, f32)>,
|
||||
mime_app_cache: mime_app::MimeAppCache,
|
||||
modifiers: Modifiers,
|
||||
mounter_items: HashMap<MounterKey, MounterItems>,
|
||||
network_drive_connecting: Option<(MounterKey, String)>,
|
||||
|
|
@ -592,7 +592,7 @@ impl App {
|
|||
}
|
||||
|
||||
// Try mime apps, which should be faster than xdg-open
|
||||
for app in mime_app::mime_apps(&mime) {
|
||||
for app in self.mime_app_cache.get(&mime) {
|
||||
let Some(mut command) = app.command(Some(path.clone().into())) else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -1431,21 +1431,24 @@ impl App {
|
|||
entity_opt: &Option<Entity>,
|
||||
kind: &'a PreviewKind,
|
||||
context_drawer: bool,
|
||||
) -> Element<'a, Message> {
|
||||
) -> Element<'a, tab::Message> {
|
||||
let cosmic_theme::Spacing { space_l, .. } = theme::active().cosmic().spacing;
|
||||
|
||||
let mut children = Vec::with_capacity(1);
|
||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||
match kind {
|
||||
PreviewKind::Custom(PreviewItem(item)) => {
|
||||
children.push(item.preview_view(IconSizes::default()));
|
||||
children.push(item.preview_view(Some(&self.mime_app_cache), IconSizes::default()));
|
||||
}
|
||||
PreviewKind::Location(location) => {
|
||||
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||
if let Some(items) = tab.items_opt() {
|
||||
for item in items.iter() {
|
||||
if item.location_opt.as_ref() == Some(location) {
|
||||
children.push(item.preview_view(tab.config.icon_sizes));
|
||||
children.push(item.preview_view(
|
||||
Some(&self.mime_app_cache),
|
||||
tab.config.icon_sizes,
|
||||
));
|
||||
// Only show one property view to avoid issues like hangs when generating
|
||||
// preview images on thousands of files
|
||||
break;
|
||||
|
|
@ -1459,7 +1462,10 @@ impl App {
|
|||
if let Some(items) = tab.items_opt() {
|
||||
for item in items.iter() {
|
||||
if item.selected {
|
||||
children.push(item.preview_view(tab.config.icon_sizes));
|
||||
children.push(item.preview_view(
|
||||
Some(&self.mime_app_cache),
|
||||
tab.config.icon_sizes,
|
||||
));
|
||||
// Only show one property view to avoid issues like hangs when generating
|
||||
// preview images on thousands of files
|
||||
break;
|
||||
|
|
@ -1467,7 +1473,10 @@ impl App {
|
|||
}
|
||||
if children.is_empty() {
|
||||
if let Some(item) = &tab.parent_item_opt {
|
||||
children.push(item.preview_view(tab.config.icon_sizes));
|
||||
children.push(item.preview_view(
|
||||
Some(&self.mime_app_cache),
|
||||
tab.config.icon_sizes,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1573,6 +1582,7 @@ impl Application for App {
|
|||
dialog_text_input: widget::Id::unique(),
|
||||
key_binds,
|
||||
margin: HashMap::new(),
|
||||
mime_app_cache: mime_app::MimeAppCache::new(),
|
||||
modifiers: Modifiers::empty(),
|
||||
mounter_items: HashMap::new(),
|
||||
network_drive_connecting: None,
|
||||
|
|
@ -1688,7 +1698,7 @@ impl Application for App {
|
|||
NavMenuAction::Open(entity),
|
||||
));
|
||||
items.push(cosmic::widget::menu::Item::Button(
|
||||
fl!("open-with"),
|
||||
fl!("menu-open-with"),
|
||||
None,
|
||||
NavMenuAction::OpenWith(entity),
|
||||
));
|
||||
|
|
@ -2016,11 +2026,11 @@ impl Application for App {
|
|||
}
|
||||
DialogPage::OpenWith {
|
||||
path,
|
||||
apps,
|
||||
mime,
|
||||
selected,
|
||||
..
|
||||
} => {
|
||||
if let Some(app) = apps.get(selected) {
|
||||
if let Some(app) = self.mime_app_cache.get(&mime).get(selected) {
|
||||
if let Some(mut command) = app.command(Some(path.clone().into())) {
|
||||
match spawn_detached(&mut command) {
|
||||
Ok(()) => {
|
||||
|
|
@ -2345,7 +2355,7 @@ impl Application for App {
|
|||
}
|
||||
},
|
||||
Message::OpenTerminal(entity_opt) => {
|
||||
if let Some(terminal) = mime_app::terminal() {
|
||||
if let Some(terminal) = self.mime_app_cache.terminal() {
|
||||
let mut paths = Vec::new();
|
||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||
|
|
@ -2471,12 +2481,13 @@ impl Application for App {
|
|||
return self.update(Message::DialogPush(DialogPage::OpenWith {
|
||||
path: path.to_path_buf(),
|
||||
mime: item.mime.clone(),
|
||||
apps: item.open_with.clone(),
|
||||
selected: 0,
|
||||
store_opt: "x-scheme-handler/mime"
|
||||
.parse::<mime_guess::Mime>()
|
||||
.ok()
|
||||
.and_then(|mime| mime_app::mime_apps(&mime).first().cloned()),
|
||||
.and_then(|mime| {
|
||||
self.mime_app_cache.get(&mime).first().cloned()
|
||||
}),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -2905,9 +2916,11 @@ impl Application for App {
|
|||
App::exec_entry_action(entry, action);
|
||||
}
|
||||
tab::Command::Iced(iced_command) => {
|
||||
commands.push(iced_command.0.map(move |tab_message| {
|
||||
message::app(Message::TabMessage(Some(entity), tab_message))
|
||||
}));
|
||||
commands.push(
|
||||
iced_command.0.map(move |x| {
|
||||
message::app(Message::TabMessage(Some(entity), x))
|
||||
}),
|
||||
);
|
||||
}
|
||||
tab::Command::MoveToTrash(paths) => {
|
||||
self.operation(Operation::Delete { paths });
|
||||
|
|
@ -2942,6 +2955,10 @@ impl Application for App {
|
|||
self.context_page = ContextPage::Preview(Some(entity), kind);
|
||||
self.set_show_context(true);
|
||||
}
|
||||
tab::Command::SetOpenWith(mime, id) => {
|
||||
//TODO: this will block for a few ms, run in background?
|
||||
self.mime_app_cache.set_default(mime, id);
|
||||
}
|
||||
tab::Command::WindowDrag => {
|
||||
if let Some(window_id) = &self.window_id_opt {
|
||||
commands.push(window::drag(*window_id));
|
||||
|
|
@ -3282,13 +3299,12 @@ impl Application for App {
|
|||
return self.update(Message::DialogPush(DialogPage::OpenWith {
|
||||
path: path.to_path_buf(),
|
||||
mime: item.mime.clone(),
|
||||
apps: item.open_with.clone(),
|
||||
selected: 0,
|
||||
store_opt: "x-scheme-handler/mime"
|
||||
.parse::<mime_guess::Mime>()
|
||||
.ok()
|
||||
.and_then(|mime| {
|
||||
mime_app::mime_apps(&mime).first().cloned()
|
||||
self.mime_app_cache.get(&mime).first().cloned()
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
|
@ -3530,14 +3546,17 @@ impl Application for App {
|
|||
if let Some(items) = tab.items_opt() {
|
||||
for item in items.iter() {
|
||||
if item.selected {
|
||||
actions.extend(item.preview_header())
|
||||
actions.extend(item.preview_header().into_iter().map(|element| {
|
||||
element.map(move |x| Message::TabMessage(Some(entity), x))
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
context_drawer::context_drawer(
|
||||
self.preview(entity_opt, kind, true),
|
||||
Message::ToggleContextPage(ContextPage::Preview(*entity_opt, kind.clone())),
|
||||
self.preview(entity_opt, kind, true)
|
||||
.map(move |x| Message::TabMessage(Some(entity), x)),
|
||||
Message::ToggleContextPage(ContextPage::Preview(Some(entity), kind.clone())),
|
||||
)
|
||||
.header_actions(actions)
|
||||
}
|
||||
|
|
@ -3556,7 +3575,7 @@ impl Application for App {
|
|||
if tab.gallery {
|
||||
return Some(
|
||||
tab.gallery_view()
|
||||
.map(move |tab_message| Message::TabMessage(Some(entity), tab_message)),
|
||||
.map(move |x| Message::TabMessage(Some(entity), x)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3878,7 +3897,7 @@ impl Application for App {
|
|||
}
|
||||
DialogPage::OpenWith {
|
||||
path,
|
||||
apps,
|
||||
mime,
|
||||
selected,
|
||||
store_opt,
|
||||
..
|
||||
|
|
@ -3889,7 +3908,7 @@ impl Application for App {
|
|||
};
|
||||
|
||||
let mut column = widget::list_column();
|
||||
for (i, app) in apps.iter().enumerate() {
|
||||
for (i, app) in self.mime_app_cache.get(mime).iter().enumerate() {
|
||||
column = column.add(
|
||||
widget::button::custom(
|
||||
widget::row::with_children(vec![
|
||||
|
|
@ -4026,8 +4045,14 @@ impl Application for App {
|
|||
let dialog = widget::dialog()
|
||||
.title(fl!("replace-title", filename = to.name.as_str()))
|
||||
.body(fl!("replace-warning-operation"))
|
||||
.control(to.replace_view(fl!("original-file"), IconSizes::default()))
|
||||
.control(from.replace_view(fl!("replace-with"), IconSizes::default()))
|
||||
.control(
|
||||
to.replace_view(fl!("original-file"), IconSizes::default())
|
||||
.map(|x| Message::TabMessage(None, x)),
|
||||
)
|
||||
.control(
|
||||
from.replace_view(fl!("replace-with"), IconSizes::default())
|
||||
.map(|x| Message::TabMessage(None, x)),
|
||||
)
|
||||
.primary_action(widget::button::suggested(fl!("replace")).on_press(
|
||||
Message::ReplaceResult(ReplaceResult::Replace(*apply_to_all)),
|
||||
));
|
||||
|
|
@ -4365,7 +4390,9 @@ impl Application for App {
|
|||
};
|
||||
}
|
||||
Some(WindowKind::DesktopViewOptions) => self.desktop_view_options(),
|
||||
Some(WindowKind::Preview(entity_opt, kind)) => self.preview(entity_opt, kind, false),
|
||||
Some(WindowKind::Preview(entity_opt, kind)) => self
|
||||
.preview(entity_opt, kind, false)
|
||||
.map(|x| Message::TabMessage(*entity_opt, x)),
|
||||
None => {
|
||||
//TODO: distinct views per monitor in desktop mode
|
||||
return self.view_main().map(|message| match message {
|
||||
|
|
|
|||
|
|
@ -471,17 +471,17 @@ impl App {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn preview<'a>(&'a self, kind: &'a PreviewKind) -> Element<'a, AppMessage> {
|
||||
fn preview<'a>(&'a self, kind: &'a PreviewKind) -> Element<'a, tab::Message> {
|
||||
let mut children = Vec::with_capacity(1);
|
||||
match kind {
|
||||
PreviewKind::Custom(PreviewItem(item)) => {
|
||||
children.push(item.preview_view(IconSizes::default()));
|
||||
children.push(item.preview_view(None, IconSizes::default()));
|
||||
}
|
||||
PreviewKind::Location(location) => {
|
||||
if let Some(items) = self.tab.items_opt() {
|
||||
for item in items.iter() {
|
||||
if item.location_opt.as_ref() == Some(location) {
|
||||
children.push(item.preview_view(self.tab.config.icon_sizes));
|
||||
children.push(item.preview_view(None, self.tab.config.icon_sizes));
|
||||
// Only show one property view to avoid issues like hangs when generating
|
||||
// preview images on thousands of files
|
||||
break;
|
||||
|
|
@ -493,7 +493,7 @@ impl App {
|
|||
if let Some(items) = self.tab.items_opt() {
|
||||
for item in items.iter() {
|
||||
if item.selected {
|
||||
children.push(item.preview_view(self.tab.config.icon_sizes));
|
||||
children.push(item.preview_view(None, self.tab.config.icon_sizes));
|
||||
// Only show one property view to avoid issues like hangs when generating
|
||||
// preview images on thousands of files
|
||||
break;
|
||||
|
|
@ -501,7 +501,7 @@ impl App {
|
|||
}
|
||||
if children.is_empty() {
|
||||
if let Some(item) = &self.tab.parent_item_opt {
|
||||
children.push(item.preview_view(self.tab.config.icon_sizes));
|
||||
children.push(item.preview_view(None, self.tab.config.icon_sizes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -814,14 +814,14 @@ impl Application for App {
|
|||
actions.extend(
|
||||
item.preview_header()
|
||||
.into_iter()
|
||||
.map(|element| element.map(Message::from)),
|
||||
.map(|element| element.map(Message::TabMessage)),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
Some(
|
||||
context_drawer::context_drawer(
|
||||
self.preview(kind).map(Message::from),
|
||||
self.preview(kind).map(Message::TabMessage),
|
||||
Message::Preview,
|
||||
)
|
||||
.header_actions(actions),
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ pub fn context_menu<'a>(
|
|||
children.push(menu_item(fl!("open"), Action::Open).into());
|
||||
}
|
||||
if selected == 1 {
|
||||
children.push(menu_item(fl!("open-with"), Action::OpenWith).into());
|
||||
children.push(menu_item(fl!("menu-open-with"), Action::OpenWith).into());
|
||||
if selected_dir == 1 {
|
||||
children
|
||||
.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal).into());
|
||||
|
|
@ -531,7 +531,7 @@ pub fn menu_bar<'a>(
|
|||
Action::Open,
|
||||
(selected > 0 && selected_dir == 0) || (selected_dir == 1 && selected == 1),
|
||||
),
|
||||
menu_button_optional(fl!("open-with"), Action::OpenWith, selected == 1),
|
||||
menu_button_optional(fl!("menu-open-with"), Action::OpenWith, selected == 1),
|
||||
menu::Item::Divider,
|
||||
menu_button_optional(fl!("rename"), Action::Rename, selected > 0),
|
||||
menu::Item::Divider,
|
||||
|
|
|
|||
104
src/mime_app.rs
104
src/mime_app.rs
|
|
@ -5,9 +5,8 @@
|
|||
use cosmic::desktop;
|
||||
use cosmic::widget;
|
||||
pub use mime_guess::Mime;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
cmp::Ordering, collections::HashMap, env, ffi::OsString, path::PathBuf, process, sync::Mutex,
|
||||
cmp::Ordering, collections::HashMap, env, ffi::OsString, fs, io, path::PathBuf, process,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
|
|
@ -52,6 +51,13 @@ impl MimeApp {
|
|||
}
|
||||
}
|
||||
|
||||
// This allows usage of MimeApp in a dropdown
|
||||
impl AsRef<str> for MimeApp {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
impl From<&desktop::DesktopEntryData> for MimeApp {
|
||||
fn from(app: &desktop::DesktopEntryData) -> Self {
|
||||
|
|
@ -82,6 +88,7 @@ fn filename_eq(path_opt: &Option<PathBuf>, filename: &str) -> bool {
|
|||
|
||||
pub struct MimeAppCache {
|
||||
cache: HashMap<Mime, Vec<MimeApp>>,
|
||||
icons: HashMap<Mime, Vec<widget::icon::Handle>>,
|
||||
terminals: Vec<MimeApp>,
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +96,7 @@ impl MimeAppCache {
|
|||
pub fn new() -> Self {
|
||||
let mut mime_app_cache = Self {
|
||||
cache: HashMap::new(),
|
||||
icons: HashMap::new(),
|
||||
terminals: Vec::new(),
|
||||
};
|
||||
mime_app_cache.reload();
|
||||
|
|
@ -106,6 +114,7 @@ impl MimeAppCache {
|
|||
let start = Instant::now();
|
||||
|
||||
self.cache.clear();
|
||||
self.icons.clear();
|
||||
self.terminals.clear();
|
||||
|
||||
//TODO: get proper locale?
|
||||
|
|
@ -254,37 +263,88 @@ impl MimeAppCache {
|
|||
});
|
||||
}
|
||||
|
||||
// Copy icons to special cache
|
||||
//TODO: adjust dropdown API so this is no longer needed
|
||||
for (mime, apps) in self.cache.iter() {
|
||||
self.icons.insert(
|
||||
mime.clone(),
|
||||
apps.iter().map(|app| app.icon.clone()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
log::info!("loaded mime app cache in {:?}", elapsed);
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &Mime) -> Vec<MimeApp> {
|
||||
self.cache.get(key).map_or_else(Vec::new, |x| x.clone())
|
||||
pub fn get(&self, key: &Mime) -> &[MimeApp] {
|
||||
static EMPTY: Vec<MimeApp> = Vec::new();
|
||||
self.cache.get(key).unwrap_or_else(|| &EMPTY)
|
||||
}
|
||||
}
|
||||
|
||||
static MIME_APP_CACHE: Lazy<Mutex<MimeAppCache>> = Lazy::new(|| Mutex::new(MimeAppCache::new()));
|
||||
pub fn icons(&self, key: &Mime) -> &[widget::icon::Handle] {
|
||||
static EMPTY: Vec<widget::icon::Handle> = Vec::new();
|
||||
self.icons.get(key).unwrap_or_else(|| &EMPTY)
|
||||
}
|
||||
|
||||
pub fn mime_apps(mime: &Mime) -> Vec<MimeApp> {
|
||||
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
||||
mime_app_cache.get(mime)
|
||||
}
|
||||
pub fn terminal(&self) -> Option<&MimeApp> {
|
||||
//TODO: consider rules in https://github.com/Vladimir-csp/xdg-terminal-exec
|
||||
|
||||
pub fn terminal() -> Option<MimeApp> {
|
||||
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
||||
// Look for and return preferred terminals
|
||||
//TODO: fallback order beyond cosmic-term?
|
||||
for id in &["com.system76.CosmicTerm"] {
|
||||
for terminal in self.terminals.iter() {
|
||||
if &terminal.id == id {
|
||||
return Some(terminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: consider rules in https://github.com/Vladimir-csp/xdg-terminal-exec
|
||||
// Return whatever was the first terminal found
|
||||
self.terminals.first()
|
||||
}
|
||||
|
||||
// Look for and return preferred terminals
|
||||
//TODO: fallback order beyond cosmic-term?
|
||||
for id in &["com.system76.CosmicTerm"] {
|
||||
for terminal in mime_app_cache.terminals.iter() {
|
||||
if &terminal.id == id {
|
||||
return Some(terminal.clone());
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
pub fn set_default(&mut self, mime: Mime, id: String) {
|
||||
log::warn!(
|
||||
"failed to set default handler for {mime:?} to {id:?}: desktop feature not enabled"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn set_default(&mut self, mime: Mime, mut id: String) {
|
||||
let Some(path) = cosmic_mime_apps::local_list_path() else {
|
||||
log::warn!("failed to find mimeapps.list path");
|
||||
return;
|
||||
};
|
||||
|
||||
let mut list = cosmic_mime_apps::List::default();
|
||||
match fs::read_to_string(&path) {
|
||||
Ok(string) => {
|
||||
list.load_from(&string);
|
||||
}
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::NotFound {
|
||||
log::warn!("failed to read {path:?}: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let suffix = ".desktop";
|
||||
if !id.ends_with(suffix) {
|
||||
id.push_str(suffix);
|
||||
}
|
||||
list.set_default_app(mime, id);
|
||||
|
||||
let mut string = list.to_string();
|
||||
string.push('\n');
|
||||
match fs::write(&path, string) {
|
||||
Ok(()) => {
|
||||
self.reload();
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to write {path:?}: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return whatever was the first terminal found
|
||||
mime_app_cache.terminals.first().cloned()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
|
|||
icon_handle_grid,
|
||||
icon_handle_list,
|
||||
icon_handle_list_condensed,
|
||||
open_with: Vec::new(),
|
||||
thumbnail_opt: Some(ItemThumbnail::NotImage),
|
||||
button_id: widget::Id::unique(),
|
||||
pos_opt: Cell::new(None),
|
||||
|
|
|
|||
65
src/tab.rs
65
src/tab.rs
|
|
@ -58,14 +58,13 @@ use tokio::sync::mpsc;
|
|||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{
|
||||
app::{self, Action, PreviewItem, PreviewKind},
|
||||
app::{Action, PreviewItem, PreviewKind},
|
||||
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
||||
config::{DesktopConfig, IconSizes, TabConfig, ICON_SCALE_MAX, ICON_SIZE_GRID},
|
||||
dialog::DialogKind,
|
||||
fl,
|
||||
localize::{LANGUAGE_CHRONO, LANGUAGE_SORTER},
|
||||
menu,
|
||||
mime_app::{mime_apps, MimeApp},
|
||||
menu, mime_app,
|
||||
mime_icon::{mime_for_path, mime_icon},
|
||||
mounter::MOUNTERS,
|
||||
mouse_area,
|
||||
|
|
@ -459,8 +458,6 @@ pub fn item_from_entry(
|
|||
}
|
||||
};
|
||||
|
||||
let open_with = mime_apps(&mime);
|
||||
|
||||
let children = if metadata.is_dir() {
|
||||
//TODO: calculate children in the background (and make it cancellable?)
|
||||
match fs::read_dir(&path) {
|
||||
|
|
@ -490,7 +487,6 @@ pub fn item_from_entry(
|
|||
icon_handle_grid,
|
||||
icon_handle_list,
|
||||
icon_handle_list_condensed,
|
||||
open_with,
|
||||
thumbnail_opt: None,
|
||||
button_id: widget::Id::unique(),
|
||||
pos_opt: Cell::new(None),
|
||||
|
|
@ -720,7 +716,6 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
|||
icon_handle_grid,
|
||||
icon_handle_list,
|
||||
icon_handle_list_condensed,
|
||||
open_with: Vec::new(),
|
||||
thumbnail_opt: Some(ItemThumbnail::NotImage),
|
||||
button_id: widget::Id::unique(),
|
||||
pos_opt: Cell::new(None),
|
||||
|
|
@ -904,7 +899,6 @@ pub fn scan_desktop(
|
|||
icon_handle_grid,
|
||||
icon_handle_list,
|
||||
icon_handle_list_condensed,
|
||||
open_with: Vec::new(),
|
||||
thumbnail_opt: Some(ItemThumbnail::NotImage),
|
||||
button_id: widget::Id::unique(),
|
||||
pos_opt: Cell::new(None),
|
||||
|
|
@ -1027,6 +1021,7 @@ pub enum Command {
|
|||
OpenInNewWindow(PathBuf),
|
||||
OpenTrash,
|
||||
Preview(PreviewKind),
|
||||
SetOpenWith(Mime, String),
|
||||
WindowDrag,
|
||||
WindowToggleMaximize,
|
||||
}
|
||||
|
|
@ -1073,6 +1068,7 @@ pub enum Message {
|
|||
SelectAll,
|
||||
SelectFirst,
|
||||
SelectLast,
|
||||
SetOpenWith(Mime, String),
|
||||
SetSort(HeadingOptions, bool),
|
||||
Thumbnail(PathBuf, ItemThumbnail),
|
||||
ToggleShowHidden,
|
||||
|
|
@ -1318,7 +1314,6 @@ pub struct Item {
|
|||
pub icon_handle_grid: widget::icon::Handle,
|
||||
pub icon_handle_list: widget::icon::Handle,
|
||||
pub icon_handle_list_condensed: widget::icon::Handle,
|
||||
pub open_with: Vec<MimeApp>,
|
||||
pub thumbnail_opt: Option<ItemThumbnail>,
|
||||
pub button_id: widget::Id,
|
||||
pub pos_opt: Cell<Option<(usize, usize)>>,
|
||||
|
|
@ -1343,7 +1338,7 @@ impl Item {
|
|||
self.mime.type_() == mime::IMAGE || self.mime.type_() == mime::TEXT
|
||||
}
|
||||
|
||||
fn preview<'a>(&'a self, sizes: IconSizes) -> Element<'a, app::Message> {
|
||||
fn preview<'a>(&'a self, sizes: IconSizes) -> Element<'a, Message> {
|
||||
let spacing = cosmic::theme::active().cosmic().spacing;
|
||||
// This loads the image only if thumbnailing worked
|
||||
let icon = widget::icon::icon(self.icon_handle_grid.clone())
|
||||
|
|
@ -1376,23 +1371,23 @@ impl Item {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn preview_header(&self) -> Vec<Element<app::Message>> {
|
||||
pub fn preview_header(&self) -> Vec<Element<Message>> {
|
||||
let mut row = Vec::with_capacity(3);
|
||||
row.push(
|
||||
widget::button::icon(widget::icon::from_name("go-previous-symbolic"))
|
||||
.on_press(app::Message::TabMessage(None, Message::ItemLeft))
|
||||
.on_press(Message::ItemLeft)
|
||||
.into(),
|
||||
);
|
||||
row.push(
|
||||
widget::button::icon(widget::icon::from_name("go-next-symbolic"))
|
||||
.on_press(app::Message::TabMessage(None, Message::ItemRight))
|
||||
.on_press(Message::ItemRight)
|
||||
.into(),
|
||||
);
|
||||
if self.can_gallery() {
|
||||
if let Some(_path) = self.path_opt() {
|
||||
row.push(
|
||||
widget::button::icon(widget::icon::from_name("view-fullscreen-symbolic"))
|
||||
.on_press(app::Message::TabMessage(None, Message::Gallery(true)))
|
||||
.on_press(Message::Gallery(true))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
|
@ -1400,7 +1395,11 @@ impl Item {
|
|||
row
|
||||
}
|
||||
|
||||
pub fn preview_view<'a>(&'a self, sizes: IconSizes) -> Element<'a, app::Message> {
|
||||
pub fn preview_view<'a>(
|
||||
&'a self,
|
||||
mime_app_cache_opt: Option<&'a mime_app::MimeAppCache>,
|
||||
sizes: IconSizes,
|
||||
) -> Element<'a, Message> {
|
||||
let cosmic_theme::Spacing {
|
||||
space_xxxs,
|
||||
space_m,
|
||||
|
|
@ -1422,6 +1421,24 @@ impl Item {
|
|||
mime = self.mime.to_string()
|
||||
)));
|
||||
let mut settings = Vec::new();
|
||||
if let Some(mime_app_cache) = mime_app_cache_opt {
|
||||
let mime_apps = mime_app_cache.get(&self.mime);
|
||||
if !mime_apps.is_empty() {
|
||||
settings.push(
|
||||
widget::settings::item::builder(fl!("open-with")).control(
|
||||
widget::dropdown(
|
||||
mime_apps,
|
||||
mime_apps.iter().position(|x| x.is_default),
|
||||
|index| {
|
||||
let mime_app = &mime_apps[index];
|
||||
Message::SetOpenWith(self.mime.clone(), mime_app.id.clone())
|
||||
},
|
||||
)
|
||||
.icons(mime_app_cache.icons(&self.mime)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
match &self.metadata {
|
||||
ItemMetadata::Path { metadata, children } => {
|
||||
if metadata.is_dir() {
|
||||
|
|
@ -1509,9 +1526,10 @@ impl Item {
|
|||
column = column.push(details);
|
||||
|
||||
if let Some(path) = self.path_opt() {
|
||||
column = column.push(widget::button::standard(fl!("open")).on_press(
|
||||
app::Message::TabMessage(None, Message::Open(Some(path.to_path_buf()))),
|
||||
));
|
||||
column = column.push(
|
||||
widget::button::standard(fl!("open"))
|
||||
.on_press(Message::Open(Some(path.to_path_buf()))),
|
||||
);
|
||||
}
|
||||
|
||||
if !settings.is_empty() {
|
||||
|
|
@ -1525,11 +1543,7 @@ impl Item {
|
|||
column.into()
|
||||
}
|
||||
|
||||
pub fn replace_view<'a>(
|
||||
&'a self,
|
||||
heading: String,
|
||||
sizes: IconSizes,
|
||||
) -> Element<'a, app::Message> {
|
||||
pub fn replace_view<'a>(&'a self, heading: String, sizes: IconSizes) -> Element<'a, Message> {
|
||||
let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing;
|
||||
|
||||
let mut row = widget::row().spacing(space_xxxs);
|
||||
|
|
@ -2831,6 +2845,9 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::SetOpenWith(mime, id) => {
|
||||
commands.push(Command::SetOpenWith(mime, id));
|
||||
}
|
||||
Message::SetSort(heading_option, dir) => {
|
||||
if !matches!(self.location, Location::Search(..)) {
|
||||
self.sort_name = heading_option;
|
||||
|
|
@ -4432,7 +4449,7 @@ impl Tab {
|
|||
dnd_dest.into()
|
||||
}
|
||||
|
||||
pub fn view<'a>(&'a self, key_binds: &'a HashMap<KeyBind, Action>) -> Element<Message> {
|
||||
pub fn view<'a>(&'a self, key_binds: &'a HashMap<KeyBind, Action>) -> Element<'a, Message> {
|
||||
widget::responsive(|size| self.view_responsive(key_binds, size)).into()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue