Partial open with implementation, parse mimeapps.list files
This commit is contained in:
parent
18e847abb8
commit
26173d6529
11 changed files with 357 additions and 147 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
|
@ -1127,7 +1127,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config"
|
name = "cosmic-config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomicwrites",
|
"atomicwrites",
|
||||||
"cosmic-config-derive",
|
"cosmic-config-derive",
|
||||||
|
|
@ -1144,7 +1144,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config-derive"
|
name = "cosmic-config-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
|
@ -1159,6 +1159,7 @@ dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"fork",
|
"fork",
|
||||||
|
"freedesktop_entry_parser",
|
||||||
"i18n-embed",
|
"i18n-embed",
|
||||||
"i18n-embed-fl",
|
"i18n-embed-fl",
|
||||||
"image 0.24.9",
|
"image 0.24.9",
|
||||||
|
|
@ -1179,6 +1180,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"trash",
|
"trash",
|
||||||
"vergen",
|
"vergen",
|
||||||
|
"xdg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1206,7 +1208,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-theme"
|
name = "cosmic-theme"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"almost",
|
"almost",
|
||||||
"cosmic-config",
|
"cosmic-config",
|
||||||
|
|
@ -2070,6 +2072,16 @@ dependencies = [
|
||||||
"xdg",
|
"xdg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "freedesktop_entry_parser"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4"
|
||||||
|
dependencies = [
|
||||||
|
"nom 7.1.3",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent-sys"
|
name = "fsevent-sys"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
|
|
@ -2650,7 +2662,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_accessibility",
|
"iced_accessibility",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
|
|
@ -2665,7 +2677,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_accessibility"
|
name = "iced_accessibility"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_winit",
|
"accesskit_winit",
|
||||||
|
|
@ -2674,7 +2686,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -2691,7 +2703,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_futures"
|
name = "iced_futures"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
|
|
@ -2704,7 +2716,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -2728,7 +2740,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_renderer"
|
name = "iced_renderer"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_tiny_skia",
|
"iced_tiny_skia",
|
||||||
|
|
@ -2740,7 +2752,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_runtime"
|
name = "iced_runtime"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -2750,7 +2762,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_style"
|
name = "iced_style"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -2760,7 +2772,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_tiny_skia"
|
name = "iced_tiny_skia"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
|
|
@ -2777,7 +2789,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -2796,7 +2808,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_widget"
|
name = "iced_widget"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_renderer",
|
"iced_renderer",
|
||||||
"iced_runtime",
|
"iced_runtime",
|
||||||
|
|
@ -2810,7 +2822,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_winit"
|
name = "iced_winit"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_runtime",
|
"iced_runtime",
|
||||||
|
|
@ -3154,7 +3166,7 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcosmic"
|
name = "libcosmic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#268b47d0002a5daa4cc50b124223737afe9a1dc5"
|
source = "git+https://github.com/pop-os/libcosmic.git#ce45af20f8f1d7c803b20c8af37fdd3adac641e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
|
|
@ -3439,6 +3451,12 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
|
|
@ -3483,9 +3501,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.10"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -3673,6 +3691,16 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "6.1.1"
|
version = "6.1.1"
|
||||||
|
|
@ -3687,7 +3715,7 @@ dependencies = [
|
||||||
"kqueue",
|
"kqueue",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"mio 0.8.10",
|
"mio 0.8.11",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
@ -5406,7 +5434,7 @@ dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"mio 0.8.10",
|
"mio 0.8.11",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
|
@ -6654,7 +6682,7 @@ dependencies = [
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"glob",
|
"glob",
|
||||||
"mime",
|
"mime",
|
||||||
"nom",
|
"nom 5.1.3",
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ vergen = { version = "8", features = ["git", "gitcl"] }
|
||||||
chrono = { version = "0.4", features = ["unstable-locales"] }
|
chrono = { version = "0.4", features = ["unstable-locales"] }
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
|
freedesktop_entry_parser = { version = "1.3", optional = true }
|
||||||
image = "0.24"
|
image = "0.24"
|
||||||
once_cell = "1.19"
|
once_cell = "1.19"
|
||||||
open = "5.0.2"
|
open = "5.0.2"
|
||||||
|
|
@ -24,6 +25,7 @@ paste = "1.0"
|
||||||
serde = { version = "1", features = ["serde_derive"] }
|
serde = { version = "1", features = ["serde_derive"] }
|
||||||
tokio = { version = "1" }
|
tokio = { version = "1" }
|
||||||
trash = "3.2.0"
|
trash = "3.2.0"
|
||||||
|
xdg = { version = "2.5.2", optional = true }
|
||||||
# Internationalization
|
# Internationalization
|
||||||
i18n-embed = { version = "0.14", features = [
|
i18n-embed = { version = "0.14", features = [
|
||||||
"fluent-system",
|
"fluent-system",
|
||||||
|
|
@ -46,8 +48,8 @@ features = ["serde"]
|
||||||
git = "https://github.com/jackpot51/systemicons"
|
git = "https://github.com/jackpot51/systemicons"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["xdg", "wgpu"]
|
default = ["desktop", "wgpu"]
|
||||||
xdg = ["libcosmic/desktop"]
|
desktop = ["libcosmic/desktop", "dep:freedesktop_entry_parser", "dep:xdg"]
|
||||||
wgpu = ["libcosmic/wgpu"]
|
wgpu = ["libcosmic/wgpu"]
|
||||||
|
|
||||||
[profile.release-with-debug]
|
[profile.release-with-debug]
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ light = Light
|
||||||
# Context menu
|
# Context menu
|
||||||
new-file = New file
|
new-file = New file
|
||||||
new-folder = New folder
|
new-folder = New folder
|
||||||
|
open-with = Open with
|
||||||
move-to-trash = Move to trash
|
move-to-trash = Move to trash
|
||||||
restore-from-trash = Restore from trash
|
restore-from-trash = Restore from trash
|
||||||
|
|
||||||
|
|
|
||||||
5
justfile
5
justfile
|
|
@ -52,7 +52,6 @@ check-json: (check '--message-format=json')
|
||||||
# Developer target
|
# Developer target
|
||||||
dev *args:
|
dev *args:
|
||||||
cargo fmt
|
cargo fmt
|
||||||
cargo test
|
|
||||||
just run {{args}}
|
just run {{args}}
|
||||||
|
|
||||||
# Run with debug logs
|
# Run with debug logs
|
||||||
|
|
@ -60,6 +59,10 @@ run *args:
|
||||||
cargo build --release
|
cargo build --release
|
||||||
env RUST_LOG=cosmic_files=debug RUST_BACKTRACE=full target/release/cosmic-files {{args}}
|
env RUST_LOG=cosmic_files=debug RUST_BACKTRACE=full target/release/cosmic-files {{args}}
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
test *args:
|
||||||
|
cargo test {{args}}
|
||||||
|
|
||||||
# Installs files
|
# Installs files
|
||||||
install:
|
install:
|
||||||
install -Dm0755 {{bin-src}} {{bin-dst}}
|
install -Dm0755 {{bin-src}} {{bin-dst}}
|
||||||
|
|
|
||||||
23
src/app.rs
23
src/app.rs
|
|
@ -58,6 +58,7 @@ pub enum Action {
|
||||||
NewFile,
|
NewFile,
|
||||||
NewFolder,
|
NewFolder,
|
||||||
Open,
|
Open,
|
||||||
|
OpenWith,
|
||||||
Operations,
|
Operations,
|
||||||
Paste,
|
Paste,
|
||||||
Properties,
|
Properties,
|
||||||
|
|
@ -94,6 +95,7 @@ impl Action {
|
||||||
Action::NewFile => Message::NewItem(entity_opt, false),
|
Action::NewFile => Message::NewItem(entity_opt, false),
|
||||||
Action::NewFolder => Message::NewItem(entity_opt, true),
|
Action::NewFolder => Message::NewItem(entity_opt, true),
|
||||||
Action::Open => Message::TabMessage(entity_opt, tab::Message::Open),
|
Action::Open => Message::TabMessage(entity_opt, tab::Message::Open),
|
||||||
|
Action::OpenWith => Message::ToggleContextPage(ContextPage::OpenWith),
|
||||||
Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
|
Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
|
||||||
Action::Paste => Message::Paste(entity_opt),
|
Action::Paste => Message::Paste(entity_opt),
|
||||||
Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
|
Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
|
||||||
|
|
@ -159,6 +161,7 @@ pub enum Message {
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum ContextPage {
|
pub enum ContextPage {
|
||||||
About,
|
About,
|
||||||
|
OpenWith,
|
||||||
Operations,
|
Operations,
|
||||||
Properties,
|
Properties,
|
||||||
Settings,
|
Settings,
|
||||||
|
|
@ -168,6 +171,7 @@ impl ContextPage {
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::About => String::new(),
|
Self::About => String::new(),
|
||||||
|
Self::OpenWith => fl!("open-with"),
|
||||||
Self::Operations => fl!("operations"),
|
Self::Operations => fl!("operations"),
|
||||||
Self::Properties => fl!("properties"),
|
Self::Properties => fl!("properties"),
|
||||||
Self::Settings => fl!("settings"),
|
Self::Settings => fl!("settings"),
|
||||||
|
|
@ -380,6 +384,24 @@ impl App {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_with(&self) -> Element<Message> {
|
||||||
|
let mut children = Vec::new();
|
||||||
|
let entity = self.tab_model.active();
|
||||||
|
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||||
|
if let Some(items) = tab.items_opt() {
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.selected {
|
||||||
|
children.push(item.open_with_view(tab.config.icon_sizes));
|
||||||
|
// Only show one property view to avoid issues like hangs when generating
|
||||||
|
// preview images on thousands of files
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
widget::settings::view_column(children).into()
|
||||||
|
}
|
||||||
|
|
||||||
fn operations(&self) -> Element<Message> {
|
fn operations(&self) -> Element<Message> {
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
|
|
||||||
|
|
@ -1101,6 +1123,7 @@ impl Application for App {
|
||||||
|
|
||||||
Some(match self.context_page {
|
Some(match self.context_page {
|
||||||
ContextPage::About => self.about(),
|
ContextPage::About => self.about(),
|
||||||
|
ContextPage::OpenWith => self.open_with(),
|
||||||
ContextPage::Operations => self.operations(),
|
ContextPage::Operations => self.operations(),
|
||||||
ContextPage::Properties => self.properties(),
|
ContextPage::Properties => self.properties(),
|
||||||
ContextPage::Settings => self.settings(),
|
ContextPage::Settings => self.settings(),
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,11 @@ pub mod dialog;
|
||||||
mod key_bind;
|
mod key_bind;
|
||||||
mod localize;
|
mod localize;
|
||||||
mod menu;
|
mod menu;
|
||||||
|
mod mime_app;
|
||||||
mod mime_icon;
|
mod mime_icon;
|
||||||
mod mouse_area;
|
mod mouse_area;
|
||||||
mod operation;
|
mod operation;
|
||||||
mod tab;
|
mod tab;
|
||||||
#[cfg(feature = "xdg")]
|
|
||||||
mod xdg;
|
|
||||||
|
|
||||||
pub fn home_dir() -> PathBuf {
|
pub fn home_dir() -> PathBuf {
|
||||||
match dirs::home_dir() {
|
match dirs::home_dir() {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,9 @@ pub fn context_menu<'a>(
|
||||||
Location::Path(_) => {
|
Location::Path(_) => {
|
||||||
if selected > 0 {
|
if selected > 0 {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open).into());
|
||||||
//TODO: Open with
|
if selected == 1 {
|
||||||
|
children.push(menu_item(fl!("open-with"), Action::OpenWith).into());
|
||||||
|
}
|
||||||
children.push(horizontal_rule(1).into());
|
children.push(horizontal_rule(1).into());
|
||||||
children.push(menu_item(fl!("rename"), Action::Rename).into());
|
children.push(menu_item(fl!("rename"), Action::Rename).into());
|
||||||
children.push(menu_item(fl!("cut"), Action::Cut).into());
|
children.push(menu_item(fl!("cut"), Action::Cut).into());
|
||||||
|
|
|
||||||
204
src/mime_app.rs
Normal file
204
src/mime_app.rs
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
use cosmic::desktop;
|
||||||
|
use cosmic::widget;
|
||||||
|
pub use mime_guess::Mime;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::{collections::HashMap, path::PathBuf, sync::Mutex, time::Instant};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MimeApp {
|
||||||
|
pub id: String,
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
|
pub name: String,
|
||||||
|
pub exec: Option<String>,
|
||||||
|
pub icon: widget::icon::Handle,
|
||||||
|
pub is_default: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
impl From<&desktop::DesktopEntryData> for MimeApp {
|
||||||
|
fn from(app: &desktop::DesktopEntryData) -> Self {
|
||||||
|
Self {
|
||||||
|
id: app.id.clone(),
|
||||||
|
path: app.path.clone(),
|
||||||
|
name: app.name.clone(),
|
||||||
|
exec: app.exec.clone(),
|
||||||
|
icon: match &app.icon {
|
||||||
|
desktop::IconSource::Name(name) => widget::icon::from_name(name.as_str()).handle(),
|
||||||
|
desktop::IconSource::Path(path) => widget::icon::from_path(path.clone()),
|
||||||
|
},
|
||||||
|
is_default: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
fn filename_eq(path_opt: &Option<PathBuf>, filename: &str) -> bool {
|
||||||
|
path_opt
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|path| path.file_name())
|
||||||
|
.map(|x| x == filename)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MimeAppCache {
|
||||||
|
cache: HashMap<Mime, Vec<MimeApp>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MimeAppCache {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut mime_app_cache = Self {
|
||||||
|
cache: HashMap::new(),
|
||||||
|
};
|
||||||
|
mime_app_cache.reload();
|
||||||
|
mime_app_cache
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
pub fn reload(&mut self) {}
|
||||||
|
|
||||||
|
// Only available when using desktop feature of libcosmic, which only works on Unix-likes
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
pub fn reload(&mut self) {
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
self.cache.clear();
|
||||||
|
|
||||||
|
//TODO: get proper locale?
|
||||||
|
let locale = None;
|
||||||
|
|
||||||
|
// Load desktop applications by supported mime types
|
||||||
|
//TODO: hashmap for all apps by id?
|
||||||
|
let all_apps = desktop::load_applications(locale, false);
|
||||||
|
for app in all_apps.iter() {
|
||||||
|
for mime in app.mime_types.iter() {
|
||||||
|
let apps = self
|
||||||
|
.cache
|
||||||
|
.entry(mime.clone())
|
||||||
|
.or_insert_with(|| Vec::with_capacity(1));
|
||||||
|
if apps.iter().find(|x| x.id == app.id).is_none() {
|
||||||
|
apps.push(MimeApp::from(app));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load mimeapps.list files
|
||||||
|
// https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html
|
||||||
|
//TODO: support lookup by desktop (colon separated list in $XDG_CURRENT_DESKTOP, converted to lowercase)
|
||||||
|
let mut mimeapps_paths = Vec::new();
|
||||||
|
match xdg::BaseDirectories::new() {
|
||||||
|
Ok(xdg_dirs) => {
|
||||||
|
for path in xdg_dirs.find_data_files("applications/mimeapps.list") {
|
||||||
|
mimeapps_paths.push(path);
|
||||||
|
}
|
||||||
|
for path in xdg_dirs.find_config_files("mimeapps.list") {
|
||||||
|
mimeapps_paths.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to get xdg base directories: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: handle directory specific behavior
|
||||||
|
for path in mimeapps_paths {
|
||||||
|
let entry = match freedesktop_entry_parser::parse_entry(&path) {
|
||||||
|
Ok(ok) => ok,
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to parse {:?}: {}", path, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for attr in entry.section("Added Associations").attrs() {
|
||||||
|
if let Ok(mime) = attr.name.parse::<Mime>() {
|
||||||
|
if let Some(filenames) = attr.value {
|
||||||
|
for filename in filenames.split_terminator(';') {
|
||||||
|
println!("Add {}={}", mime, filename);
|
||||||
|
let apps = self
|
||||||
|
.cache
|
||||||
|
.entry(mime.clone())
|
||||||
|
.or_insert_with(|| Vec::with_capacity(1));
|
||||||
|
if apps
|
||||||
|
.iter()
|
||||||
|
.find(|x| filename_eq(&x.path, filename))
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
if let Some(app) =
|
||||||
|
all_apps.iter().find(|x| filename_eq(&x.path, filename))
|
||||||
|
{
|
||||||
|
apps.push(MimeApp::from(app));
|
||||||
|
} else {
|
||||||
|
log::warn!("failed to find application {:?}", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in entry.section("Removed Associations").attrs() {
|
||||||
|
if let Ok(mime) = attr.name.parse::<Mime>() {
|
||||||
|
if let Some(filenames) = attr.value {
|
||||||
|
for filename in filenames.split_terminator(';') {
|
||||||
|
println!("Remove {}={}", mime, filename);
|
||||||
|
if let Some(apps) = self.cache.get_mut(&mime) {
|
||||||
|
apps.retain(|x| !filename_eq(&x.path, filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in entry.section("Default Applications").attrs() {
|
||||||
|
if let Ok(mime) = attr.name.parse::<Mime>() {
|
||||||
|
if let Some(filenames) = attr.value {
|
||||||
|
for filename in filenames.split_terminator(';') {
|
||||||
|
println!("Default {}={}", mime, filename);
|
||||||
|
if let Some(apps) = self.cache.get_mut(&mime) {
|
||||||
|
let mut found = false;
|
||||||
|
for app in apps.iter_mut() {
|
||||||
|
if filename_eq(&app.path, filename) {
|
||||||
|
app.is_default = true;
|
||||||
|
found = true;
|
||||||
|
} else {
|
||||||
|
app.is_default = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
log::warn!("failed to find application {:?}", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort apps by name
|
||||||
|
for apps in self.cache.values_mut() {
|
||||||
|
apps.sort_by(|a, b| lexical_sort::natural_lexical_cmp(&a.name, &b.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static MIME_APP_CACHE: Lazy<Mutex<MimeAppCache>> = Lazy::new(|| Mutex::new(MimeAppCache::new()));
|
||||||
|
|
||||||
|
pub fn mime_apps(mime: &Mime) -> Vec<MimeApp> {
|
||||||
|
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
||||||
|
mime_app_cache.get(mime)
|
||||||
|
}
|
||||||
125
src/tab.rs
125
src/tab.rs
|
|
@ -20,20 +20,17 @@ use cosmic::{
|
||||||
},
|
},
|
||||||
theme, widget, Element,
|
theme, widget, Element,
|
||||||
};
|
};
|
||||||
use mime_guess::MimeGuess;
|
use mime_guess::{mime, Mime, MimeGuess};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
|
||||||
fs::{self, Metadata},
|
fs::{self, Metadata},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "xdg")]
|
|
||||||
use crate::xdg::{mime_apps, DesktopEntryData};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::Action,
|
app::Action,
|
||||||
config::{IconSizes, TabConfig},
|
config::{IconSizes, TabConfig},
|
||||||
|
|
@ -41,6 +38,7 @@ use crate::{
|
||||||
fl,
|
fl,
|
||||||
key_bind::KeyBind,
|
key_bind::KeyBind,
|
||||||
menu,
|
menu,
|
||||||
|
mime_app::{mime_apps, MimeApp},
|
||||||
mime_icon::mime_icon,
|
mime_icon::mime_icon,
|
||||||
mouse_area,
|
mouse_area,
|
||||||
};
|
};
|
||||||
|
|
@ -224,23 +222,39 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
let mime_guess = MimeGuess::from_path(&path);
|
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
||||||
|
|
||||||
let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
(
|
(
|
||||||
|
//TODO: make this a static
|
||||||
|
"inode/directory".parse().unwrap(),
|
||||||
folder_icon(&path, sizes.grid()),
|
folder_icon(&path, sizes.grid()),
|
||||||
folder_icon(&path, sizes.list()),
|
folder_icon(&path, sizes.list()),
|
||||||
folder_icon(&path, sizes.list_condensed()),
|
folder_icon(&path, sizes.list_condensed()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
//TODO: best fallback mime for files?
|
||||||
|
MimeGuess::from_path(&path).first_or_octet_stream(),
|
||||||
mime_icon(&path, sizes.grid()),
|
mime_icon(&path, sizes.grid()),
|
||||||
mime_icon(&path, sizes.list()),
|
mime_icon(&path, sizes.list()),
|
||||||
mime_icon(&path, sizes.list_condensed()),
|
mime_icon(&path, sizes.list_condensed()),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut open_with = mime_apps(&mime);
|
||||||
|
if open_with.is_empty() {
|
||||||
|
//TODO: more fallbacks
|
||||||
|
if mime.type_() == "text" {
|
||||||
|
open_with = mime_apps(&mime::TEXT_PLAIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let thumbnail_res_opt = if mime.type_() == "image" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Err(()))
|
||||||
|
};
|
||||||
|
|
||||||
let children = if metadata.is_dir() {
|
let children = if metadata.is_dir() {
|
||||||
//TODO: calculate children in the background (and make it cancellable?)
|
//TODO: calculate children in the background (and make it cancellable?)
|
||||||
match fs::read_dir(&path) {
|
match fs::read_dir(&path) {
|
||||||
|
|
@ -259,19 +273,12 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
metadata: ItemMetadata::Path { metadata, children },
|
metadata: ItemMetadata::Path { metadata, children },
|
||||||
hidden,
|
hidden,
|
||||||
path,
|
path,
|
||||||
mime_guess,
|
mime,
|
||||||
icon_handle_grid,
|
icon_handle_grid,
|
||||||
icon_handle_list,
|
icon_handle_list,
|
||||||
icon_handle_list_condensed,
|
icon_handle_list_condensed,
|
||||||
#[cfg(feature = "xdg")]
|
open_with,
|
||||||
open_with: mime_guess
|
thumbnail_res_opt,
|
||||||
.first()
|
|
||||||
.map(|mime| mime_apps(&mime))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
thumbnail_res_opt: match mime_guess.first() {
|
|
||||||
Some(mime) if mime.type_() == "image" => None,
|
|
||||||
_ => Some(Err(())),
|
|
||||||
},
|
|
||||||
button_id: widget::Id::unique(),
|
button_id: widget::Id::unique(),
|
||||||
pos_opt: Cell::new(None),
|
pos_opt: Cell::new(None),
|
||||||
rect_opt: Cell::new(None),
|
rect_opt: Cell::new(None),
|
||||||
|
|
@ -333,16 +340,18 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
||||||
let path = entry.original_path();
|
let path = entry.original_path();
|
||||||
let name = entry.name.clone();
|
let name = entry.name.clone();
|
||||||
|
|
||||||
let mime_guess = MimeGuess::from_path(&path);
|
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
||||||
|
|
||||||
let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) =
|
|
||||||
match metadata.size {
|
match metadata.size {
|
||||||
trash::TrashItemSize::Entries(_) => (
|
trash::TrashItemSize::Entries(_) => (
|
||||||
|
//TODO: make this a static
|
||||||
|
"inode/directory".parse().unwrap(),
|
||||||
folder_icon(&path, sizes.grid()),
|
folder_icon(&path, sizes.grid()),
|
||||||
folder_icon(&path, sizes.list()),
|
folder_icon(&path, sizes.list()),
|
||||||
folder_icon(&path, sizes.list_condensed()),
|
folder_icon(&path, sizes.list_condensed()),
|
||||||
),
|
),
|
||||||
trash::TrashItemSize::Bytes(_) => (
|
trash::TrashItemSize::Bytes(_) => (
|
||||||
|
//TODO: best fallback mime for files?
|
||||||
|
MimeGuess::from_path(&path).first_or_octet_stream(),
|
||||||
mime_icon(&path, sizes.grid()),
|
mime_icon(&path, sizes.grid()),
|
||||||
mime_icon(&path, sizes.list()),
|
mime_icon(&path, sizes.list()),
|
||||||
mime_icon(&path, sizes.list_condensed()),
|
mime_icon(&path, sizes.list_condensed()),
|
||||||
|
|
@ -354,11 +363,10 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
||||||
metadata: ItemMetadata::Trash { metadata, entry },
|
metadata: ItemMetadata::Trash { metadata, entry },
|
||||||
hidden: false,
|
hidden: false,
|
||||||
path,
|
path,
|
||||||
mime_guess,
|
mime,
|
||||||
icon_handle_grid,
|
icon_handle_grid,
|
||||||
icon_handle_list,
|
icon_handle_list,
|
||||||
icon_handle_list_condensed,
|
icon_handle_list_condensed,
|
||||||
#[cfg(feature = "xdg")]
|
|
||||||
open_with: Vec::new(),
|
open_with: Vec::new(),
|
||||||
thumbnail_res_opt: Some(Err(())),
|
thumbnail_res_opt: Some(Err(())),
|
||||||
button_id: widget::Id::unique(),
|
button_id: widget::Id::unique(),
|
||||||
|
|
@ -457,18 +465,17 @@ impl ItemMetadata {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub metadata: ItemMetadata,
|
pub metadata: ItemMetadata,
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub mime_guess: MimeGuess,
|
pub mime: Mime,
|
||||||
pub icon_handle_grid: widget::icon::Handle,
|
pub icon_handle_grid: widget::icon::Handle,
|
||||||
pub icon_handle_list: widget::icon::Handle,
|
pub icon_handle_list: widget::icon::Handle,
|
||||||
pub icon_handle_list_condensed: widget::icon::Handle,
|
pub icon_handle_list_condensed: widget::icon::Handle,
|
||||||
#[cfg(feature = "xdg")]
|
pub open_with: Vec<MimeApp>,
|
||||||
pub open_with: Vec<DesktopEntryData>,
|
|
||||||
pub thumbnail_res_opt: Option<Result<image::RgbaImage, ()>>,
|
pub thumbnail_res_opt: Option<Result<image::RgbaImage, ()>>,
|
||||||
pub button_id: widget::Id,
|
pub button_id: widget::Id,
|
||||||
pub pos_opt: Cell<Option<(usize, usize)>>,
|
pub pos_opt: Cell<Option<(usize, usize)>>,
|
||||||
|
|
@ -478,20 +485,47 @@ pub struct Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
|
pub fn open_with_view(&self, sizes: IconSizes) -> Element<crate::app::Message> {
|
||||||
|
let cosmic_theme::Spacing {
|
||||||
|
space_xs,
|
||||||
|
space_xxxs,
|
||||||
|
..
|
||||||
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
|
let mut column = widget::column().spacing(space_xxxs);
|
||||||
|
|
||||||
|
column = column.push(widget::text::heading(&self.name));
|
||||||
|
|
||||||
|
for app in self.open_with.iter() {
|
||||||
|
column = column.push(
|
||||||
|
widget::button(
|
||||||
|
widget::row::with_children(vec![
|
||||||
|
widget::icon(app.icon.clone()).into(),
|
||||||
|
widget::text(&app.name).into(),
|
||||||
|
])
|
||||||
|
.spacing(space_xs),
|
||||||
|
)
|
||||||
|
.padding(space_xs)
|
||||||
|
.width(Length::Fill),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
column.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn property_view(&self, sizes: IconSizes) -> Element<crate::app::Message> {
|
pub fn property_view(&self, sizes: IconSizes) -> Element<crate::app::Message> {
|
||||||
let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing;
|
let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
let mut column = widget::column().spacing(space_xxxs);
|
let mut column = widget::column().spacing(space_xxxs);
|
||||||
|
|
||||||
let is_image = if let Some(mime) = self.mime_guess.first() {
|
|
||||||
mime.type_() == "image" && self.path.is_file()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
column = column.push(widget::row::with_children(vec![
|
column = column.push(widget::row::with_children(vec![
|
||||||
widget::horizontal_space(Length::Fill).into(),
|
widget::horizontal_space(Length::Fill).into(),
|
||||||
if is_image {
|
// This loads the image only if thumbnailing worked
|
||||||
|
if self
|
||||||
|
.thumbnail_res_opt
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |res| res.is_ok())
|
||||||
|
{
|
||||||
widget::image::viewer(widget::image::Handle::from_path(&self.path))
|
widget::image::viewer(widget::image::Handle::from_path(&self.path))
|
||||||
.min_scale(1.0)
|
.min_scale(1.0)
|
||||||
.into()
|
.into()
|
||||||
|
|
@ -506,9 +540,7 @@ impl Item {
|
||||||
|
|
||||||
column = column.push(widget::text::heading(self.name.clone()));
|
column = column.push(widget::text::heading(self.name.clone()));
|
||||||
|
|
||||||
if let Some(mime) = self.mime_guess.first() {
|
column = column.push(widget::text(format!("Type: {}", self.mime)));
|
||||||
column = column.push(widget::text(format!("Type: {}", mime)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: translate!
|
//TODO: translate!
|
||||||
//TODO: correct display of folder size?
|
//TODO: correct display of folder size?
|
||||||
|
|
@ -553,27 +585,6 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Item {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let mut d = f.debug_struct("Item");
|
|
||||||
d.field("name", &self.name);
|
|
||||||
d.field("metadata", &self.metadata);
|
|
||||||
d.field("hidden", &self.hidden);
|
|
||||||
d.field("path", &self.path);
|
|
||||||
d.field("mime_guess", &self.mime_guess);
|
|
||||||
// icon_handles
|
|
||||||
#[cfg(feature = "xdg")]
|
|
||||||
d.field("open_with", &self.open_with);
|
|
||||||
// thumbnail_res_opt
|
|
||||||
d.field("button_id", &self.button_id);
|
|
||||||
d.field("pos_opt", &self.pos_opt);
|
|
||||||
d.field("rect_opt", &self.rect_opt);
|
|
||||||
d.field("selected", &self.selected);
|
|
||||||
d.field("click_time", &self.click_time);
|
|
||||||
d.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum View {
|
pub enum View {
|
||||||
Grid,
|
Grid,
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
pub use cosmic::desktop::DesktopEntryData;
|
|
||||||
use cosmic::desktop::{load_applications, Mime};
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use std::{collections::HashMap, sync::Mutex, time::Instant};
|
|
||||||
|
|
||||||
pub struct MimeAppCache {
|
|
||||||
cache: HashMap<Mime, Vec<DesktopEntryData>>,
|
|
||||||
empty: Vec<DesktopEntryData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MimeAppCache {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut mime_app_cache = Self {
|
|
||||||
cache: HashMap::new(),
|
|
||||||
empty: Vec::new(),
|
|
||||||
};
|
|
||||||
mime_app_cache.reload();
|
|
||||||
mime_app_cache
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reload(&mut self) {
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
self.cache.clear();
|
|
||||||
|
|
||||||
//TODO: get proper locale?
|
|
||||||
let locale = None;
|
|
||||||
for app in load_applications(locale, false) {
|
|
||||||
for mime_type in app.mime_types.iter() {
|
|
||||||
self.cache
|
|
||||||
.entry(mime_type.clone())
|
|
||||||
.or_insert_with(|| Vec::with_capacity(1))
|
|
||||||
.push(app.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for apps in self.cache.values_mut() {
|
|
||||||
apps.sort_by(|a, b| lexical_sort::natural_lexical_cmp(&a.name, &b.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
|
||||||
log::info!("loaded mime app cache in {:?}", elapsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, key: &Mime) -> &Vec<DesktopEntryData> {
|
|
||||||
self.cache.get(&key).unwrap_or_else(|| &self.empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static MIME_APP_CACHE: Lazy<Mutex<MimeAppCache>> = Lazy::new(|| Mutex::new(MimeAppCache::new()));
|
|
||||||
|
|
||||||
pub fn mime_apps(mime: &Mime) -> Vec<DesktopEntryData> {
|
|
||||||
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
|
||||||
mime_app_cache.get(mime).clone()
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
pub mod mime_app;
|
|
||||||
pub use mime_app::*;
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue