Compare commits
80 commits
pre-1.6-me
...
local/libc
| Author | SHA1 | Date | |
|---|---|---|---|
| 20842026d7 | |||
| 4b5fcfe5d7 | |||
|
|
d1f0af78e6 | ||
|
|
87f407e3ed | ||
|
|
e2cad979ce | ||
|
|
b326e48cf6 | ||
|
|
c0b8a8c60a | ||
|
|
fe71aca0e5 | ||
|
|
d6e7618b76 | ||
|
|
c576bbcd60 | ||
|
|
762fc8fb48 | ||
|
|
7ba55f66cc | ||
|
|
b7005660f1 | ||
|
|
77f062647c | ||
|
|
00233428b3 | ||
| 98159d317c | |||
| e8eb42b507 | |||
| dd57647ced | |||
|
|
089ad2b417 | ||
|
|
1761b9b84b | ||
|
|
06278ee7f1 | ||
|
|
a412787d69 | ||
|
|
f3b8f6f585 | ||
|
|
de739425cb | ||
| 35334ba93b | |||
| deb6000c10 | |||
|
|
67af455898 | ||
|
|
b46b77f3a7 | ||
|
|
9642fef9cd | ||
|
|
0afac77e83 | ||
|
|
e84d3be4fd | ||
|
|
bb8b61f48b | ||
|
|
7cebbef82f | ||
| 0f6f9509ae | |||
|
|
08a637767d | ||
|
|
3d520858f3 | ||
|
|
28546795b0 | ||
|
|
cca10d2fd3 | ||
|
|
eebf5a9d4c | ||
|
|
a5422167cf | ||
|
|
3aa55b07b7 | ||
| 1488e2b01b | |||
|
|
fd6d4523cd | ||
|
|
9bdba47514 | ||
|
|
3c9a78ac9f | ||
|
|
e96b915f63 | ||
|
|
9ff853c46d | ||
|
|
6e210a3753 | ||
|
|
9c841dbacd | ||
|
|
991e5b234e | ||
|
|
78ac96c613 | ||
|
|
55c1b0afe0 | ||
|
|
e3aa2a0ec5 | ||
|
|
6273fe6505 | ||
|
|
5bdfffa494 | ||
|
|
95035166d3 | ||
|
|
24e34eaa0f | ||
|
|
0875cda769 | ||
|
|
ebce599f3a | ||
|
|
d6f6179e67 | ||
|
|
9a4f78aa75 | ||
|
|
a1c1aff60c | ||
|
|
9a21542825 | ||
|
|
7ae2621f70 | ||
|
|
eb04ae28da | ||
|
|
dc36bdc8d3 | ||
|
|
8ef1082a4c | ||
|
|
a93fc1d9ee | ||
|
|
5278c67957 | ||
|
|
6c45017b24 | ||
|
|
b1fbc1d538 | ||
|
|
c4a9096ae2 | ||
|
|
fab53e54d6 | ||
|
|
168ff6d6f8 | ||
|
|
908218e3e0 | ||
|
|
8fc5182486 | ||
|
|
e00725a450 | ||
|
|
0e761ba811 | ||
|
|
674a33e3de | ||
|
|
6fe510a67a |
55 changed files with 3292 additions and 1888 deletions
1789
Cargo.lock
generated
1789
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
14
Cargo.toml
14
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "cosmic-files"
|
name = "cosmic-files"
|
||||||
version = "1.3.0"
|
version = "1.9.0"
|
||||||
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
@ -11,16 +11,16 @@ anyhow = "1"
|
||||||
jiff = "0.2"
|
jiff = "0.2"
|
||||||
jiff-icu = "0.2"
|
jiff-icu = "0.2"
|
||||||
icu = { version = "2.2.0", features = ["compiled_data"] }
|
icu = { version = "2.2.0", features = ["compiled_data"] }
|
||||||
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c253ec1", optional = true }
|
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c0cff4d", optional = true }
|
||||||
cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true }
|
cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true }
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
gio = { version = "0.21", optional = true }
|
gio = { version = "0.21", optional = true }
|
||||||
glib = { version = "0.21", optional = true }
|
glib = { version = "0.21", optional = true }
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
ignore = "0.4"
|
ignore = "0.4"
|
||||||
image = "0.25"
|
image.workspace = true
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log.workspace = true
|
||||||
mime_guess = "2"
|
mime_guess = "2"
|
||||||
notify-debouncer-full = "0.7"
|
notify-debouncer-full = "0.7"
|
||||||
notify-rust = { version = "4", optional = true }
|
notify-rust = { version = "4", optional = true }
|
||||||
|
|
@ -166,4 +166,8 @@ mime = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch =
|
||||||
cosmic-text = { path = "../cosmic-text" }
|
cosmic-text = { path = "../cosmic-text" }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["cosmic-files-applet"]
|
members = ["cosmic-files-applet", "cosmic-files-thumbnailer"]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
image = "0.25"
|
||||||
|
log = "0.4"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
[package]
|
[package]
|
||||||
name = "cosmic-files-applet"
|
name = "cosmic-files-applet"
|
||||||
version = "1.2.0"
|
version = "1.9.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log.workspace = true
|
||||||
zbus = "4" # Blocking connection in zbus 5 hangs
|
zbus = "4" # Blocking connection in zbus 5 hangs
|
||||||
|
|
||||||
[dependencies.cosmic-files]
|
[dependencies.cosmic-files]
|
||||||
|
|
|
||||||
8
cosmic-files-thumbnailer/Cargo.toml
Normal file
8
cosmic-files-thumbnailer/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "cosmic-files-thumbnailer"
|
||||||
|
version = "1.9.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
image.workspace = true
|
||||||
|
pelite = "0.10"
|
||||||
254
cosmic-files-thumbnailer/src/main.rs
Normal file
254
cosmic-files-thumbnailer/src/main.rs
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use image::{DynamicImage, ImageFormat, RgbaImage};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
thumbnail_from_args(std::env::args_os().skip(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn thumbnail_from_args(mut args: impl Iterator<Item = OsString>) -> Result<(), Box<dyn Error>> {
|
||||||
|
let usage = || {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"usage: cosmic-files-thumbnailer OUTPUT --size SIZE INPUT",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let output = args.next().ok_or_else(usage)?;
|
||||||
|
if args.next().as_deref() != Some(OsStr::new("--size")) {
|
||||||
|
return Err(usage().into());
|
||||||
|
}
|
||||||
|
let size = args
|
||||||
|
.next()
|
||||||
|
.and_then(|arg| arg.into_string().ok())
|
||||||
|
.and_then(|arg| arg.parse::<u32>().ok())
|
||||||
|
.filter(|size| *size > 0)
|
||||||
|
.ok_or_else(usage)?;
|
||||||
|
let input = args.next().ok_or_else(usage)?;
|
||||||
|
if args.next().is_some() {
|
||||||
|
return Err(usage().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
thumbnail(Path::new(&input), Path::new(&output), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn thumbnail(input: &Path, output: &Path, size: u32) -> Result<(), Box<dyn Error>> {
|
||||||
|
let icon = thumbnail_image(input, size)?;
|
||||||
|
DynamicImage::ImageRgba8(icon).save_with_format(output, ImageFormat::Png)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn thumbnail_image(input: &Path, size: u32) -> Result<RgbaImage, Box<dyn Error>> {
|
||||||
|
if size == 0 {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"thumbnail size must be positive",
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the PE so only the headers and resource pages touched by pelite are read.
|
||||||
|
let data = pelite::FileMap::open(input)?;
|
||||||
|
let bytes = data.as_ref();
|
||||||
|
if bytes.len() < 64 || !bytes.starts_with(b"MZ") {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, "input is not a PE file").into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = pelite::PeFile::from_bytes(bytes).map_err(invalid_data)?;
|
||||||
|
let resources = file.resources().map_err(invalid_data)?;
|
||||||
|
let (_name, group) = resources
|
||||||
|
.icons()
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "PE file has no icon group"))?
|
||||||
|
.map_err(invalid_data)?;
|
||||||
|
|
||||||
|
let mut ico = Vec::new();
|
||||||
|
group.write(&mut ico).map_err(invalid_data)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
DynamicImage::ImageRgba8(largest_icon(&ico).map_err(invalid_data)?)
|
||||||
|
.thumbnail(size, size)
|
||||||
|
.into_rgba8(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_data(error: impl std::fmt::Display) -> io::Error {
|
||||||
|
io::Error::new(io::ErrorKind::InvalidData, error.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn largest_icon(ico: &[u8]) -> Result<RgbaImage, String> {
|
||||||
|
if ico.len() < 6 {
|
||||||
|
return Err("ICO header is truncated".to_string());
|
||||||
|
}
|
||||||
|
let count = usize::from(u16::from_le_bytes([ico[4], ico[5]]));
|
||||||
|
let mut best: Option<(u64, RgbaImage)> = None;
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..count.min(32) {
|
||||||
|
let entry = 6 + i * 16;
|
||||||
|
if ico.len() < entry + 16 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let size = u32::from_le_bytes([
|
||||||
|
ico[entry + 8],
|
||||||
|
ico[entry + 9],
|
||||||
|
ico[entry + 10],
|
||||||
|
ico[entry + 11],
|
||||||
|
]) as usize;
|
||||||
|
let offset = u32::from_le_bytes([
|
||||||
|
ico[entry + 12],
|
||||||
|
ico[entry + 13],
|
||||||
|
ico[entry + 14],
|
||||||
|
ico[entry + 15],
|
||||||
|
]) as usize;
|
||||||
|
let Some(end) = offset.checked_add(size) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(data) = ico.get(offset..end) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
match decode_icon(&ico[entry..entry + 16], data) {
|
||||||
|
Ok(image) => {
|
||||||
|
let pixels = u64::from(image.width()) * u64::from(image.height());
|
||||||
|
if best
|
||||||
|
.as_ref()
|
||||||
|
.is_none_or(|(best_pixels, _)| pixels > *best_pixels)
|
||||||
|
{
|
||||||
|
best = Some((pixels, image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => errors.push(format!("frame {i}: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best.map(|(_, image)| image).ok_or_else(|| {
|
||||||
|
if errors.is_empty() {
|
||||||
|
"PE icon contains no complete frames".to_string()
|
||||||
|
} else {
|
||||||
|
format!("PE icon could not be decoded ({})", errors.join("; "))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_icon(entry: &[u8], data: &[u8]) -> Result<RgbaImage, String> {
|
||||||
|
if data.starts_with(b"\x89PNG\r\n\x1a\n") {
|
||||||
|
return image::ImageReader::with_format(io::Cursor::new(data), ImageFormat::Png)
|
||||||
|
.decode()
|
||||||
|
.map(DynamicImage::into_rgba8)
|
||||||
|
.map_err(|err| err.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let capacity = 22usize
|
||||||
|
.checked_add(data.len())
|
||||||
|
.ok_or_else(|| "frame is too large".to_string())?;
|
||||||
|
let data_len = u32::try_from(data.len()).map_err(|_| "frame is too large".to_string())?;
|
||||||
|
let mut ico = Vec::with_capacity(capacity);
|
||||||
|
ico.extend_from_slice(&[0, 0, 1, 0, 1, 0]);
|
||||||
|
ico.extend_from_slice(entry);
|
||||||
|
ico[14..18].copy_from_slice(&data_len.to_le_bytes());
|
||||||
|
ico[18..22].copy_from_slice(&22u32.to_le_bytes());
|
||||||
|
ico.extend_from_slice(data);
|
||||||
|
|
||||||
|
image::ImageReader::with_format(io::Cursor::new(ico), ImageFormat::Ico)
|
||||||
|
.decode()
|
||||||
|
.map(DynamicImage::into_rgba8)
|
||||||
|
.map_err(|err| err.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{largest_icon, thumbnail_from_args};
|
||||||
|
use image::{DynamicImage, ImageFormat, Rgb, RgbImage, Rgba, RgbaImage};
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn malformed_thumbnail_request_returns_an_error() {
|
||||||
|
let args = [OsString::from("output.png")];
|
||||||
|
assert!(thumbnail_from_args(args.into_iter()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn largest_icon_skips_invalid_entries() {
|
||||||
|
let image = RgbaImage::from_pixel(2, 2, Rgba([1, 2, 3, 255]));
|
||||||
|
let mut png = Cursor::new(Vec::new());
|
||||||
|
DynamicImage::ImageRgba8(image)
|
||||||
|
.write_to(&mut png, ImageFormat::Png)
|
||||||
|
.unwrap();
|
||||||
|
let png = png.into_inner();
|
||||||
|
|
||||||
|
let mut ico = vec![0, 0, 1, 0, 2, 0];
|
||||||
|
let mut invalid_entry = [0; 16];
|
||||||
|
invalid_entry[8..12].copy_from_slice(&4u32.to_le_bytes());
|
||||||
|
invalid_entry[12..16].copy_from_slice(&u32::MAX.to_le_bytes());
|
||||||
|
ico.extend_from_slice(&invalid_entry);
|
||||||
|
|
||||||
|
let mut valid_entry = [0; 16];
|
||||||
|
valid_entry[..8].copy_from_slice(&[2, 2, 0, 0, 1, 0, 32, 0]);
|
||||||
|
valid_entry[8..12].copy_from_slice(&u32::try_from(png.len()).unwrap().to_le_bytes());
|
||||||
|
valid_entry[12..16].copy_from_slice(&38u32.to_le_bytes());
|
||||||
|
ico.extend_from_slice(&valid_entry);
|
||||||
|
ico.extend_from_slice(&png);
|
||||||
|
|
||||||
|
let decoded = largest_icon(&ico).expect("valid icon after malformed entry");
|
||||||
|
assert_eq!(decoded.dimensions(), (2, 2));
|
||||||
|
assert_eq!(decoded.get_pixel(0, 0), &Rgba([1, 2, 3, 255]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dib_and_mask_is_applied() {
|
||||||
|
let mut dib = vec![0; 40];
|
||||||
|
dib[0..4].copy_from_slice(&40u32.to_le_bytes());
|
||||||
|
dib[4..8].copy_from_slice(&2i32.to_le_bytes());
|
||||||
|
dib[8..12].copy_from_slice(&4i32.to_le_bytes());
|
||||||
|
dib[12..14].copy_from_slice(&1u16.to_le_bytes());
|
||||||
|
dib[14..16].copy_from_slice(&24u16.to_le_bytes());
|
||||||
|
|
||||||
|
// Two bottom-up BGR rows, padded to four-byte boundaries.
|
||||||
|
dib.extend_from_slice(&[0, 0, 255, 0, 0, 255, 0, 0]);
|
||||||
|
dib.extend_from_slice(&[0, 0, 255, 0, 0, 255, 0, 0]);
|
||||||
|
// The first mask row is the bottom image row; its first pixel is transparent.
|
||||||
|
dib.extend_from_slice(&[0b1000_0000, 0, 0, 0]);
|
||||||
|
dib.extend_from_slice(&[0, 0, 0, 0]);
|
||||||
|
|
||||||
|
let mut ico = vec![0, 0, 1, 0, 1, 0];
|
||||||
|
let mut entry = [0; 16];
|
||||||
|
entry[..8].copy_from_slice(&[2, 2, 0, 0, 1, 0, 24, 0]);
|
||||||
|
entry[8..12].copy_from_slice(&u32::try_from(dib.len()).unwrap().to_le_bytes());
|
||||||
|
entry[12..16].copy_from_slice(&22u32.to_le_bytes());
|
||||||
|
ico.extend_from_slice(&entry);
|
||||||
|
ico.extend_from_slice(&dib);
|
||||||
|
|
||||||
|
let decoded = largest_icon(&ico).expect("valid DIB icon");
|
||||||
|
assert_eq!(decoded.get_pixel(0, 0), &Rgba([255, 0, 0, 255]));
|
||||||
|
assert_eq!(decoded.get_pixel(0, 1), &Rgba([255, 0, 0, 0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rgb_png_icon_is_decoded() {
|
||||||
|
let image = RgbImage::from_pixel(2, 2, Rgb([1, 2, 3]));
|
||||||
|
let mut png = Cursor::new(Vec::new());
|
||||||
|
DynamicImage::ImageRgb8(image)
|
||||||
|
.write_to(&mut png, ImageFormat::Png)
|
||||||
|
.unwrap();
|
||||||
|
let png = png.into_inner();
|
||||||
|
|
||||||
|
let mut ico = vec![0, 0, 1, 0, 1, 0];
|
||||||
|
let mut entry = [0; 16];
|
||||||
|
entry[..8].copy_from_slice(&[2, 2, 0, 0, 1, 0, 24, 0]);
|
||||||
|
entry[8..12].copy_from_slice(&u32::try_from(png.len()).unwrap().to_le_bytes());
|
||||||
|
entry[12..16].copy_from_slice(&22u32.to_le_bytes());
|
||||||
|
ico.extend_from_slice(&entry);
|
||||||
|
ico.extend_from_slice(&png);
|
||||||
|
|
||||||
|
let decoded = largest_icon(&ico).expect("valid RGB PNG icon");
|
||||||
|
assert_eq!(decoded.get_pixel(0, 0), &Rgba([1, 2, 3, 255]));
|
||||||
|
}
|
||||||
|
}
|
||||||
42
debian/changelog
vendored
42
debian/changelog
vendored
|
|
@ -1,3 +1,45 @@
|
||||||
|
cosmic-files (1.9.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.9.0 version update
|
||||||
|
|
||||||
|
-- Michael Murphy <michael@mmurphy.dev> Mon, 14 Sep 2026 20:35:19 +0200
|
||||||
|
|
||||||
|
cosmic-files (1.8.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.8.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Wed, 02 Sep 2026 08:14:53 -0600
|
||||||
|
|
||||||
|
cosmic-files (1.7.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.7.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Tue, 25 Aug 2026 09:20:22 -0600
|
||||||
|
|
||||||
|
cosmic-files (1.6.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.6.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Tue, 18 Aug 2026 07:13:48 -0600
|
||||||
|
|
||||||
|
cosmic-files (1.5.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.5.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Tue, 28 Jul 2026 09:14:09 -0600
|
||||||
|
|
||||||
|
cosmic-files (1.4.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.4.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Mon, 20 Jul 2026 14:36:06 -0600
|
||||||
|
|
||||||
|
cosmic-files (1.3.0) noble; urgency=medium
|
||||||
|
|
||||||
|
* Epoch 1.3.0 version update
|
||||||
|
|
||||||
|
-- Jeremy Soller <jeremy@system76.com> Sun, 12 Jul 2026 13:21:18 -0600
|
||||||
|
|
||||||
cosmic-files (1.2.0) noble; urgency=medium
|
cosmic-files (1.2.0) noble; urgency=medium
|
||||||
|
|
||||||
* Epoch 1.2.0 version update
|
* Epoch 1.2.0 version update
|
||||||
|
|
|
||||||
6
debian/source/options
vendored
6
debian/source/options
vendored
|
|
@ -1,4 +1,6 @@
|
||||||
tar-ignore=.github
|
tar-ignore=.github
|
||||||
tar-ignore=.vscode
|
tar-ignore=target/.rustc_info.json
|
||||||
|
tar-ignore=target/CACHEDIR.TAG
|
||||||
|
tar-ignore=target/debug
|
||||||
|
tar-ignore=target/release
|
||||||
tar-ignore=vendor
|
tar-ignore=vendor
|
||||||
tar-ignore=target
|
|
||||||
|
|
@ -84,7 +84,7 @@ settings = الإعدادات
|
||||||
### Appearance
|
### Appearance
|
||||||
|
|
||||||
appearance = المظهر
|
appearance = المظهر
|
||||||
theme = النسق
|
theme = السمة
|
||||||
match-desktop = طابق سطح المكتب
|
match-desktop = طابق سطح المكتب
|
||||||
dark = داكن
|
dark = داكن
|
||||||
light = فاتح
|
light = فاتح
|
||||||
|
|
@ -110,7 +110,7 @@ new-tab = لسان جديد
|
||||||
new-window = نافذة جديدة
|
new-window = نافذة جديدة
|
||||||
rename = غيِّر الاسم...
|
rename = غيِّر الاسم...
|
||||||
close-tab = أغلق اللسان
|
close-tab = أغلق اللسان
|
||||||
quit = أنهِ
|
quit = إنهِ
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ icon-size-and-spacing = حجم الأيقونة والتباعد
|
||||||
icon-size = حجم الأيقونة
|
icon-size = حجم الأيقونة
|
||||||
grid-spacing = تباعد شبكي
|
grid-spacing = تباعد شبكي
|
||||||
trashed-on = مهمل
|
trashed-on = مهمل
|
||||||
details = التفاصيل
|
details = تفاصيل
|
||||||
pause = ألبث
|
pause = ألبث
|
||||||
resume = استئناف
|
resume = استئناف
|
||||||
create-archive = أنشئ أرشيف
|
create-archive = أنشئ أرشيف
|
||||||
|
|
@ -383,3 +383,7 @@ context-action-confirm-warning =
|
||||||
*[other] عنصر
|
*[other] عنصر
|
||||||
}.
|
}.
|
||||||
run = شغِّل
|
run = شغِّل
|
||||||
|
checksum = تدقيق المجموع { $kind }
|
||||||
|
calculate = احسب
|
||||||
|
error = خطأ
|
||||||
|
rename-confirm = أعد التسمية
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ name-no-slashes = El nom no pot contenir barres.
|
||||||
cancel = Cancel·lar
|
cancel = Cancel·lar
|
||||||
create = Crea
|
create = Crea
|
||||||
open = Obre
|
open = Obre
|
||||||
open-file = Obre el fixer
|
open-file = Obre el fitxer
|
||||||
open-folder = Obre la carpeta
|
open-folder = Obre la carpeta
|
||||||
open-in-new-tab = Obre en una pestanya nova
|
open-in-new-tab = Obre en una pestanya nova
|
||||||
open-in-new-window = Obre en una finestra nova
|
open-in-new-window = Obre en una finestra nova
|
||||||
|
|
|
||||||
|
|
@ -428,3 +428,9 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Spustit
|
run = Spustit
|
||||||
rename-confirm = Přejmenovat
|
rename-confirm = Přejmenovat
|
||||||
|
checksum = Kontrolní součet { $kind }
|
||||||
|
calculate = Vypočítat
|
||||||
|
error = Chyba
|
||||||
|
search-application = Hledat podle názvu aplikace
|
||||||
|
sidebar-label = Popisek v postranním panelu
|
||||||
|
change-sidebar-label = Změnit popisek
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,43 @@
|
||||||
cosmic-files = COSMIC Filer
|
cosmic-files = COSMIC Filhåndtering
|
||||||
empty-folder = Tom mappe
|
empty-folder = Tom mappe
|
||||||
empty-folder-hidden = Tom mappe (har skjulte filer)
|
empty-folder-hidden = Tom mappe (har skjulte emner)
|
||||||
no-results = Ingen resultater
|
no-results = Fandt ingen resultater
|
||||||
filesystem = Filsystem
|
filesystem = Filsystem
|
||||||
home = Hjem
|
home = Hjem
|
||||||
networks = Netværk
|
networks = Netværk
|
||||||
notification-in-progress = Filoperationer er igangværende.
|
notification-in-progress = Fil-operationer er igang
|
||||||
trash = Skraldespand
|
trash = Papirkurv
|
||||||
recents = Seneste
|
recents = Seneste
|
||||||
undo = Fortryd
|
undo = Fortryd
|
||||||
today = I dag
|
today = I dag
|
||||||
# Desktop view options
|
# Desktop view options
|
||||||
desktop-view-options = Indstillinger for skrivebordsudseende...
|
desktop-view-options = Valgmuligheder for skrivebordsvisning...
|
||||||
show-on-desktop = Vis på Skrivebordet
|
show-on-desktop = Vis på Skrivebord
|
||||||
desktop-folder-content = Indhold på Skrivebordet
|
desktop-folder-content = Skrivebords-mappeindhold
|
||||||
mounted-drives = Monterede drev
|
mounted-drives = Monterede drev
|
||||||
trash-folder-icon = Skraldespandsikon
|
trash-folder-icon = Papirkurv-ikon
|
||||||
icon-size-and-spacing = Ikonstørrelse og afstand
|
icon-size-and-spacing = Ikonstørrelse og -afstand
|
||||||
icon-size = Ikonstørrelse
|
icon-size = Ikonstørrelse
|
||||||
# List view
|
# List view
|
||||||
name = Navn
|
name = Navn
|
||||||
modified = Ændret
|
modified = Ændret
|
||||||
trashed-on = Smidt ud
|
trashed-on = Kasseret
|
||||||
size = Størrelse
|
size = Størrelse
|
||||||
# Progress footer
|
# Progress footer
|
||||||
details = Detaljer
|
details = Detaljer
|
||||||
dismiss = Afvis besked
|
dismiss = Luk meddelelse
|
||||||
operations-running = { $running } operationer er i gang ({ $percent }%)...
|
operations-running =
|
||||||
operations-running-finished = { $running } operationer er i gang ({ $percent }%), { $finished } færdiggjort...
|
{ $running } { $running ->
|
||||||
|
[one] operation
|
||||||
|
*[other] operationer
|
||||||
|
} kører ({ $percent }%)...
|
||||||
|
operations-running-finished =
|
||||||
|
{ $running } { $running ->
|
||||||
|
[one] operation
|
||||||
|
*[other] operationer
|
||||||
|
} kører ({ $percent }%), { $finished } færdig...
|
||||||
pause = Pause
|
pause = Pause
|
||||||
resume = Fortsæt
|
resume = Genoptag
|
||||||
|
|
||||||
# Dialogs
|
# Dialogs
|
||||||
|
|
||||||
|
|
@ -40,12 +48,12 @@ create-archive = Opret arkiv
|
||||||
|
|
||||||
## Empty Trash Dialog
|
## Empty Trash Dialog
|
||||||
|
|
||||||
empty-trash = Tøm skraldespand
|
empty-trash = Tøm papirkurv
|
||||||
empty-trash-warning = Er du sikker på du vil slette alle objekter i Skraldespanden permanent?
|
empty-trash-warning = Emner i Papirkurv-mappen vil blive slettet permanent
|
||||||
|
|
||||||
## Mount Error Dialog
|
## Mount Error Dialog
|
||||||
|
|
||||||
mount-error = Kan ikke tilgå drev
|
mount-error = Ude af stand til at tilgå drev
|
||||||
|
|
||||||
## New File/Folder Dialog
|
## New File/Folder Dialog
|
||||||
|
|
||||||
|
|
@ -53,22 +61,22 @@ create-new-file = Opret ny fil
|
||||||
create-new-folder = Opret ny mappe
|
create-new-folder = Opret ny mappe
|
||||||
file-name = Filnavn
|
file-name = Filnavn
|
||||||
folder-name = Mappenavn
|
folder-name = Mappenavn
|
||||||
file-already-exists = En fil med det navn eksisterer allerede.
|
file-already-exists = En fil med det navn eksisterer allerede
|
||||||
folder-already-exists = En mappe med det navn eksisterer allerede.
|
folder-already-exists = En mappe med det navn eksisterer allerede
|
||||||
name-hidden = Navne begyndende med "." vil blive skjult.
|
name-hidden = Navne begyndende med "." vil være skjulte
|
||||||
name-invalid = Navn kan ikke være "{ $filename }".
|
name-invalid = Navn må ikke være "{ $filename }"
|
||||||
name-no-slashes = Navn kan ikke indeholde skråstreg.
|
name-no-slashes = Navn må ikke indeholde skråstreger
|
||||||
|
|
||||||
## Open/Save Dialog
|
## Open/Save Dialog
|
||||||
|
|
||||||
cancel = Annullér
|
cancel = Afbryd
|
||||||
create = Opret
|
create = Opret
|
||||||
open = Åbn
|
open = Åbn
|
||||||
open-file = Åbn fil
|
open-file = Åbn fil
|
||||||
open-folder = Åbn mappe
|
open-folder = Åbn mappe
|
||||||
open-in-new-tab = Åbn i ny fane
|
open-in-new-tab = Åbn i nyt faneblad
|
||||||
open-in-new-window = Åbn i nyt vindue
|
open-in-new-window = Åbn i nyt vindue
|
||||||
open-item-location = Åbn placering for objekt
|
open-item-location = Åbn emne-placering
|
||||||
open-multiple-files = Åbn flere filer
|
open-multiple-files = Åbn flere filer
|
||||||
open-multiple-folders = Åbn flere mapper
|
open-multiple-folders = Åbn flere mapper
|
||||||
save = Gem
|
save = Gem
|
||||||
|
|
@ -87,20 +95,20 @@ rename-folder = Omdøb mappe
|
||||||
## Replace Dialog
|
## Replace Dialog
|
||||||
|
|
||||||
replace = Erstat
|
replace = Erstat
|
||||||
replace-title = "{ $filename }" eksisterer allerede på denne placering.
|
replace-title = "{ $filename }" eksisterer allerede i denne placering
|
||||||
replace-warning = Vil du erstatte den med den du er ved at gemme? Hvis du erstatter den, overskriver du dens indhold.
|
replace-warning = Ønsker du at erstatte den med den, du er ved at gemme? Erstatning af den vil overskrive dens indhold.
|
||||||
replace-warning-operation = Vil du erstatte den? Hvis du erstatter den, overskriver du dens indhold.
|
replace-warning-operation = Ønsker du at erstatte den? Erstatning af den vil overskrive dens indhold.
|
||||||
original-file = Original fil
|
original-file = Original fil
|
||||||
replace-with = Erstat med
|
replace-with = Erstat med
|
||||||
apply-to-all = Anvend for alle
|
apply-to-all = Anvend på alle
|
||||||
keep-both = Behold begge
|
keep-both = Behold begge
|
||||||
skip = Spring over
|
skip = Spring over
|
||||||
|
|
||||||
## Set as Executable and Launch Dialog
|
## Set as Executable and Launch Dialog
|
||||||
|
|
||||||
set-executable-and-launch = Indstil som eksekverbar fil og start
|
set-executable-and-launch = Angiv som eksekverbar og start
|
||||||
set-executable-and-launch-description = Vil du indstille "{ $name }" som en eksekverbar fil og starte den?
|
set-executable-and-launch-description = Vil du angive "{ $name }" som eksekverbar og starte den?
|
||||||
set-and-launch = Indstil og start
|
set-and-launch = Angiv og start
|
||||||
|
|
||||||
## Metadata Dialog
|
## Metadata Dialog
|
||||||
|
|
||||||
|
|
@ -239,13 +247,13 @@ settings = Indstillinger
|
||||||
|
|
||||||
appearance = Udseende
|
appearance = Udseende
|
||||||
theme = Tema
|
theme = Tema
|
||||||
match-desktop = Match skrivebord
|
match-desktop = Følg skrivebordets indstillinger
|
||||||
dark = Mørk
|
dark = Mørkt
|
||||||
light = Lys
|
light = Lyst
|
||||||
# Context menu
|
# Context menu
|
||||||
add-to-sidebar = Tilføj til sidebjælke
|
add-to-sidebar = Tilføj til sidebjælke
|
||||||
compress = Komprimér
|
compress = Komprimer…
|
||||||
extract-here = Extract
|
extract-here = Uddrag
|
||||||
new-file = Ny fil...
|
new-file = Ny fil...
|
||||||
new-folder = Ny mappe...
|
new-folder = Ny mappe...
|
||||||
open-in-terminal = Åbn i terminal
|
open-in-terminal = Åbn i terminal
|
||||||
|
|
@ -280,15 +288,15 @@ quit = Afslut
|
||||||
edit = Redigér
|
edit = Redigér
|
||||||
cut = Klip
|
cut = Klip
|
||||||
copy = Kopiér
|
copy = Kopiér
|
||||||
paste = Sæt ind
|
paste = Indsæt
|
||||||
select-all = Vælg alt
|
select-all = Vælg alle
|
||||||
|
|
||||||
## View
|
## View
|
||||||
|
|
||||||
zoom-in = Zoom ind
|
zoom-in = Zoom ind
|
||||||
default-size = Standardstørrelse
|
default-size = Standardstørrelse
|
||||||
zoom-out = Zoom ud
|
zoom-out = Zoom ud
|
||||||
view = Visning
|
view = Vis
|
||||||
grid-view = Gitter-visning
|
grid-view = Gitter-visning
|
||||||
list-view = Liste-visning
|
list-view = Liste-visning
|
||||||
show-hidden-files = Vis skjulte filer
|
show-hidden-files = Vis skjulte filer
|
||||||
|
|
@ -306,3 +314,102 @@ sort-newest-first = Nyeste først
|
||||||
sort-oldest-first = Ældste først
|
sort-oldest-first = Ældste først
|
||||||
sort-smallest-to-largest = Mindste til største
|
sort-smallest-to-largest = Mindste til største
|
||||||
sort-largest-to-smallest = Største til mindste
|
sort-largest-to-smallest = Største til mindste
|
||||||
|
delete = Slet
|
||||||
|
run = Kør
|
||||||
|
repository = Pakkearkiv
|
||||||
|
grid-spacing = Gitter-afstand
|
||||||
|
extract-password-required = Adgangskode påkrævet
|
||||||
|
extract-to = Udpak Til...
|
||||||
|
extract-to-title = Udpak til mappe
|
||||||
|
empty-trash-title = Tøm papirkurv?
|
||||||
|
keywords = Mappe;Håndtering;
|
||||||
|
comment = Filhåndteringsprogram til COSMIC-skrivebordet
|
||||||
|
copy-to-title = Vælg kopi destination
|
||||||
|
copy-to-button-label = Kopier
|
||||||
|
move-to-title = Vælg flytte destination
|
||||||
|
move-to-button-label = Flyt
|
||||||
|
deleted =
|
||||||
|
Slettede { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
} fra { trash }
|
||||||
|
removing-from-recents =
|
||||||
|
Fjerner { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
} fra { recents }
|
||||||
|
type-to-search-enter-path = Indtast stien til mappen eller filen
|
||||||
|
permanently-deleting =
|
||||||
|
Sletter permanent { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
}
|
||||||
|
execute-only = Kun kørsel
|
||||||
|
removed-from-recents =
|
||||||
|
Fjernede { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
} fra { recents }
|
||||||
|
permanently-deleted =
|
||||||
|
Slettede permanent { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
}
|
||||||
|
write-only = Kun skrivning
|
||||||
|
remove = Fjern
|
||||||
|
context-action = Konteksthandling
|
||||||
|
context-action-confirm-title = Kør “{ $name }”?
|
||||||
|
context-action-confirm-warning =
|
||||||
|
Dette vil køre på { $items } { $items ->
|
||||||
|
[one] item
|
||||||
|
*[other] items
|
||||||
|
}.
|
||||||
|
selected-items = De { $items } valgte elementer
|
||||||
|
mixed = Blandet
|
||||||
|
none = Ingen
|
||||||
|
write-execute = Skriv og kør
|
||||||
|
read-only = Kun læsning
|
||||||
|
read-execute = Læs og kør
|
||||||
|
read-write = Læs og skriv
|
||||||
|
read-write-execute = Læs, skriv og kør
|
||||||
|
keep = Behold
|
||||||
|
support = Support
|
||||||
|
progress-failed = { $percent } %, mislykkedes
|
||||||
|
pasted-image = Indsat billede
|
||||||
|
pasted-text = Indsat tekst
|
||||||
|
pasted-video = Indsat video
|
||||||
|
deleting =
|
||||||
|
Sletter { $items } { $items ->
|
||||||
|
[one] element
|
||||||
|
*[other] elementer
|
||||||
|
} fra { trash } ({ $progress })...
|
||||||
|
setting-permissions = Indstiller tilladelser for “{ $name }” til { $mode }
|
||||||
|
set-permissions = Sæt tilladelser for “{ $name }” til { $mode }
|
||||||
|
show-recents = Seneste-mappe i sidepanelet
|
||||||
|
type-to-search = Skriv for at søge
|
||||||
|
type-to-search-recursive = Søger i den aktuelle mappe og alle undermapper
|
||||||
|
type-to-search-select = Vælger den første matchende fil eller mappe
|
||||||
|
clear-recents-history = Ryd seneste historik
|
||||||
|
copy-to = Kopiér til…
|
||||||
|
delete-permanently = Slet permanent
|
||||||
|
eject = Skub ud
|
||||||
|
move-to = Flyt til…
|
||||||
|
remove-from-recents = Fjern fra seneste
|
||||||
|
reload-folder = Genindlæs mappe
|
||||||
|
copy-path = Kopiér sti
|
||||||
|
rename-confirm = Omdøb
|
||||||
|
calculate = Udregn
|
||||||
|
error = Fejl
|
||||||
|
checksum = { $kind }-kontrolsum
|
||||||
|
other-apps = Andre applikationer
|
||||||
|
related-apps = Relaterede applikationer
|
||||||
|
permanently-delete-question = Slet permanent?
|
||||||
|
permanently-delete-warning = { $target } vil blive slettet permanent. Denne handling kan ikke fortrydes.
|
||||||
|
open-with = Åbn med
|
||||||
|
favorite-path-error = Fejl ved åbning af sti
|
||||||
|
favorite-path-error-description =
|
||||||
|
Ude af stand til at åbne "{ $path }"
|
||||||
|
"{ $path }" Eksisterer muligvis ikke, eller du har måske ikketilladelse til at åbne den
|
||||||
|
|
||||||
|
Ønsker du at fjerne den fra sidebjælken?
|
||||||
|
single-click = Enkelt klik for at åbne
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ recents = Zuletzt verwendet
|
||||||
undo = Rückgängig
|
undo = Rückgängig
|
||||||
today = Heute
|
today = Heute
|
||||||
# Optionen für die Desktop-Ansicht
|
# Optionen für die Desktop-Ansicht
|
||||||
desktop-view-options = Optionen für die Desktop-Ansicht…
|
desktop-view-options = Optionen für die Desktop-Ansicht ...
|
||||||
show-on-desktop = Auf Desktop anzeigen
|
show-on-desktop = Auf Desktop anzeigen
|
||||||
desktop-folder-content = Inhalt des Desktop-Ordners
|
desktop-folder-content = Inhalt des Desktop-Ordners
|
||||||
mounted-drives = Eingehängte Laufwerke
|
mounted-drives = Eingehängte Laufwerke
|
||||||
|
|
@ -31,12 +31,12 @@ operations-running =
|
||||||
{ $running } { $running ->
|
{ $running } { $running ->
|
||||||
[one] laufender Vorgang
|
[one] laufender Vorgang
|
||||||
*[other] laufende Vorgänge
|
*[other] laufende Vorgänge
|
||||||
} ({ $percent } %)...
|
} ({ $percent } %) ...
|
||||||
operations-running-finished =
|
operations-running-finished =
|
||||||
{ $running } { $running ->
|
{ $running } { $running ->
|
||||||
[one] laufender Vorgang
|
[one] laufender Vorgang
|
||||||
*[other] laufende Vorgänge
|
*[other] laufende Vorgänge
|
||||||
} ({ $percent } %), { $finished } abgeschlossen...
|
} ({ $percent } %), { $finished } abgeschlossen ...
|
||||||
pause = Pause
|
pause = Pause
|
||||||
resume = Fortsetzen
|
resume = Fortsetzen
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ create-archive = Archiv erstellen
|
||||||
## Entpacken-Dialog
|
## Entpacken-Dialog
|
||||||
|
|
||||||
extract-password-required = Passwort erforderlich
|
extract-password-required = Passwort erforderlich
|
||||||
extract-to = Entpacken nach...
|
extract-to = Entpacken nach ...
|
||||||
extract-to-title = In Ordner entpacken
|
extract-to-title = In Ordner entpacken
|
||||||
|
|
||||||
## Dialog zum Leeren des Papierkorbs
|
## Dialog zum Leeren des Papierkorbs
|
||||||
|
|
@ -179,7 +179,7 @@ keep = Behalten
|
||||||
add-network-drive = Netzlaufwerk hinzufügen
|
add-network-drive = Netzlaufwerk hinzufügen
|
||||||
connect = Verbinden
|
connect = Verbinden
|
||||||
connect-anonymously = Anonym verbinden
|
connect-anonymously = Anonym verbinden
|
||||||
connecting = Wird verbunden...
|
connecting = Wird verbunden ...
|
||||||
domain = Domain
|
domain = Domain
|
||||||
enter-server-address = Serveradresse eingeben
|
enter-server-address = Serveradresse eingeben
|
||||||
network-drive-description =
|
network-drive-description =
|
||||||
|
|
@ -218,7 +218,7 @@ compressing =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} von „{ $from }“ nach „{ $to }“ komprimiert ({ $progress })...
|
} von „{ $from }“ nach „{ $to }“ komprimiert ({ $progress }) ...
|
||||||
compressed =
|
compressed =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
|
|
@ -231,7 +231,7 @@ copying =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} von „{ $from }“ nach „{ $to }“ kopiert ({ $progress })...
|
} von „{ $from }“ nach „{ $to }“ kopiert ({ $progress }) ...
|
||||||
copied =
|
copied =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
|
|
@ -241,19 +241,19 @@ deleting =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} aus dem { trash } gelöscht ({ $progress })...
|
} aus dem { trash } gelöscht ({ $progress }) ...
|
||||||
deleted =
|
deleted =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
*[other] Elemente wurden
|
*[other] Elemente wurden
|
||||||
} aus dem { trash } gelöscht
|
} aus dem { trash } gelöscht
|
||||||
emptying-trash = { trash } wird geleert ({ $progress })...
|
emptying-trash = { trash } wird geleert ({ $progress }) ...
|
||||||
emptied-trash = { trash } geleert
|
emptied-trash = { trash } geleert
|
||||||
extracting =
|
extracting =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} von „{ $from }“ nach „{ $to }“ entpackt ({ $progress })...
|
} von „{ $from }“ nach „{ $to }“ entpackt ({ $progress }) ...
|
||||||
extracted =
|
extracted =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
|
|
@ -267,7 +267,7 @@ moving =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} von „{ $from }“ nach „{ $to }“ verschoben ({ $progress })...
|
} von „{ $from }“ nach „{ $to }“ verschoben ({ $progress }) ...
|
||||||
moved =
|
moved =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
|
|
@ -289,7 +289,7 @@ restoring =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wird
|
[one] Element wird
|
||||||
*[other] Elemente werden
|
*[other] Elemente werden
|
||||||
} aus dem { trash } wiederhergestellt ({ $progress })...
|
} aus dem { trash } wiederhergestellt ({ $progress }) ...
|
||||||
restored =
|
restored =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] Element wurde
|
[one] Element wurde
|
||||||
|
|
@ -299,7 +299,7 @@ unknown-folder = unbekannter Ordner
|
||||||
|
|
||||||
## Öffnen mit
|
## Öffnen mit
|
||||||
|
|
||||||
menu-open-with = Öffnen mit...
|
menu-open-with = Öffnen mit ...
|
||||||
default-app = { $name } (Standard)
|
default-app = { $name } (Standard)
|
||||||
|
|
||||||
## Details anzeigen
|
## Details anzeigen
|
||||||
|
|
@ -311,7 +311,7 @@ item-size = Größe: { $size }
|
||||||
item-created = Erstellt: { $created }
|
item-created = Erstellt: { $created }
|
||||||
item-modified = Geändert: { $modified }
|
item-modified = Geändert: { $modified }
|
||||||
item-accessed = Zugegriffen: { $accessed }
|
item-accessed = Zugegriffen: { $accessed }
|
||||||
calculating = Wird berechnet...
|
calculating = Wird berechnet ...
|
||||||
|
|
||||||
## Einstellungen
|
## Einstellungen
|
||||||
|
|
||||||
|
|
@ -333,15 +333,15 @@ type-to-search-recursive = Durchsucht den aktuellen Ordner und alle Unterordner
|
||||||
type-to-search-enter-path = Gib den Pfad zum Verzeichnis oder zur Datei ein
|
type-to-search-enter-path = Gib den Pfad zum Verzeichnis oder zur Datei ein
|
||||||
# Kontextmenü
|
# Kontextmenü
|
||||||
add-to-sidebar = Zur Seitenleiste hinzufügen
|
add-to-sidebar = Zur Seitenleiste hinzufügen
|
||||||
compress = Komprimieren...
|
compress = Komprimieren ...
|
||||||
delete-permanently = Endgültig löschen
|
delete-permanently = Endgültig löschen
|
||||||
extract-here = Entpacken
|
extract-here = Entpacken
|
||||||
new-file = Neue Datei...
|
new-file = Neue Datei ...
|
||||||
new-folder = Neuer Ordner...
|
new-folder = Neuer Ordner ...
|
||||||
open-in-terminal = Im Terminal öffnen
|
open-in-terminal = Im Terminal öffnen
|
||||||
move-to-trash = In den Papierkorb verschieben
|
move-to-trash = In den Papierkorb verschieben
|
||||||
restore-from-trash = Aus dem Papierkorb wiederherstellen
|
restore-from-trash = Aus dem Papierkorb wiederherstellen
|
||||||
remove-from-sidebar = Von der Seitenleiste entfernen
|
remove-from-sidebar = Aus der Seitenleiste entfernen
|
||||||
sort-by-name = Nach Name sortieren
|
sort-by-name = Nach Name sortieren
|
||||||
sort-by-modified = Nach Änderung sortieren
|
sort-by-modified = Nach Änderung sortieren
|
||||||
sort-by-size = Nach Größe sortieren
|
sort-by-size = Nach Größe sortieren
|
||||||
|
|
@ -349,9 +349,9 @@ sort-by-trashed = Nach Löschzeitpunkt sortieren
|
||||||
|
|
||||||
## Desktop
|
## Desktop
|
||||||
|
|
||||||
change-wallpaper = Hintergrundbild ändern...
|
change-wallpaper = Hintergrundbild ändern ...
|
||||||
desktop-appearance = Desktop-Aussehen...
|
desktop-appearance = Desktop-Aussehen ...
|
||||||
display-settings = Anzeigeeinstellungen...
|
display-settings = Anzeigeeinstellungen ...
|
||||||
|
|
||||||
# Menü
|
# Menü
|
||||||
|
|
||||||
|
|
@ -362,7 +362,7 @@ file = Datei
|
||||||
new-tab = Neuer Tab
|
new-tab = Neuer Tab
|
||||||
new-window = Neues Fenster
|
new-window = Neues Fenster
|
||||||
reload-folder = Ordner neu laden
|
reload-folder = Ordner neu laden
|
||||||
rename = Umbenennen...
|
rename = Umbenennen ...
|
||||||
close-tab = Tab schließen
|
close-tab = Tab schließen
|
||||||
quit = Beenden
|
quit = Beenden
|
||||||
|
|
||||||
|
|
@ -385,8 +385,8 @@ list-view = Listenansicht
|
||||||
show-hidden-files = Versteckte Dateien anzeigen
|
show-hidden-files = Versteckte Dateien anzeigen
|
||||||
list-directories-first = Verzeichnisse zuerst auflisten
|
list-directories-first = Verzeichnisse zuerst auflisten
|
||||||
gallery-preview = Galerie-Vorschau
|
gallery-preview = Galerie-Vorschau
|
||||||
menu-settings = Einstellungen...
|
menu-settings = Einstellungen ...
|
||||||
menu-about = Über COSMIC Dateien...
|
menu-about = Über COSMIC Dateien ...
|
||||||
|
|
||||||
## Sortieren
|
## Sortieren
|
||||||
|
|
||||||
|
|
@ -397,7 +397,7 @@ sort-newest-first = Neueste zuerst
|
||||||
sort-oldest-first = Älteste zuerst
|
sort-oldest-first = Älteste zuerst
|
||||||
sort-smallest-to-largest = Von klein nach groß
|
sort-smallest-to-largest = Von klein nach groß
|
||||||
sort-largest-to-smallest = Von groß nach klein
|
sort-largest-to-smallest = Von groß nach klein
|
||||||
repository = Repository
|
repository = Repositorium
|
||||||
empty-trash-title = Papierkorb leeren?
|
empty-trash-title = Papierkorb leeren?
|
||||||
copy-to-title = Kopierziel auswählen
|
copy-to-title = Kopierziel auswählen
|
||||||
copy-to-button-label = Kopieren
|
copy-to-button-label = Kopieren
|
||||||
|
|
@ -418,7 +418,7 @@ type-to-search-select = Wählt die erste übereinstimmende Datei oder den ersten
|
||||||
pasted-image = Eingefügtes Bild
|
pasted-image = Eingefügtes Bild
|
||||||
pasted-text = Eingefügter Text
|
pasted-text = Eingefügter Text
|
||||||
pasted-video = Eingefügtes Video
|
pasted-video = Eingefügtes Video
|
||||||
copy-to = Kopieren nach...
|
copy-to = Kopieren nach ...
|
||||||
show-recents = Ordner zuletzt verwendeter Elemente in der Seitenleiste
|
show-recents = Ordner zuletzt verwendeter Elemente in der Seitenleiste
|
||||||
clear-recents-history = Verlauf zuletzt verwendeter Elemente leeren
|
clear-recents-history = Verlauf zuletzt verwendeter Elemente leeren
|
||||||
comment = Dateimanager für den COSMIC Desktop
|
comment = Dateimanager für den COSMIC Desktop
|
||||||
|
|
@ -426,7 +426,7 @@ keywords = Ordner;Manager;
|
||||||
move-to-button-label = Verschieben
|
move-to-button-label = Verschieben
|
||||||
move-to-title = Verschiebeziel auswählen
|
move-to-title = Verschiebeziel auswählen
|
||||||
remove-from-recents = Aus den zuletzt verwendeten Elementen entfernen
|
remove-from-recents = Aus den zuletzt verwendeten Elementen entfernen
|
||||||
move-to = Verschieben nach...
|
move-to = Verschieben nach ...
|
||||||
copy-path = Pfad kopieren
|
copy-path = Pfad kopieren
|
||||||
mixed = Gemischt
|
mixed = Gemischt
|
||||||
context-action = Kontextaktion
|
context-action = Kontextaktion
|
||||||
|
|
@ -438,3 +438,8 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Ausführen
|
run = Ausführen
|
||||||
rename-confirm = Umbenennen
|
rename-confirm = Umbenennen
|
||||||
|
checksum = { $kind } Prüfsumme
|
||||||
|
calculate = Berechnen
|
||||||
|
error = Fehler
|
||||||
|
sidebar-label = Bezeichnung in der Seitenleiste
|
||||||
|
search-application = Nach App-Name suchen
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ password = Κωδικός πρόσβασης
|
||||||
remove = Αφαίρεση
|
remove = Αφαίρεση
|
||||||
create = Δημιουργία
|
create = Δημιουργία
|
||||||
pause = Παύση
|
pause = Παύση
|
||||||
quit = Έξοδος
|
quit = Τερματισμός
|
||||||
calculating = Υπολογισμός...
|
calculating = Υπολογισμός...
|
||||||
keep = Διατήρηση
|
keep = Διατήρηση
|
||||||
edit = Επεξεργασία
|
edit = Επεξεργασία
|
||||||
|
|
@ -328,3 +328,9 @@ context-action-confirm-warning =
|
||||||
*[other] στοιχεία
|
*[other] στοιχεία
|
||||||
}.
|
}.
|
||||||
rename-confirm = Μετονομασία
|
rename-confirm = Μετονομασία
|
||||||
|
checksum = Άθροισμα ελέγχου { $kind }
|
||||||
|
calculate = Υπολογισμός
|
||||||
|
error = Σφάλμα
|
||||||
|
sidebar-label = Ετικέτα πλαϊνής στήλης
|
||||||
|
search-application = Αναζήτηση με όνομα εφαρμογής
|
||||||
|
change-sidebar-label = Αλλαγή ετικέτας πλαϊνής στήλης
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
save = Save
|
||||||
|
quit = Quit
|
||||||
|
name = Name
|
||||||
|
delete = Delete
|
||||||
|
cancel = Cancel
|
||||||
|
run = Run
|
||||||
|
new-window = New window
|
||||||
|
theme = Theme
|
||||||
|
appearance = Appearance
|
||||||
|
light = Light
|
||||||
|
repository = Repository
|
||||||
|
support = Support
|
||||||
|
dark = Dark
|
||||||
|
match-desktop = Match desktop
|
||||||
|
settings = Settings
|
||||||
|
replace = Replace
|
||||||
|
file = File
|
||||||
|
zoom-in = Zoom in
|
||||||
|
select-all = Select all
|
||||||
|
zoom-out = Zoom out
|
||||||
|
default-size = Default size
|
||||||
|
edit = Edit
|
||||||
|
copy = Copy
|
||||||
|
paste = Paste
|
||||||
|
view = View
|
||||||
|
undo = Undo
|
||||||
|
cut = Cut
|
||||||
|
icon-size-and-spacing = Icon size and spacing
|
||||||
|
cosmic-files = COSMIC Files
|
||||||
|
trash = Rubbish
|
||||||
|
empty-folder-hidden = Empty folder (has hidden items)
|
||||||
|
no-results = No results found
|
||||||
|
empty-folder = Empty folder
|
||||||
|
menu-settings = Settings...
|
||||||
|
recents = Recents
|
||||||
|
mounted-drives = Mounted drives
|
||||||
|
filesystem = Filesystem
|
||||||
|
home = Home
|
||||||
|
desktop-view-options = Desktop view options...
|
||||||
|
show-on-desktop = Show on Desktop
|
||||||
|
trash-folder-icon = Bin folder icon
|
||||||
|
desktop-folder-content = Desktop folder content
|
||||||
|
networks = Networks
|
||||||
|
today = Today
|
||||||
|
notification-in-progress = File operations are in progress
|
||||||
|
comment = File manager for the COSMIC desktop
|
||||||
|
keywords = Folder;Manager;
|
||||||
|
size = Size
|
||||||
|
dismiss = Dismiss message
|
||||||
|
trashed-on = Binned
|
||||||
|
create-archive = Create archive
|
||||||
|
pause = Pause
|
||||||
|
resume = Resume
|
||||||
|
grid-spacing = Grid spacing
|
||||||
|
details = Details
|
||||||
|
operations-running-finished =
|
||||||
|
{ $running } { $running ->
|
||||||
|
[one] operation
|
||||||
|
*[other] operations
|
||||||
|
} running ({ $percent }%), { $finished } finished...
|
||||||
|
icon-size = Icon size
|
||||||
|
modified = Modified
|
||||||
|
operations-running =
|
||||||
|
{ $running } { $running ->
|
||||||
|
[one] operation
|
||||||
|
*[other] operations
|
||||||
|
} running ({ $percent }%)...
|
||||||
|
copy-to-title = Select copy destination
|
||||||
|
open-file = Open file
|
||||||
|
open-multiple-files = Open multiple files
|
||||||
|
create-new-folder = Create new folder
|
||||||
|
create = Create
|
||||||
|
other-apps = Other applications
|
||||||
|
open-multiple-folders = Open multiple folders
|
||||||
|
extract-to = Extract To...
|
||||||
|
create-new-file = Create new file
|
||||||
|
open-in-new-window = Open in new window
|
||||||
|
folder-name = Folder name
|
||||||
|
browse-store = Browse { $store }
|
||||||
|
open-item-location = Open item location
|
||||||
|
mount-error = Unable to access drive
|
||||||
|
open = Open
|
||||||
|
extract-to-title = Extract to folder
|
||||||
|
open-with-title = How do you want to open "{ $name }"?
|
||||||
|
extract-password-required = Password required
|
||||||
|
open-folder = Open folder
|
||||||
|
open-in-new-tab = Open in new tab
|
||||||
|
file-name = File name
|
||||||
|
save-file = Save file
|
||||||
|
file-already-exists = A file with that name already exists
|
||||||
|
name-hidden = Names starting with "." will be hidden
|
||||||
|
folder-already-exists = A folder with that name already exists
|
||||||
|
empty-trash = Empty bin
|
||||||
|
empty-trash-title = Empty bin?
|
||||||
|
name-no-slashes = Name cannot contain slashes
|
||||||
|
name-invalid = Name cannot be "{ $filename }"
|
||||||
|
copy-to-button-label = Copy
|
||||||
|
move-to-title = Select move destination
|
||||||
|
move-to-button-label = Move
|
||||||
|
context-action = Context action
|
||||||
|
|
@ -119,6 +119,9 @@ rename-file = Rename file
|
||||||
rename-folder = Rename folder
|
rename-folder = Rename folder
|
||||||
rename-confirm = Rename
|
rename-confirm = Rename
|
||||||
|
|
||||||
|
## Change Sidebar Label Dialog
|
||||||
|
sidebar-label = Sidebar label
|
||||||
|
|
||||||
## Replace Dialog
|
## Replace Dialog
|
||||||
replace = Replace
|
replace = Replace
|
||||||
replace-title = "{$filename}" already exists in this location
|
replace-title = "{$filename}" already exists in this location
|
||||||
|
|
@ -299,6 +302,7 @@ unknown-folder = unknown folder
|
||||||
## Open with
|
## Open with
|
||||||
menu-open-with = Open with...
|
menu-open-with = Open with...
|
||||||
default-app = {$name} (default)
|
default-app = {$name} (default)
|
||||||
|
search-application = Search by app name
|
||||||
|
|
||||||
## Show details
|
## Show details
|
||||||
show-details = Show details
|
show-details = Show details
|
||||||
|
|
@ -347,6 +351,7 @@ move-to = Move to...
|
||||||
move-to-trash = Move to trash
|
move-to-trash = Move to trash
|
||||||
restore-from-trash = Restore from trash
|
restore-from-trash = Restore from trash
|
||||||
remove-from-sidebar = Remove from sidebar
|
remove-from-sidebar = Remove from sidebar
|
||||||
|
change-sidebar-label = Change sidebar label
|
||||||
sort-by-name = Sort by name
|
sort-by-name = Sort by name
|
||||||
sort-by-modified = Sort by modified
|
sort-by-modified = Sort by modified
|
||||||
sort-by-size = Sort by size
|
sort-by-size = Sort by size
|
||||||
|
|
|
||||||
|
|
@ -345,3 +345,4 @@ sort-newest-first = جدیدترین در ابتدا
|
||||||
sort-oldest-first = قدیمیترین در ابتدا
|
sort-oldest-first = قدیمیترین در ابتدا
|
||||||
sort-smallest-to-largest = کوچکترین به بزرگترین
|
sort-smallest-to-largest = کوچکترین به بزرگترین
|
||||||
sort-largest-to-smallest = بزرگترین به کوچکترین
|
sort-largest-to-smallest = بزرگترین به کوچکترین
|
||||||
|
run = اجرا
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ settings = Asetukset
|
||||||
|
|
||||||
appearance = Ulkoasu
|
appearance = Ulkoasu
|
||||||
theme = Teema
|
theme = Teema
|
||||||
match-desktop = Sovita työpöytään
|
match-desktop = Sama kuin työpöytä
|
||||||
dark = Tumma
|
dark = Tumma
|
||||||
light = Vaalea
|
light = Vaalea
|
||||||
|
|
||||||
|
|
@ -415,3 +415,9 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Suorita
|
run = Suorita
|
||||||
rename-confirm = Nimeä uudelleen
|
rename-confirm = Nimeä uudelleen
|
||||||
|
checksum = { $kind }-tarkistussumma
|
||||||
|
calculate = Laske
|
||||||
|
error = Virhe
|
||||||
|
search-application = Hae sovelluksen nimellä
|
||||||
|
sidebar-label = Sivupalkin nimike
|
||||||
|
change-sidebar-label = Muuta sivupalkin nimikettä
|
||||||
|
|
|
||||||
0
i18n/fil/cosmic_files.ftl
Normal file
0
i18n/fil/cosmic_files.ftl
Normal file
|
|
@ -80,14 +80,14 @@ cancel = Annuler
|
||||||
create = Créer
|
create = Créer
|
||||||
open = Ouvrir
|
open = Ouvrir
|
||||||
open-file = Ouvrir le fichier
|
open-file = Ouvrir le fichier
|
||||||
open-folder = Ouvrir dossier
|
open-folder = Ouvrir le dossier
|
||||||
open-in-new-tab = Ouvrir dans un nouvel onglet
|
open-in-new-tab = Ouvrir dans un nouvel onglet
|
||||||
open-in-new-window = Ouvrir dans une nouvelle fenêtre
|
open-in-new-window = Ouvrir dans une nouvelle fenêtre
|
||||||
open-item-location = Ouvrir l'emplacement de l'élément
|
open-item-location = Ouvrir l'emplacement de l'élément
|
||||||
open-multiple-files = Ouvrir plusieurs fichiers
|
open-multiple-files = Ouvrir plusieurs fichiers
|
||||||
open-multiple-folders = Ouvrir plusieurs dossiers
|
open-multiple-folders = Ouvrir plusieurs dossiers
|
||||||
save = Enregistrer
|
save = Enregistrer
|
||||||
save-file = Enregistrer fichier
|
save-file = Enregistrer le fichier
|
||||||
|
|
||||||
## Open With Dialog
|
## Open With Dialog
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ keep = Conserver
|
||||||
## Add Network Drive
|
## Add Network Drive
|
||||||
|
|
||||||
add-network-drive = Ajouter un lecteur réseau
|
add-network-drive = Ajouter un lecteur réseau
|
||||||
connect = Connecter
|
connect = Se connecter
|
||||||
connect-anonymously = Se connecter anonymement
|
connect-anonymously = Se connecter anonymement
|
||||||
connecting = Connexion...
|
connecting = Connexion...
|
||||||
domain = Domaine
|
domain = Domaine
|
||||||
|
|
@ -206,8 +206,8 @@ network-drive-schemes =
|
||||||
File Transfer Protocol,ftp:// or ftps://
|
File Transfer Protocol,ftp:// or ftps://
|
||||||
Network File System,nfs://
|
Network File System,nfs://
|
||||||
Server Message Block,smb://
|
Server Message Block,smb://
|
||||||
SSH File Transfer Protocol,sftp:// or ssh://
|
SSH File Transfer Protocol,sftp:// ou ssh://
|
||||||
WebDav,dav:// or davs://
|
WebDAV,dav:// ou davs://
|
||||||
network-drive-error = Impossible d'accéder au lecteur réseau
|
network-drive-error = Impossible d'accéder au lecteur réseau
|
||||||
password = Mot de passe
|
password = Mot de passe
|
||||||
remember-password = Se souvenir du mot de passe
|
remember-password = Se souvenir du mot de passe
|
||||||
|
|
@ -222,7 +222,7 @@ history = Historique
|
||||||
no-history = Aucun élément dans l'historique.
|
no-history = Aucun élément dans l'historique.
|
||||||
pending = En attente
|
pending = En attente
|
||||||
progress = { $percent }%
|
progress = { $percent }%
|
||||||
progress-cancelled = { $percent }%, annulation
|
progress-cancelled = { $percent }%, annulé
|
||||||
progress-paused = { $percent }%, en pause
|
progress-paused = { $percent }%, en pause
|
||||||
failed = Échoué
|
failed = Échoué
|
||||||
complete = Terminé
|
complete = Terminé
|
||||||
|
|
@ -259,7 +259,7 @@ deleted =
|
||||||
[one] élément supprimé
|
[one] élément supprimé
|
||||||
*[other] éléments supprimés
|
*[other] éléments supprimés
|
||||||
} depuis { trash }
|
} depuis { trash }
|
||||||
emptying-trash = { trash } en cours de nettoyage ({ $progress })...
|
emptying-trash = Nettoyage en cours de { trash } ({ $progress })...
|
||||||
emptied-trash = { trash } vidée
|
emptied-trash = { trash } vidée
|
||||||
extracting =
|
extracting =
|
||||||
Extraction de { $items } { $items ->
|
Extraction de { $items } { $items ->
|
||||||
|
|
@ -271,7 +271,7 @@ extracted =
|
||||||
[one] élément extrait
|
[one] élément extrait
|
||||||
*[other] éléments extraits
|
*[other] éléments extraits
|
||||||
} depuis "{ $from }" vers "{ $to }"
|
} depuis "{ $from }" vers "{ $to }"
|
||||||
setting-executable-and-launching = Paramétrage de "{ $name }" comme exécutable et prêt à être lancé
|
setting-executable-and-launching = Définition de "{ $name }" comme exécutable et lancement en cours
|
||||||
set-executable-and-launched = Défini "{ $name }" comme exécutable et lancé
|
set-executable-and-launched = Défini "{ $name }" comme exécutable et lancé
|
||||||
moving =
|
moving =
|
||||||
Déplacement de { $items } { $items ->
|
Déplacement de { $items } { $items ->
|
||||||
|
|
@ -282,7 +282,7 @@ moved =
|
||||||
{ $items } { $items ->
|
{ $items } { $items ->
|
||||||
[one] élément déplacé
|
[one] élément déplacé
|
||||||
*[other] éléments déplacés
|
*[other] éléments déplacés
|
||||||
} de "{ $from }" à "{ $to }"
|
} de "{ $from }" vers "{ $to }"
|
||||||
permanently-deleting =
|
permanently-deleting =
|
||||||
Suppression définitive de { $items } { $items ->
|
Suppression définitive de { $items } { $items ->
|
||||||
[one] élément
|
[one] élément
|
||||||
|
|
@ -310,7 +310,7 @@ unknown-folder = Dossier inconnu
|
||||||
## Open with
|
## Open with
|
||||||
|
|
||||||
menu-open-with = Ouvrir avec...
|
menu-open-with = Ouvrir avec...
|
||||||
default-app = { $name } (défaut)
|
default-app = { $name } (par défaut)
|
||||||
|
|
||||||
## Show details
|
## Show details
|
||||||
|
|
||||||
|
|
@ -352,7 +352,7 @@ open-in-terminal = Ouvrir dans le terminal
|
||||||
edit-desktop-entry = Modifier le fichier .desktop
|
edit-desktop-entry = Modifier le fichier .desktop
|
||||||
move-to-trash = Déplacer vers la corbeille
|
move-to-trash = Déplacer vers la corbeille
|
||||||
restore-from-trash = Restaurer depuis la corbeille
|
restore-from-trash = Restaurer depuis la corbeille
|
||||||
remove-from-sidebar = Supprimer de la barre latérale
|
remove-from-sidebar = Retirer de la barre latérale
|
||||||
sort-by-name = Trier par nom
|
sort-by-name = Trier par nom
|
||||||
sort-by-modified = Trier par date de modification
|
sort-by-modified = Trier par date de modification
|
||||||
sort-by-size = Trier par taille
|
sort-by-size = Trier par taille
|
||||||
|
|
@ -415,11 +415,11 @@ removing-from-recents =
|
||||||
*[other] éléments
|
*[other] éléments
|
||||||
} de { recents }
|
} de { recents }
|
||||||
other-apps = Autres applications
|
other-apps = Autres applications
|
||||||
set-permissions = Définir les permissions pour "{ $name }" à { $mode }
|
set-permissions = Permissions définies pour "{ $name }" à { $mode }
|
||||||
repository = Dépôt
|
repository = Dépôt
|
||||||
support = Support
|
support = Support
|
||||||
eject = Éjecter
|
eject = Éjecter
|
||||||
remove-from-recents = Supprimer des récents
|
remove-from-recents = Retirer des récents
|
||||||
empty-trash-title = Vider la corbeille ?
|
empty-trash-title = Vider la corbeille ?
|
||||||
setting-permissions = Définition des permissions pour "{ $name }" à { $mode }
|
setting-permissions = Définition des permissions pour "{ $name }" à { $mode }
|
||||||
removed-from-recents =
|
removed-from-recents =
|
||||||
|
|
@ -428,9 +428,9 @@ removed-from-recents =
|
||||||
*[other] éléments supprimés
|
*[other] éléments supprimés
|
||||||
} de { recents }
|
} de { recents }
|
||||||
progress-failed = { $percent }%, échec
|
progress-failed = { $percent }%, échec
|
||||||
type-to-search-select = Sélectionne le premier fichier ou dossier qui convient
|
type-to-search-select = Sélectionne le premier fichier ou dossier correspondant
|
||||||
pasted-image = Image collée
|
pasted-image = Image collée
|
||||||
pasted-text = Text collé
|
pasted-text = Texte collé
|
||||||
pasted-video = Vidéo collée
|
pasted-video = Vidéo collée
|
||||||
copy-to-title = Sélectionner la destination de la copie
|
copy-to-title = Sélectionner la destination de la copie
|
||||||
copy-to-button-label = Copier
|
copy-to-button-label = Copier
|
||||||
|
|
@ -453,3 +453,9 @@ context-action-confirm-warning =
|
||||||
run = Exécuter
|
run = Exécuter
|
||||||
context-action = Action contextuelle
|
context-action = Action contextuelle
|
||||||
rename-confirm = Renommer
|
rename-confirm = Renommer
|
||||||
|
calculate = Calculer
|
||||||
|
error = Erreur
|
||||||
|
checksum = Somme de contrôle { $kind }
|
||||||
|
sidebar-label = Libellé de la barre latérale
|
||||||
|
search-application = Chercher par nom d'appli
|
||||||
|
change-sidebar-label = Changer le libellé de la barre latérale
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,7 @@ single-click = Cliceáil amháin le hoscailt
|
||||||
|
|
||||||
### Appearance
|
### Appearance
|
||||||
|
|
||||||
appearance = Cuma
|
appearance = Dealramh
|
||||||
theme = Téama
|
theme = Téama
|
||||||
match-desktop = Meaitseáil deasc
|
match-desktop = Meaitseáil deasc
|
||||||
dark = Dorcha
|
dark = Dorcha
|
||||||
|
|
@ -443,3 +443,6 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Rith
|
run = Rith
|
||||||
rename-confirm = Athainmnigh
|
rename-confirm = Athainmnigh
|
||||||
|
checksum = { $kind } suim sheiceála
|
||||||
|
calculate = Ríomh
|
||||||
|
error = Earráid
|
||||||
|
|
|
||||||
333
i18n/gl/cosmic_files.ftl
Normal file
333
i18n/gl/cosmic_files.ftl
Normal file
|
|
@ -0,0 +1,333 @@
|
||||||
|
name = Nome
|
||||||
|
save = Gardar
|
||||||
|
cancel = Cancelar
|
||||||
|
run = Executar
|
||||||
|
delete = Eliminar
|
||||||
|
repository = Repositorio
|
||||||
|
support = Soporte
|
||||||
|
settings = Axustes
|
||||||
|
appearance = Apariencia
|
||||||
|
theme = Tema
|
||||||
|
match-desktop = Axustar ao escritorio
|
||||||
|
dark = Escuro
|
||||||
|
light = Claro
|
||||||
|
replace = Remplazar
|
||||||
|
file = Ficheiro
|
||||||
|
new-window = Nova xanela
|
||||||
|
quit = Pechar
|
||||||
|
edit = Editar
|
||||||
|
undo = Desfacer
|
||||||
|
cut = Cortar
|
||||||
|
copy = Copiar
|
||||||
|
paste = Pegar
|
||||||
|
select-all = Seleccionar todo
|
||||||
|
view = Ver
|
||||||
|
zoom-in = Aumentar Zoom
|
||||||
|
default-size = Tamaño por defecto
|
||||||
|
zoom-out = Afastar Zoom
|
||||||
|
menu-settings = Axustes...
|
||||||
|
cosmic-files = Ficheiros COSMIC
|
||||||
|
comment = Xestor de ficheiros para o escritorio COSMIC
|
||||||
|
keywords = Cartafol;Xestor;
|
||||||
|
empty-folder = Cartafol baleiro
|
||||||
|
empty-folder-hidden = Cartafol baleiro (contén elementos agochados)
|
||||||
|
no-results = Non se atoparon resultados
|
||||||
|
filesystem = Sistema de ficheiros
|
||||||
|
home = Inicio
|
||||||
|
networks = Redes
|
||||||
|
notification-in-progress = Operacións de ficheiros en progreso
|
||||||
|
trash = Lixo
|
||||||
|
recents = Recentes
|
||||||
|
today = Hoxe
|
||||||
|
desktop-view-options = Axustes da vista do escritorio…
|
||||||
|
show-on-desktop = Amosar no Escritorio
|
||||||
|
desktop-folder-content = Contido do cartafol Escritorio
|
||||||
|
mounted-drives = Unidades montadas
|
||||||
|
trash-folder-icon = Icona do cartafol do Lixo
|
||||||
|
icon-size-and-spacing = Tamaño e espazado das iconas
|
||||||
|
icon-size = Tamaño de icona
|
||||||
|
grid-spacing = Espazado da grella
|
||||||
|
modified = Modificado
|
||||||
|
trashed-on = No lixo
|
||||||
|
size = Tamaño
|
||||||
|
details = Detalles
|
||||||
|
dismiss = Descartar a mensaxe
|
||||||
|
operations-running =
|
||||||
|
{ $running } { $executandose ->
|
||||||
|
[unha] operacion
|
||||||
|
*[outra] operacions
|
||||||
|
} executandose ({ $percent }%)...
|
||||||
|
operations-running-finished =
|
||||||
|
{ $running } { $executandose ->
|
||||||
|
[unha] operacion
|
||||||
|
*[outra] operacions
|
||||||
|
} executandose ({ $percent }%), { $finished } rematadas...
|
||||||
|
pause = Pausa
|
||||||
|
resume = Retomar
|
||||||
|
create-archive = Crear arquivo comprimido
|
||||||
|
copy-to-title = Seleccionar o destino da copia
|
||||||
|
copy-to-button-label = Copiar
|
||||||
|
extract-password-required = Contrasinal necesario
|
||||||
|
extract-to = Extraer en…
|
||||||
|
extract-to-title = Extraer a cartafol
|
||||||
|
empty-trash = Baleirar Lixo
|
||||||
|
empty-trash-title = Baleirar o lixo?
|
||||||
|
empty-trash-warning = Os elementos do cartafol do lixo eliminaranse de forma permanente
|
||||||
|
mount-error = Non é posible acceder a unidade
|
||||||
|
move-to-title = Seleccionar o destino do movemento
|
||||||
|
move-to-button-label = Mover
|
||||||
|
create-new-file = Crear un novo ficheiro
|
||||||
|
create-new-folder = Crear novo cartafol
|
||||||
|
file-name = Nome do ficheiro
|
||||||
|
folder-name = Nome do cartafol
|
||||||
|
file-already-exists = Existe un ficheiro co mesmo nome
|
||||||
|
folder-already-exists = Existe un cartafol co mesmo nome
|
||||||
|
name-hidden = Os nomes que comecen por "." agocharanse
|
||||||
|
name-invalid = O nome non pode ser "{ $filename }"
|
||||||
|
name-no-slashes = O nome non pode conter barras
|
||||||
|
create = Crear
|
||||||
|
open = Abrir
|
||||||
|
open-file = Abrir ficheiro
|
||||||
|
open-folder = Abrir cartafol
|
||||||
|
open-in-new-tab = Abrir nunha nova lapela
|
||||||
|
open-in-new-window = Abrir nunha nova xanela
|
||||||
|
open-item-location = Abrir ubicación do ítem
|
||||||
|
open-multiple-files = Abrir multiples ficheiros
|
||||||
|
open-multiple-folders = Abrir multiples cartafoles
|
||||||
|
save-file = Gardar ficheiro
|
||||||
|
open-with-title = Como queres abrir «{ $name }»?
|
||||||
|
browse-store = Atopar { $store }
|
||||||
|
other-apps = Outras aplicacións
|
||||||
|
related-apps = Aplicacións relacionadas
|
||||||
|
context-action = Acción contextual
|
||||||
|
context-action-confirm-title = Executar "{ $name }"?
|
||||||
|
context-action-confirm-warning =
|
||||||
|
Esto vaise executar en { $items } { $items ->
|
||||||
|
[un] item
|
||||||
|
*[outro] items
|
||||||
|
}.
|
||||||
|
selected-items = Os { $items } elementos seleccionados
|
||||||
|
permanently-delete-question = Eliminar permanentemente?
|
||||||
|
permanently-delete-warning = { $target } será eliminado permanentemente. Esta acción non se poderá desfacer.
|
||||||
|
rename-file = Renomear ficheiro
|
||||||
|
rename-folder = Renomear cartafol
|
||||||
|
rename-confirm = Renomear
|
||||||
|
replace-title = "{ $filename }" xa existe nesta ubicación
|
||||||
|
replace-warning = Queres substituílo polo que estás a gardar? Ao substituílo sobrescribirase o seu contido.
|
||||||
|
replace-warning-operation = Queres substituílo? Ao substituílo sobrescribirase o seu contido.
|
||||||
|
original-file = Ficheiro orixinal
|
||||||
|
replace-with = Remplazar con
|
||||||
|
apply-to-all = Aplicar a todo
|
||||||
|
keep-both = Manter ambos
|
||||||
|
skip = Saltar
|
||||||
|
set-executable-and-launch = Marcar como executable e lanzalo
|
||||||
|
set-executable-and-launch-description = Queres marcar «{ $name }» como executábel e lanzalo?
|
||||||
|
set-and-launch = Marcar e executar
|
||||||
|
open-with = Abrir con
|
||||||
|
owner = Propietario
|
||||||
|
group = Grupo
|
||||||
|
other = Outro
|
||||||
|
mixed = Mesturar
|
||||||
|
none = Ningún
|
||||||
|
execute-only = Só execución
|
||||||
|
write-only = Só escritura
|
||||||
|
write-execute = Escritura e execución
|
||||||
|
read-only = Só lectura
|
||||||
|
read-execute = Lectura e execución
|
||||||
|
read-write = Lectura e escritura
|
||||||
|
read-write-execute = Lectura, escritura e execución
|
||||||
|
favorite-path-error = Erro abrindo o directorio
|
||||||
|
favorite-path-error-description =
|
||||||
|
Non foi posíbel abrir «{ $path }».
|
||||||
|
É posíbel que «{ $path }» non exista ou que non teñas permisos para abrilo.
|
||||||
|
|
||||||
|
Queres retiralo da barra lateral?
|
||||||
|
remove = Eliminar
|
||||||
|
keep = Manter
|
||||||
|
add-network-drive = Engadir unidade de rede
|
||||||
|
connect = Conectar
|
||||||
|
connect-anonymously = Conectar de xeito anonimo
|
||||||
|
connecting = Conectando...
|
||||||
|
domain = Dominio
|
||||||
|
enter-server-address = Introducir a dirección do servidor
|
||||||
|
network-drive-description =
|
||||||
|
Os enderezos dos servidores inclúen un prefixo de protocolo e un enderezo.
|
||||||
|
Exemplos: ssh://192.168.0.1, ftp://[2001:db8::1]
|
||||||
|
network-drive-schemes =
|
||||||
|
Protocolos dispoñíbeis,Prefixo
|
||||||
|
AppleTalk,afp://
|
||||||
|
Protocolo de transferencia de ficheiros,ftp:// ou ftps://
|
||||||
|
Sistema de ficheiros en rede,nfs://
|
||||||
|
Server Message Block,smb://
|
||||||
|
Protocolo de transferencia de ficheiros por SSH,sftp:// ou ssh://
|
||||||
|
WebDAV,dav:// ou davs://
|
||||||
|
network-drive-error = Non foi posible acceder a unidade de rede
|
||||||
|
password = Contrasinal
|
||||||
|
remember-password = Recordar o contrasinal
|
||||||
|
try-again = Voltar a intentar
|
||||||
|
username = Nome de usuario
|
||||||
|
cancelled = Cancelado
|
||||||
|
edit-history = Editar historial
|
||||||
|
history = Historial
|
||||||
|
no-history = Non hai elementos no historial.
|
||||||
|
pending = Pendente
|
||||||
|
progress = { $percent }%
|
||||||
|
progress-cancelled = { $percent }%, cancelado
|
||||||
|
progress-failed = { $percent }%, fallou
|
||||||
|
progress-paused = { $percent }%, pausado
|
||||||
|
failed = Fallou
|
||||||
|
complete = Completado
|
||||||
|
compressing =
|
||||||
|
Comprimindo { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }» ({ $progress })...
|
||||||
|
compressed =
|
||||||
|
Comprimidos { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }»
|
||||||
|
copy_noun = Copiar
|
||||||
|
pasted-image = Imaxe pegada
|
||||||
|
pasted-text = Texto Pegado
|
||||||
|
pasted-video = Video pegado
|
||||||
|
creating = Creando "{ $name }" en "{ $parent }"
|
||||||
|
created = Creado "{ $name }" en "{ $parent }"
|
||||||
|
copying =
|
||||||
|
Copiando { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }» ({ $progress })...
|
||||||
|
copied =
|
||||||
|
Copiados { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }»
|
||||||
|
deleted =
|
||||||
|
Eliminando { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} do lixo ({ $progress })
|
||||||
|
emptying-trash = Baleirando { trash } ({ $progress })...
|
||||||
|
emptied-trash = Baleirado o { trash }
|
||||||
|
extracting =
|
||||||
|
Extraendo { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }» ({ $progress })...
|
||||||
|
extracted =
|
||||||
|
Extraídos { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }»
|
||||||
|
setting-executable-and-launching = Marcando «{ $name }» como executábel e executándoo
|
||||||
|
set-executable-and-launched = «{ $name }» marcouse como executábel e executouse
|
||||||
|
setting-permissions = Establecendo os permisos de «{ $name }» en { $mode }
|
||||||
|
set-permissions = Establecéronse os permisos de «{ $name }» en { $mode }
|
||||||
|
moving =
|
||||||
|
Movendo { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }» ({ $progress })...
|
||||||
|
moved =
|
||||||
|
Movidos { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de «{ $from }» a «{ $to }»
|
||||||
|
permanently-deleting =
|
||||||
|
Eliminando permanentemente { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
}
|
||||||
|
permanently-deleted =
|
||||||
|
Eliminados permanentemente { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
}
|
||||||
|
removing-from-recents =
|
||||||
|
Retirando { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} dos { recents }
|
||||||
|
removed-from-recents =
|
||||||
|
Retirado { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de { recents }
|
||||||
|
renaming = Renomeando "{ $from }" a "{ $to }"
|
||||||
|
renamed = Renomeado "{ $from }" a "{ $to }"
|
||||||
|
restoring =
|
||||||
|
Restaurando { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de { trash } ({ $progress })...
|
||||||
|
restored =
|
||||||
|
Restaurado { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} de { trash }
|
||||||
|
unknown-folder = cartafol descoñecido
|
||||||
|
menu-open-with = Abrir con...
|
||||||
|
default-app = { $name } (por defecto)
|
||||||
|
show-details = Amosar detalles
|
||||||
|
type = Tipo: { $mime }
|
||||||
|
items = Elementos: { $items }
|
||||||
|
item-size = Tamaño: { $size }
|
||||||
|
item-created = Creado: { $created }
|
||||||
|
item-modified = Modificado: { $modified }
|
||||||
|
item-accessed = Accedido: { $accessed }
|
||||||
|
calculating = Calculando...
|
||||||
|
checksum = { $kind } checksum
|
||||||
|
calculate = Calculado
|
||||||
|
error = Erro
|
||||||
|
single-click = Clic único para abrir
|
||||||
|
show-recents = Cartafol de recentes no panel lateral
|
||||||
|
type-to-search = Escribe para atopar
|
||||||
|
type-to-search-recursive = Busca no cartafol actual e en todos os subcartafoles
|
||||||
|
type-to-search-enter-path = Introduce a ruta do cartafol ou ficheiro
|
||||||
|
type-to-search-select = Selecciona o primeiro ficheiro ou cartafol coincidente
|
||||||
|
add-to-sidebar = Engadir o panel lateral
|
||||||
|
clear-recents-history = Limpar historial de recentes
|
||||||
|
compress = Comprimir...
|
||||||
|
copy-to = Copiar a...
|
||||||
|
delete-permanently = Eliminar permanentemente
|
||||||
|
eject = Expulsar
|
||||||
|
extract-here = Extraer
|
||||||
|
new-file = Novo ficheiro...
|
||||||
|
new-folder = Novo cartafol...
|
||||||
|
open-in-terminal = Abrir no terminal
|
||||||
|
move-to = Mover a...
|
||||||
|
move-to-trash = Mover ao lixo
|
||||||
|
restore-from-trash = Recuperar do lixo
|
||||||
|
remove-from-sidebar = Eliminar do panel lateral
|
||||||
|
sort-by-name = Ordenar por nome
|
||||||
|
sort-by-modified = Ordenar por modificación
|
||||||
|
sort-by-size = Ordenar por tamaño
|
||||||
|
sort-by-trashed = Ordenar pola data de eliminación
|
||||||
|
remove-from-recents = Eliminar de recentes
|
||||||
|
change-wallpaper = Cambiar fondo de pantalla...
|
||||||
|
desktop-appearance = Apariencia do Escritorio...
|
||||||
|
display-settings = Axustes de pantalla...
|
||||||
|
new-tab = Nova lapela
|
||||||
|
reload-folder = Recargar cartafol
|
||||||
|
rename = Renomear...
|
||||||
|
close-tab = Pechar lapela
|
||||||
|
copy-path = Copiar ruta
|
||||||
|
grid-view = Vista de grella
|
||||||
|
list-view = Vista de lista
|
||||||
|
show-hidden-files = Amosar ficheiros ocultos
|
||||||
|
list-directories-first = Listar primeiro os directorios
|
||||||
|
gallery-preview = Vista previa da galería
|
||||||
|
menu-about = Sobre Ficheiros COSMIC...
|
||||||
|
sort = Ordenar
|
||||||
|
sort-a-z = A-Z
|
||||||
|
sort-z-a = Z-A
|
||||||
|
sort-newest-first = Novos primeiro
|
||||||
|
sort-oldest-first = Antigos primeiro
|
||||||
|
sort-smallest-to-largest = Do máis pequeno ao máis grande
|
||||||
|
sort-largest-to-smallest = Do máis grande ao máis pequeno
|
||||||
|
deleting =
|
||||||
|
Eliminando { $items } { $items ->
|
||||||
|
[one] elemento
|
||||||
|
*[other] elementos
|
||||||
|
} da { trash } ({ $progress })...
|
||||||
|
|
@ -5,7 +5,7 @@ no-results = कोई परिणाम नहीं
|
||||||
filesystem = फाइल सिस्टम
|
filesystem = फाइल सिस्टम
|
||||||
home = होम
|
home = होम
|
||||||
networks = नेटवर्क्स
|
networks = नेटवर्क्स
|
||||||
notification-in-progress = फाइल संचालन प्रगति पर है।
|
notification-in-progress = फ़ाइल संचालन प्रगति पर हैं
|
||||||
trash = कचरा
|
trash = कचरा
|
||||||
recents = हाल के
|
recents = हाल के
|
||||||
undo = पूर्ववत करें
|
undo = पूर्ववत करें
|
||||||
|
|
@ -33,8 +33,8 @@ create-archive = संग्रह बनाएँ
|
||||||
|
|
||||||
## Empty Trash Dialog
|
## Empty Trash Dialog
|
||||||
|
|
||||||
empty-trash = कचरा खाली करें
|
empty-trash = रद्दी साफ़ करें
|
||||||
empty-trash-warning = क्या आप वाकई कचरे में सभी आइटमों को स्थायी रूप से हटाना चाहते हैं?
|
empty-trash-warning = रद्दी फ़ोल्डर में मौजूद आइटम स्थायी रूप से हटा दिए जाएंगे
|
||||||
|
|
||||||
## New File/Folder Dialog
|
## New File/Folder Dialog
|
||||||
|
|
||||||
|
|
@ -42,11 +42,11 @@ create-new-file = नई फाइल बनाएँ
|
||||||
create-new-folder = नया फ़ोल्डर बनाएँ
|
create-new-folder = नया फ़ोल्डर बनाएँ
|
||||||
file-name = फाइल का नाम
|
file-name = फाइल का नाम
|
||||||
folder-name = फ़ोल्डर का नाम
|
folder-name = फ़ोल्डर का नाम
|
||||||
file-already-exists = इसी नाम की फाइल पहले से मौजूद है।
|
file-already-exists = उस नाम की फ़ाइल पहले से मौजूद है
|
||||||
folder-already-exists = इसी नाम का फ़ोल्डर पहले से मौजूद है।
|
folder-already-exists = उस नाम का फ़ोल्डर पहले से मौजूद है
|
||||||
name-hidden = "." से शुरू होने वाले नाम छिपे रहेंगे।
|
name-hidden = "." से शुरू होने वाले नाम छिपे होंगे
|
||||||
name-invalid = नाम "{ $filename }" मान्य नहीं है।
|
name-invalid = नाम "{ $filename }" नहीं हो सकता
|
||||||
name-no-slashes = नाम में स्लैश का उपयोग नहीं किया जा सकता है।
|
name-no-slashes = नाम में स्लैश नहीं हो सकते
|
||||||
|
|
||||||
## Open/Save Dialog
|
## Open/Save Dialog
|
||||||
|
|
||||||
|
|
@ -75,8 +75,8 @@ rename-folder = फ़ोल्डर का नाम बदलें
|
||||||
|
|
||||||
## Replace Dialog
|
## Replace Dialog
|
||||||
|
|
||||||
replace = प्रतिस्थापित करें
|
replace = बदलें
|
||||||
replace-title = { $filename } पहले से इस स्थान पर मौजूद है।
|
replace-title = { $filename } पहले से इस स्थान पर मौजूद है
|
||||||
replace-warning = क्या आप इसे प्रतिस्थापित करना चाहते हैं? यदि प्रतिस्थापित किया गया, तो मौजूदा फ़ाइल को ओवरराइट किया जाएगा।
|
replace-warning = क्या आप इसे प्रतिस्थापित करना चाहते हैं? यदि प्रतिस्थापित किया गया, तो मौजूदा फ़ाइल को ओवरराइट किया जाएगा।
|
||||||
replace-warning-operation = क्या आप इसे बदलना चाहते हैं? प्रतिस्थापित करने पर मौजूदा फ़ाइल ओवरराइट हो जाएगी।
|
replace-warning-operation = क्या आप इसे बदलना चाहते हैं? प्रतिस्थापित करने पर मौजूदा फ़ाइल ओवरराइट हो जाएगी।
|
||||||
original-file = मूल फ़ाइल
|
original-file = मूल फ़ाइल
|
||||||
|
|
@ -211,13 +211,13 @@ show-details = विवरण दिखाएँ
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
settings = सेटिंग
|
settings = सेटिंग्स
|
||||||
|
|
||||||
### Appearance
|
### Appearance
|
||||||
|
|
||||||
appearance = रूप
|
appearance = रुप-रंग
|
||||||
theme = थीम
|
theme = प्रसंग
|
||||||
match-desktop = सिस्टम सेटिंग्स से मेल खाएँ
|
match-desktop = डेस्कटॉप से मेल खाएँ
|
||||||
dark = डार्क
|
dark = डार्क
|
||||||
light = लाइट
|
light = लाइट
|
||||||
# Context menu
|
# Context menu
|
||||||
|
|
@ -251,27 +251,27 @@ new-tab = नया टैब
|
||||||
new-window = नई विंडो
|
new-window = नई विंडो
|
||||||
rename = नाम बदलें...
|
rename = नाम बदलें...
|
||||||
close-tab = टैब बंद करें
|
close-tab = टैब बंद करें
|
||||||
quit = बंद करें
|
quit = बाहर जाएँ
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
edit = संपादित करें
|
edit = संपादन
|
||||||
cut = कट करें
|
cut = काटें
|
||||||
copy = नकल करें
|
copy = कॉपी करें
|
||||||
paste = चिपकाएँ
|
paste = चिपकाएँ
|
||||||
select-all = सभी चुनें
|
select-all = सभी चुनें
|
||||||
|
|
||||||
## View
|
## View
|
||||||
|
|
||||||
zoom-in = ज़ूम इन करें
|
zoom-in = बड़ा करें
|
||||||
default-size = डिफ़ॉल्ट आकार
|
default-size = मूल आकार
|
||||||
zoom-out = ज़ूम आउट करें
|
zoom-out = छोटा करें
|
||||||
view = दृश्य
|
view = दृश्य
|
||||||
grid-view = ग्रिड दृश्य
|
grid-view = ग्रिड दृश्य
|
||||||
list-view = सूची दृश्य
|
list-view = सूची दृश्य
|
||||||
show-hidden-files = छिपी हुई फाइलें दिखाएँ
|
show-hidden-files = छिपी हुई फाइलें दिखाएँ
|
||||||
list-directories-first = सबसे पहले डाइरेक्ट्री दिखाएँ
|
list-directories-first = सबसे पहले डाइरेक्ट्री दिखाएँ
|
||||||
menu-settings = सेटिंग्स...
|
menu-settings = सेटिंग्स..।
|
||||||
menu-about = कॉस्मिक फाइल्स के बारे में...
|
menu-about = कॉस्मिक फाइल्स के बारे में...
|
||||||
|
|
||||||
## Sort
|
## Sort
|
||||||
|
|
@ -284,4 +284,98 @@ sort-oldest-first = पुराने से नए
|
||||||
sort-smallest-to-largest = छोटे से बड़े
|
sort-smallest-to-largest = छोटे से बड़े
|
||||||
sort-largest-to-smallest = बड़े से छोटे
|
sort-largest-to-smallest = बड़े से छोटे
|
||||||
repository = रिपॉजिटरी
|
repository = रिपॉजिटरी
|
||||||
support = सहायता
|
support = समर्थन
|
||||||
|
read-execute = पढ़ें और निष्पादित करें
|
||||||
|
deleted =
|
||||||
|
{ trash } से { $items } { $items ->
|
||||||
|
[one] आइटम मिटाया गया
|
||||||
|
*[other] आइटम मिटाए गए
|
||||||
|
}
|
||||||
|
dismiss = संदेश खारिज करें
|
||||||
|
favorite-path-error = निर्देशिका खोलने में त्रुटि
|
||||||
|
progress = { $percent }%
|
||||||
|
related-apps = संबंधित ऐप्स
|
||||||
|
removing-from-recents =
|
||||||
|
{ recents } से { $items } { $items ->
|
||||||
|
[one] आइटम हटाया जा रहा है
|
||||||
|
*[other] आइटम हटाए जा रहे हैं
|
||||||
|
}
|
||||||
|
remove = हटाएँ
|
||||||
|
read-write-execute = पढ़ें, लिखें और निष्पादित करें
|
||||||
|
other-apps = अन्य ऐप्स
|
||||||
|
pause = विराम
|
||||||
|
keep = रखें
|
||||||
|
permanently-deleting =
|
||||||
|
{ $items } { $items ->
|
||||||
|
[one] आइटम स्थायी रूप से मिटाया जा रहा है
|
||||||
|
*[other] आइटम स्थायी रूप से मिटाए जा रहे हैं
|
||||||
|
}
|
||||||
|
read-write = पढ़ें और लिखें
|
||||||
|
none = कोई नहीं
|
||||||
|
resume = फिर से शुरू करें
|
||||||
|
grid-spacing = ग्रिड स्पेसिंग
|
||||||
|
extract-to = इस रूप में निकालें..।
|
||||||
|
delete = हटाएं
|
||||||
|
read-only = केवल पढ़ने के लिए
|
||||||
|
deleting =
|
||||||
|
{ trash } से { $items } { $items ->
|
||||||
|
[one] आइटम मिटाया जा रहा है
|
||||||
|
*[other] आइटम मिटाए जा रहे हैं
|
||||||
|
} ({ $progress })..।
|
||||||
|
execute-only = केवल निष्पादित करें
|
||||||
|
details = विवरण
|
||||||
|
mount-error = ड्राइव तक पहुँचने में असमर्थ
|
||||||
|
removed-from-recents =
|
||||||
|
{ recents } से { $items } { $items ->
|
||||||
|
[one] आइटम हटाया गया
|
||||||
|
*[other] आइटम हटाए गए
|
||||||
|
}
|
||||||
|
progress-paused = { $percent }%, रुका हुआ
|
||||||
|
cancelled = रद्द किया गया
|
||||||
|
operations-running-finished =
|
||||||
|
{ $running } { $running ->
|
||||||
|
[one] ऑपरेशन
|
||||||
|
*[other] ऑपरेशन
|
||||||
|
} चल रहा है ({ $percent }%), { $finished } समाप्त..।
|
||||||
|
progress-failed = { $percent }%, विफल
|
||||||
|
extract-to-title = फ़ोल्डर में निकालें
|
||||||
|
open-with = इससे खोलें
|
||||||
|
permanently-deleted =
|
||||||
|
{ $items } { $items ->
|
||||||
|
[one] आइटम स्थायी रूप से मिटाया गया
|
||||||
|
*[other] आइटम स्थायी रूप से मिटाए गए
|
||||||
|
}
|
||||||
|
write-execute = लिखें और निष्पादित करें
|
||||||
|
extract-password-required = पासवर्ड आवश्यक है
|
||||||
|
progress-cancelled = { $percent }%, रद्द किया गया
|
||||||
|
write-only = केवल लिखने के लिए
|
||||||
|
permanently-delete-warning = { $target } को स्थाई रूप से हटा दिया जाएगा। इस कार्रवाई को पूर्ववत नहीं किया जा सकता है।
|
||||||
|
favorite-path-error-description =
|
||||||
|
"{ $path }" को खोला नहीं जा सकता
|
||||||
|
"{ $path }" मौजूद नहीं हो सकता है या आपके पास इसे खोलने की अनुमति नहीं हो सकती है
|
||||||
|
|
||||||
|
क्या आप इसे साइडबार से हटाना चाहते हैं?
|
||||||
|
empty-trash-title = रद्दी साफ़ करें?
|
||||||
|
permanently-delete-question = स्थाई रूप से हटाएं?
|
||||||
|
operations-running =
|
||||||
|
{ $running } { $running ->
|
||||||
|
[one] ऑपरेशन
|
||||||
|
*[other] ऑपरेशन
|
||||||
|
} चल रहा है ({ $percent }%)..।
|
||||||
|
copy-to-title = कॉपी गंतव्य चुनें
|
||||||
|
copy-to-button-label = कॉपी
|
||||||
|
move-to-title = मूव गंतव्य चुनें
|
||||||
|
move-to-button-label = मूव
|
||||||
|
context-action = संदर्भ क्रिया
|
||||||
|
context-action-confirm-title = "{ $name }" चलाएँ?
|
||||||
|
context-action-confirm-warning =
|
||||||
|
यह { $items } { $items ->
|
||||||
|
[one] आइटम
|
||||||
|
*[other] आइटम
|
||||||
|
} पर चलेगा।
|
||||||
|
run = चलाएँ
|
||||||
|
rename-confirm = नाम बदलें
|
||||||
|
mixed = मिश्रित
|
||||||
|
pasted-image = चिपकाई गई छवि
|
||||||
|
pasted-text = चिपकाया गया पाठ
|
||||||
|
pasted-video = चिपकाया गया वीडियो
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ default-app = { $name } (alapértelmezett)
|
||||||
|
|
||||||
show-details = Részletek megjelenítése
|
show-details = Részletek megjelenítése
|
||||||
type = Típus: { $mime }
|
type = Típus: { $mime }
|
||||||
items = Elemek: { $items }
|
items = Elemek száma: { $items }
|
||||||
item-size = Méret: { $size }
|
item-size = Méret: { $size }
|
||||||
item-created = Létrehozva: { $created }
|
item-created = Létrehozva: { $created }
|
||||||
item-modified = Módosítva: { $modified }
|
item-modified = Módosítva: { $modified }
|
||||||
|
|
@ -446,3 +446,9 @@ context-action-confirm-warning =
|
||||||
} fog lefutni.
|
} fog lefutni.
|
||||||
run = Futtatás
|
run = Futtatás
|
||||||
rename-confirm = Átnevezés
|
rename-confirm = Átnevezés
|
||||||
|
checksum = { $kind }-ellenőrzőösszeg
|
||||||
|
calculate = Számítás
|
||||||
|
error = Hiba
|
||||||
|
sidebar-label = Oldalsávcímke
|
||||||
|
search-application = Keresés alkalmazásnév alapján
|
||||||
|
change-sidebar-label = Oldalsávcímke módosítása
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ settings = Pengaturan
|
||||||
single-click = Klik sekali untuk membuka
|
single-click = Klik sekali untuk membuka
|
||||||
appearance = Tampilan
|
appearance = Tampilan
|
||||||
theme = Tema
|
theme = Tema
|
||||||
match-desktop = Cocokkan desktop
|
match-desktop = Cocok desktop
|
||||||
dark = Gelap
|
dark = Gelap
|
||||||
light = Terang
|
light = Terang
|
||||||
type-to-search = Ketik untuk mencari
|
type-to-search = Ketik untuk mencari
|
||||||
|
|
@ -328,3 +328,9 @@ context-action-confirm-warning =
|
||||||
*[other] item
|
*[other] item
|
||||||
}.
|
}.
|
||||||
rename-confirm = Ganti nama
|
rename-confirm = Ganti nama
|
||||||
|
checksum = { $kind } checksum
|
||||||
|
calculate = Hitung
|
||||||
|
error = Galat
|
||||||
|
sidebar-label = Label bilah sisi
|
||||||
|
search-application = Cari berdasarkan nama aplikasi
|
||||||
|
change-sidebar-label = Ubah label bilah sisi
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
cosmic-files = COSMIC Files
|
cosmic-files = COSMIC Files
|
||||||
comment = File manager di COSMIC
|
comment = File manager per il desktop COSMIC
|
||||||
keywords = File;Archivi;Cartelle;Explorer;
|
keywords = File;Archivi;Cartelle;Explorer;
|
||||||
empty-folder = Cartella vuota
|
empty-folder = Cartella vuota
|
||||||
empty-folder-hidden = Cartella vuota (con elementi nascosti)
|
empty-folder-hidden = Cartella vuota (con elementi nascosti)
|
||||||
|
|
@ -7,7 +7,7 @@ no-results = Nessun risultato trovato
|
||||||
filesystem = Filesystem
|
filesystem = Filesystem
|
||||||
home = Home
|
home = Home
|
||||||
networks = Reti
|
networks = Reti
|
||||||
notification-in-progress = Operazioni sui file in corso.
|
notification-in-progress = Operazioni sui file in corso
|
||||||
trash = Cestino
|
trash = Cestino
|
||||||
recents = Recenti
|
recents = Recenti
|
||||||
undo = Annulla
|
undo = Annulla
|
||||||
|
|
@ -322,7 +322,7 @@ single-click = Click singolo per aprire
|
||||||
|
|
||||||
appearance = Aspetto
|
appearance = Aspetto
|
||||||
theme = Tema
|
theme = Tema
|
||||||
match-desktop = Sistema
|
match-desktop = Abbina al desktop
|
||||||
dark = Scuro
|
dark = Scuro
|
||||||
light = Chiaro
|
light = Chiaro
|
||||||
|
|
||||||
|
|
@ -422,3 +422,4 @@ removed-from-recents =
|
||||||
[one] elemento
|
[one] elemento
|
||||||
*[other] elementi
|
*[other] elementi
|
||||||
} da { recents }
|
} da { recents }
|
||||||
|
run = Esegui
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ name = Isem
|
||||||
modified = Ittusnifel
|
modified = Ittusnifel
|
||||||
trashed-on = Yettwakkes ɣer tqecwalt n yiḍumman
|
trashed-on = Yettwakkes ɣer tqecwalt n yiḍumman
|
||||||
size = Tiddi
|
size = Tiddi
|
||||||
details = Talqayt
|
details = Ifatusen
|
||||||
pause = Serǧu
|
pause = Serǧu
|
||||||
resume = Kemmel
|
resume = Kemmel
|
||||||
create-archive = Snulfu-d aɣbaṛ
|
create-archive = Snulfu-d aɣbaṛ
|
||||||
|
|
@ -40,7 +40,7 @@ file-already-exists = Afaylu s yisem-agi yella yakan
|
||||||
folder-already-exists = Akaram s yisem-agi yella yakan
|
folder-already-exists = Akaram s yisem-agi yella yakan
|
||||||
name-hidden = Ismawen ibeddun s "." ad ttwaffren
|
name-hidden = Ismawen ibeddun s "." ad ttwaffren
|
||||||
name-invalid = Isem ur yezmir ara ad yili "{ $filename }"
|
name-invalid = Isem ur yezmir ara ad yili "{ $filename }"
|
||||||
cancel = Sefsex
|
cancel = Semmet
|
||||||
create = Snulfu-d
|
create = Snulfu-d
|
||||||
open = Ldi
|
open = Ldi
|
||||||
open-file = Ldi afaylu
|
open-file = Ldi afaylu
|
||||||
|
|
@ -72,7 +72,7 @@ comment = Amsefrak n yifuyla i tnarit COSMIC
|
||||||
keywords = Akaram;Amsefrak;
|
keywords = Akaram;Amsefrak;
|
||||||
delete = kkes
|
delete = kkes
|
||||||
replace = Semselsi
|
replace = Semselsi
|
||||||
support = Tallalt
|
support = Tallelt
|
||||||
settings = Iɣewwaṛen
|
settings = Iɣewwaṛen
|
||||||
appearance = Timeẓri
|
appearance = Timeẓri
|
||||||
theme = Asentel
|
theme = Asentel
|
||||||
|
|
@ -86,10 +86,10 @@ zoom-out = Asemẓi
|
||||||
view = Wali
|
view = Wali
|
||||||
menu-settings = Iɣewwaṛen…
|
menu-settings = Iɣewwaṛen…
|
||||||
save = Sekles
|
save = Sekles
|
||||||
match-desktop = Amṣada d tnarit
|
match-desktop = Semṣada akked tnarit
|
||||||
file = Afaylu
|
file = Afaylu
|
||||||
new-window = Asfaylu amaynut
|
new-window = Asfaylu amaynut
|
||||||
quit = Tuffɣa
|
quit = Ffeɣ
|
||||||
edit = Ẓreg
|
edit = Ẓreg
|
||||||
cut = Gzem
|
cut = Gzem
|
||||||
copy = Nɣel
|
copy = Nɣel
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ name = Аты
|
||||||
modified = Өзгертілген
|
modified = Өзгертілген
|
||||||
trashed-on = Қоқыс шелегіне тасталған
|
trashed-on = Қоқыс шелегіне тасталған
|
||||||
size = Өлшемі
|
size = Өлшемі
|
||||||
details = Ақпараты
|
details = Толық ақпарат
|
||||||
dismiss = Хабарламаны елемеу
|
dismiss = Хабарламаны елемеу
|
||||||
operations-running =
|
operations-running =
|
||||||
{ $running } { $running ->
|
{ $running } { $running ->
|
||||||
|
|
@ -246,10 +246,10 @@ item-accessed = Қол жеткізілген: { $accessed }
|
||||||
calculating = Есептеу...
|
calculating = Есептеу...
|
||||||
settings = Баптаулар
|
settings = Баптаулар
|
||||||
single-click = Ашу үшін бір рет шерту
|
single-click = Ашу үшін бір рет шерту
|
||||||
appearance = Сыртқы түрі
|
appearance = Сыртқы көрініс
|
||||||
theme = Тақырып
|
theme = Тема
|
||||||
match-desktop = Жұмыс үстеліне сәйкес келу
|
match-desktop = Жұмыс үстеліне сәйкес болу
|
||||||
dark = Күңгірт
|
dark = Қою
|
||||||
light = Ашық
|
light = Ашық
|
||||||
type-to-search = Іздеу үшін теру
|
type-to-search = Іздеу үшін теру
|
||||||
type-to-search-recursive = Ағымдағы бума мен барлық ішкі бумаларды іздейді
|
type-to-search-recursive = Ағымдағы бума мен барлық ішкі бумаларды іздейді
|
||||||
|
|
@ -328,3 +328,6 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Орындау
|
run = Орындау
|
||||||
rename-confirm = Атын өзгерту
|
rename-confirm = Атын өзгерту
|
||||||
|
checksum = { $kind } бақылау сомасы
|
||||||
|
calculate = Есептеу
|
||||||
|
error = Қате
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,10 @@ new-window = Çarçoveya nû
|
||||||
remove = Rake
|
remove = Rake
|
||||||
zoom-out = Dûr bike
|
zoom-out = Dûr bike
|
||||||
compressing =
|
compressing =
|
||||||
{ $items } tê guvaştin { $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }" ({ $progress })...
|
} tê guvaştin ji "{ $from }" bo "{ $to }" ({ $progress })...
|
||||||
move-to-trash = Bilivîne bo jêbirdankê
|
move-to-trash = Bilivîne bo jêbirdankê
|
||||||
menu-about = Derbarê Pelên COSMIC...
|
menu-about = Derbarê Pelên COSMIC...
|
||||||
file-already-exists = Pelek bi heman navî jixwe heye
|
file-already-exists = Pelek bi heman navî jixwe heye
|
||||||
|
|
@ -42,10 +42,10 @@ open-multiple-files = Gelek pelan veke
|
||||||
default-size = Mezinahiya berdest
|
default-size = Mezinahiya berdest
|
||||||
name-hidden = Navên ku bi "." tê destpêkirin wê werin veşartin
|
name-hidden = Navên ku bi "." tê destpêkirin wê werin veşartin
|
||||||
extracted =
|
extracted =
|
||||||
{ $items } hate derxistin { $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }"
|
} hate derxistin ji "{ $from }" bo "{ $to }"
|
||||||
create-new-folder = Peldanka nû biafrîne
|
create-new-folder = Peldanka nû biafrîne
|
||||||
folder-already-exists = Peldankek bi heman navî jixwe heye
|
folder-already-exists = Peldankek bi heman navî jixwe heye
|
||||||
create-archive = Erşîvê biafrîne
|
create-archive = Erşîvê biafrîne
|
||||||
|
|
@ -79,10 +79,10 @@ none = Ne yek
|
||||||
no-results = Tu encam nehatin dîtin
|
no-results = Tu encam nehatin dîtin
|
||||||
theme = Rûkar
|
theme = Rûkar
|
||||||
compressed =
|
compressed =
|
||||||
{ $items } hate guvaştin{ $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }"
|
} hate guvaştin ji "{ $from }" bo "{ $to }"
|
||||||
appearance = Xuyang
|
appearance = Xuyang
|
||||||
rename-folder = Navê peldankê biguherîne
|
rename-folder = Navê peldankê biguherîne
|
||||||
new-file = Pela nû...
|
new-file = Pela nû...
|
||||||
|
|
@ -95,20 +95,20 @@ light = Ronî
|
||||||
extract-to = Derxîne bo...
|
extract-to = Derxîne bo...
|
||||||
add-network-drive = Ajokarê torê tevlî bike
|
add-network-drive = Ajokarê torê tevlî bike
|
||||||
copying =
|
copying =
|
||||||
{ $items } tê jêgirtin{ $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }" ({ $progress })...
|
} tê jêgirtin ji "{ $from }" bo "{ $to }" ({ $progress })...
|
||||||
create-new-file = Pelê nû biafrîne
|
create-new-file = Pelê nû biafrîne
|
||||||
sort-by-trashed = Li gorî demê rêz bike
|
sort-by-trashed = Li gorî demê rêz bike
|
||||||
support = Piştgirî
|
support = Piştgirî
|
||||||
try-again = Dîsa hewl bide
|
try-again = Dîsa hewl bide
|
||||||
eject = Biavêje
|
eject = Biavêje
|
||||||
copied =
|
copied =
|
||||||
{ $items } hate jêgirtin { $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }"
|
} hate jêgirtin ji "{ $from }" bo "{ $to }"
|
||||||
open-in-new-window = Di çarçoveyeke nû de veke
|
open-in-new-window = Di çarçoveyeke nû de veke
|
||||||
empty-folder = Peldanka vala
|
empty-folder = Peldanka vala
|
||||||
empty-trash = Jêbirdankê vala bike
|
empty-trash = Jêbirdankê vala bike
|
||||||
|
|
@ -117,14 +117,14 @@ list-directories-first = Pêşî rêgehan lîste bike
|
||||||
folder-name = Navê peldankê
|
folder-name = Navê peldankê
|
||||||
browse-store = { $store } bigere
|
browse-store = { $store } bigere
|
||||||
remove-from-recents = Ji dawiyê rake
|
remove-from-recents = Ji dawiyê rake
|
||||||
paste = Pêve bike
|
paste = Pê ve bike
|
||||||
empty-trash-title = Jêbirdankê vala bike?
|
empty-trash-title = Jêbirdankê vala bike?
|
||||||
menu-settings = Sazkarî...
|
menu-settings = Sazkarî...
|
||||||
moving =
|
moving =
|
||||||
{ $items } tê livandin{ $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }" ({ $progress })...
|
} tê livandin ji "{ $from }" bo "{ $to }" ({ $progress })...
|
||||||
change-wallpaper = Wêneyê dîwêr biguhêrîne...
|
change-wallpaper = Wêneyê dîwêr biguhêrîne...
|
||||||
network-drive-description =
|
network-drive-description =
|
||||||
Di nav navnîşanên rajekarê de pêşgira protokolekê û navnîşanek heye.
|
Di nav navnîşanên rajekarê de pêşgira protokolekê û navnîşanek heye.
|
||||||
|
|
@ -158,8 +158,8 @@ progress-paused = { $percent }%, hate rawestandin
|
||||||
desktop-view-options = Vebijêrkên dîtina sermaseyê...
|
desktop-view-options = Vebijêrkên dîtina sermaseyê...
|
||||||
show-on-desktop = Li ser sermaseyê nîşan bide
|
show-on-desktop = Li ser sermaseyê nîşan bide
|
||||||
cancelled = Têkbirî
|
cancelled = Têkbirî
|
||||||
new-folder = Peldankan nû...
|
new-folder = Peldanka nû...
|
||||||
match-desktop = Li gorî sermaseyê
|
match-desktop = Bi sermaseyê re li hev bîne
|
||||||
name-no-slashes = Nav nabe ku "/" tê de hebe
|
name-no-slashes = Nav nabe ku "/" tê de hebe
|
||||||
operations-running-finished =
|
operations-running-finished =
|
||||||
{ $running } { $running ->
|
{ $running } { $running ->
|
||||||
|
|
@ -175,10 +175,10 @@ extract-to-title = Derxîne bo peldankê
|
||||||
icon-size = Mezinahiya îkonê
|
icon-size = Mezinahiya îkonê
|
||||||
open-with-title = Tu çawa dixwazî "{ $name }" vekî?
|
open-with-title = Tu çawa dixwazî "{ $name }" vekî?
|
||||||
extracting =
|
extracting =
|
||||||
{ $items } tê derxistin { $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo"{ $to }" ({ $progress })...
|
} tê derxistin ji "{ $from }" bo"{ $to }" ({ $progress })...
|
||||||
settings = Sazkarî
|
settings = Sazkarî
|
||||||
complete = Qediya
|
complete = Qediya
|
||||||
permanently-delete-question = Bi mayînde jê bibe?
|
permanently-delete-question = Bi mayînde jê bibe?
|
||||||
|
|
@ -193,10 +193,10 @@ sort-largest-to-smallest = Mezintir bo biçûktir
|
||||||
restore-from-trash = Ji jêbirdankê vegerîne
|
restore-from-trash = Ji jêbirdankê vegerîne
|
||||||
cut = Jê bike
|
cut = Jê bike
|
||||||
moved =
|
moved =
|
||||||
{ $items } hate livandin { $items ->
|
{ $items } { $items ->
|
||||||
[one] hêman
|
[one] hêman
|
||||||
*[other] hêman
|
*[other] hêman
|
||||||
} ji "{ $from }" bo "{ $to }"
|
} hate livandin ji "{ $from }" bo "{ $to }"
|
||||||
progress-cancelled = { $percent }%, hat têkbirin
|
progress-cancelled = { $percent }%, hat têkbirin
|
||||||
open-in-new-tab = Di rûgerê nû de veke
|
open-in-new-tab = Di rûgerê nû de veke
|
||||||
file = Pel
|
file = Pel
|
||||||
|
|
@ -220,7 +220,7 @@ trash = Jêbirdank
|
||||||
undo = Vegerîne
|
undo = Vegerîne
|
||||||
today = Îro
|
today = Îro
|
||||||
name = Nav
|
name = Nav
|
||||||
modified = Guhertî
|
modified = Guhertin
|
||||||
size = Mezinahî
|
size = Mezinahî
|
||||||
details = Hûrgilî
|
details = Hûrgilî
|
||||||
pause = Rawestîne
|
pause = Rawestîne
|
||||||
|
|
@ -229,7 +229,7 @@ copy-to-title = Rêgeha jêgirtinê hilbijêre
|
||||||
copy-to-button-label = Jê bigire
|
copy-to-button-label = Jê bigire
|
||||||
move-to-title = Rêgeha livandinê hilbijêre
|
move-to-title = Rêgeha livandinê hilbijêre
|
||||||
move-to-button-label = Bilivîne
|
move-to-button-label = Bilivîne
|
||||||
create = Biafrîne
|
create = Afirandin
|
||||||
save = Tomar bike
|
save = Tomar bike
|
||||||
context-action = Çalakiya naverokê
|
context-action = Çalakiya naverokê
|
||||||
context-action-confirm-title = "{ $name }" bixebtîne?
|
context-action-confirm-title = "{ $name }" bixebtîne?
|
||||||
|
|
@ -263,7 +263,7 @@ restoring =
|
||||||
} ji { trash } ({ $progress })...
|
} ji { trash } ({ $progress })...
|
||||||
icon-size-and-spacing = Mezinahiya îkonan û valahiya di navbera wan de
|
icon-size-and-spacing = Mezinahiya îkonan û valahiya di navbera wan de
|
||||||
type-to-search-enter-path = Riya rêgehê yan jî pelê têdixîne
|
type-to-search-enter-path = Riya rêgehê yan jî pelê têdixîne
|
||||||
menu-open-with = Veke bi...
|
menu-open-with = Veke bi riya...
|
||||||
original-file = Pelê resen
|
original-file = Pelê resen
|
||||||
read-write-execute = Xwendin, nivîsandin û xebitandin
|
read-write-execute = Xwendin, nivîsandin û xebitandin
|
||||||
calculating = Tê jimartin...
|
calculating = Tê jimartin...
|
||||||
|
|
@ -311,7 +311,7 @@ restored =
|
||||||
domain = Navper
|
domain = Navper
|
||||||
sort = Rêz bike
|
sort = Rêz bike
|
||||||
item-accessed = Gihîştin: { $accessed }
|
item-accessed = Gihîştin: { $accessed }
|
||||||
open-with = Veke bi
|
open-with = Veke bi riya
|
||||||
keep-both = Herduyan bihêle
|
keep-both = Herduyan bihêle
|
||||||
permanently-deleted =
|
permanently-deleted =
|
||||||
{ $items } bi mayînde hate jêbirin{ $items ->
|
{ $items } bi mayînde hate jêbirin{ $items ->
|
||||||
|
|
@ -325,6 +325,12 @@ replace = Biguhêrîne
|
||||||
replace-title = "{ $filename }" jixwe di vê cihê de heye
|
replace-title = "{ $filename }" jixwe di vê cihê de heye
|
||||||
unknown-folder = Peldanka nenas
|
unknown-folder = Peldanka nenas
|
||||||
write-only = Tenê nivîsandin
|
write-only = Tenê nivîsandin
|
||||||
trashed-on = Li Jêbirdankê hatiye avêtin
|
trashed-on = Jêbirî
|
||||||
mixed = Tevlihev
|
mixed = Tevlihev
|
||||||
type-to-search-select = Pel an peldanka yekem a lihevhatî hildibijêre
|
type-to-search-select = Pel an peldanka yekem a lihevhatî hildibijêre
|
||||||
|
calculate = Bijmêre
|
||||||
|
error = Şaşetî
|
||||||
|
checksum = Tevahiya { $kind } kontrol bike
|
||||||
|
sidebar-label = Nîşanka benda kêlekê
|
||||||
|
search-application = Li gorî navê sepanê bigere
|
||||||
|
change-sidebar-label = Nîşanka benda kêlekê biguhêrîne
|
||||||
|
|
|
||||||
|
|
@ -278,3 +278,12 @@ move-to-button-label = 이동
|
||||||
clear-recents-history = 최근 기록 비우기
|
clear-recents-history = 최근 기록 비우기
|
||||||
copy-path = 복사 경로
|
copy-path = 복사 경로
|
||||||
move-to-title = 이동 위치 선택
|
move-to-title = 이동 위치 선택
|
||||||
|
copy-to-title = 복사 경로 선택
|
||||||
|
run = 실행
|
||||||
|
rename-confirm = 이름 변경
|
||||||
|
mixed = 혼합됨
|
||||||
|
pasted-image = 붙여넣은 이미지
|
||||||
|
pasted-text = 붙여넣은 텍스트
|
||||||
|
pasted-video = 붙여넣은 영상
|
||||||
|
copy-to = 복사하기...
|
||||||
|
move-to = 이동하기...
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@ item-created = Sukurtas: { $created }
|
||||||
item-modified = Modifikuota: { $modified }
|
item-modified = Modifikuota: { $modified }
|
||||||
item-accessed = Paskutinė prieiga: { $accessed }
|
item-accessed = Paskutinė prieiga: { $accessed }
|
||||||
calculating = Skaičiuojama...
|
calculating = Skaičiuojama...
|
||||||
settings = Nuostatos
|
settings = Nuostatai
|
||||||
single-click = Vieno paspaudimo atidarymas
|
single-click = Vieno paspaudimo atidarymas
|
||||||
appearance = Išvaizda
|
appearance = Išvaizda
|
||||||
match-desktop = Pagal darbalaukio temą
|
match-desktop = Pagal darbalaukio temą
|
||||||
|
|
@ -276,7 +276,7 @@ new-window = Naujas langas
|
||||||
reload-folder = Perkrauti aplanką
|
reload-folder = Perkrauti aplanką
|
||||||
rename = Pervadinti...
|
rename = Pervadinti...
|
||||||
close-tab = Uždaryti skirtuką
|
close-tab = Uždaryti skirtuką
|
||||||
quit = Išeiti
|
quit = Išjungti
|
||||||
edit = Redaguoti
|
edit = Redaguoti
|
||||||
cut = Iškirpti
|
cut = Iškirpti
|
||||||
copy = Kopijuoti
|
copy = Kopijuoti
|
||||||
|
|
@ -291,7 +291,7 @@ list-view = Sąrašo išdėstymas
|
||||||
show-hidden-files = Rodyti paslėptus failus
|
show-hidden-files = Rodyti paslėptus failus
|
||||||
list-directories-first = Pirmiau pateikti aplankus
|
list-directories-first = Pirmiau pateikti aplankus
|
||||||
gallery-preview = Galerijos peržiūra
|
gallery-preview = Galerijos peržiūra
|
||||||
menu-settings = Nuostatos...
|
menu-settings = Nuostatai...
|
||||||
menu-about = Apie COSMIC Files...
|
menu-about = Apie COSMIC Files...
|
||||||
sort = Rikiuoti
|
sort = Rikiuoti
|
||||||
sort-a-z = A-Ž
|
sort-a-z = A-Ž
|
||||||
|
|
@ -318,3 +318,9 @@ copy-to = Kopijuoti į...
|
||||||
move-to = Perkeltiį į...
|
move-to = Perkeltiį į...
|
||||||
copy-path = Kopijuoti kelią
|
copy-path = Kopijuoti kelią
|
||||||
theme = Stilius
|
theme = Stilius
|
||||||
|
context-action = Konteksto veiksmas
|
||||||
|
context-action-confirm-title = Paleisti „{ $name }“?
|
||||||
|
run = Paleisti
|
||||||
|
rename-confirm = Pervadinti
|
||||||
|
calculate = Skaičiuoti
|
||||||
|
error = Klaida
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ removed-from-recents =
|
||||||
} uit { recents } verwijderd
|
} uit { recents } verwijderd
|
||||||
remove-from-recents = Uit recente verwijderen
|
remove-from-recents = Uit recente verwijderen
|
||||||
type-to-search-select = Dit selecteert het eerst overeenkomende bestand of map
|
type-to-search-select = Dit selecteert het eerst overeenkomende bestand of map
|
||||||
comment = Bestandsbeheerder voor COSMIC desktop
|
comment = Bestandsbeheerder voor COSMIC
|
||||||
copy-to-title = Kopieerbestemming aanwijzen
|
copy-to-title = Kopieerbestemming aanwijzen
|
||||||
copy-to-button-label = Kopiëren
|
copy-to-button-label = Kopiëren
|
||||||
move-to-button-label = Verplaatsen
|
move-to-button-label = Verplaatsen
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
appearance = Aparéncia
|
||||||
|
theme = Tèma
|
||||||
|
match-desktop = Assortir al burèu
|
||||||
|
dark = Escur
|
||||||
|
light = Clar
|
||||||
|
file = Fichièr
|
||||||
|
details = Detalhs
|
||||||
|
name = Nom
|
||||||
|
cancel = Anullar
|
||||||
|
repository = Depaus
|
||||||
|
settings = Configuracion
|
||||||
|
menu-settings = Configuracion...
|
||||||
|
quit = Quitar
|
||||||
|
cosmic-files = Fichièrs de COSMIC
|
||||||
|
comment = Gestionari de fichièrs pel burèu COSMIC
|
||||||
|
save-file = Enregistrar lo fichièr
|
||||||
|
open-with-title = Cossí volètz dobrir « { $name } » ?
|
||||||
|
other-apps = Autras aplicacions
|
||||||
|
context-action-confirm-title = Executar « { $name } » ?
|
||||||
|
run = Executar
|
||||||
|
delete = Suprimir
|
||||||
|
replace = Remplaçar
|
||||||
|
owner = Propietari
|
||||||
|
group = Grop
|
||||||
|
write-execute = Escritura e execucion
|
||||||
|
read-only = Lectura sola
|
||||||
|
read-execute = Lectura e execucion
|
||||||
|
read-write = Lectura e execucion
|
||||||
|
read-write-execute = Lectura, escritura e execucion
|
||||||
|
remove = Suprimir
|
||||||
|
connecting = Connexion...
|
||||||
|
domain = Domeni
|
||||||
|
password = Senhal
|
||||||
|
|
@ -146,7 +146,7 @@ new-tab = ਨਵੀਂ ਟੈਬ
|
||||||
new-window = ਨਵੀਂ ਵਿੰਡੋ
|
new-window = ਨਵੀਂ ਵਿੰਡੋ
|
||||||
rename = ਨਾਂ ਨੂੰ ਬਦਲੋ...
|
rename = ਨਾਂ ਨੂੰ ਬਦਲੋ...
|
||||||
close-tab = ਟੈਬ ਨੂੰ ਬੰਦ ਕਰੋ
|
close-tab = ਟੈਬ ਨੂੰ ਬੰਦ ਕਰੋ
|
||||||
quit = ਬਾਹਰ
|
quit = ਸਮਾਪਤ
|
||||||
edit = ਸੋਧੋ
|
edit = ਸੋਧੋ
|
||||||
cut = ਕੱਟੋ
|
cut = ਕੱਟੋ
|
||||||
copy = ਕਾਪੀ ਕਰੋ
|
copy = ਕਾਪੀ ਕਰੋ
|
||||||
|
|
@ -188,9 +188,9 @@ item-accessed = ਪਹੁੰਚ: { $accessed }
|
||||||
calculating = ਗਿਣਤੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...
|
calculating = ਗਿਣਤੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...
|
||||||
single-click = ਇੱਕ ਵਾਰ ਕਲਿੱਕ ਕਰਕੇ ਖੋਲ੍ਹੋ
|
single-click = ਇੱਕ ਵਾਰ ਕਲਿੱਕ ਕਰਕੇ ਖੋਲ੍ਹੋ
|
||||||
show-recents = ਬਾਹੀ ਵਿੱਚ ਸੱਜਰੇ ਫੋਲਡਰ
|
show-recents = ਬਾਹੀ ਵਿੱਚ ਸੱਜਰੇ ਫੋਲਡਰ
|
||||||
match-desktop = ਡੈਸਕਟਾਪ ਨਾਲ ਮਿਲਦਾ
|
match-desktop = ਡੈਸਕਟਾਪ ਨਾਲ ਮਿਲਾਓ
|
||||||
dark = ਗੂੜ੍ਹਾ
|
dark = ਗੂੜ੍ਹਾ
|
||||||
light = ਹਲਕਾ
|
light = ਫਿੱਕਾ
|
||||||
type-to-search = ਖੋਜਣ ਲਈ ਲਿਖੋ
|
type-to-search = ਖੋਜਣ ਲਈ ਲਿਖੋ
|
||||||
type-to-search-recursive = ਮੌਜੂਦਾ ਫੋਲਡਰ ਅਤੇ ਸਭ ਅਧੀਨ-ਫੋਲਡਰਾਂ ਵਿੱਚ ਖੋਜੋ
|
type-to-search-recursive = ਮੌਜੂਦਾ ਫੋਲਡਰ ਅਤੇ ਸਭ ਅਧੀਨ-ਫੋਲਡਰਾਂ ਵਿੱਚ ਖੋਜੋ
|
||||||
add-to-sidebar = ਬਾਹੀ ਵਿੱਚ ਜੋੜੋ
|
add-to-sidebar = ਬਾਹੀ ਵਿੱਚ ਜੋੜੋ
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
cosmic-files = Pliki COSMIC
|
cosmic-files = Pliki COSMIC
|
||||||
comment = Menedżer plików pulpitu COSMIC
|
comment = Menedżer plików dla środowiska COSMIC
|
||||||
keywords = Katalogi;Pliki;Menedżer;
|
keywords = Katalogi;Pliki;Menedżer;
|
||||||
empty-folder = Pusty katalog
|
empty-folder = Pusty katalog
|
||||||
empty-folder-hidden = Pusty katalog (z ukrytymi plikami)
|
empty-folder-hidden = Pusty katalog (z ukrytymi plikami)
|
||||||
|
|
@ -27,7 +27,7 @@ modified = Zmodyfikowano
|
||||||
trashed-on = Wyrzucono do kosza
|
trashed-on = Wyrzucono do kosza
|
||||||
size = Rozmiar
|
size = Rozmiar
|
||||||
# Progress footer
|
# Progress footer
|
||||||
details = Detale
|
details = Szczegóły
|
||||||
dismiss = Odrzuć wiadomość
|
dismiss = Odrzuć wiadomość
|
||||||
operations-running =
|
operations-running =
|
||||||
{ $running } bieżące { $running ->
|
{ $running } bieżące { $running ->
|
||||||
|
|
@ -390,7 +390,7 @@ new-window = Nowe okno
|
||||||
reload-folder = Odśwież katalog
|
reload-folder = Odśwież katalog
|
||||||
rename = Zmień nazwę…
|
rename = Zmień nazwę…
|
||||||
close-tab = Zamknij kartę
|
close-tab = Zamknij kartę
|
||||||
quit = Zamknij
|
quit = Zakończ
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -447,3 +447,9 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Uruchom
|
run = Uruchom
|
||||||
rename-confirm = Zmień nazwę
|
rename-confirm = Zmień nazwę
|
||||||
|
checksum = { $kind } suma kontrolna
|
||||||
|
calculate = Oblicz
|
||||||
|
error = Błąd
|
||||||
|
sidebar-label = Etykieta panelu bocznego
|
||||||
|
search-application = Wyszukaj po nazwie aplikacji
|
||||||
|
change-sidebar-label = Zmień etykietę panelu bocznego
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,10 @@ permanently-delete-warning = Deseja realmente excluir permanentemente { $target
|
||||||
rename-file = Renomear arquivo
|
rename-file = Renomear arquivo
|
||||||
rename-folder = Renomear pasta
|
rename-folder = Renomear pasta
|
||||||
|
|
||||||
|
## Change Sidebar Label Dialog
|
||||||
|
|
||||||
|
sidebar-label = Legenda da barra lateral
|
||||||
|
|
||||||
## Replace Dialog
|
## Replace Dialog
|
||||||
|
|
||||||
replace = Substituir
|
replace = Substituir
|
||||||
|
|
@ -350,7 +354,7 @@ light = Estilo claro
|
||||||
|
|
||||||
### Type to Search
|
### Type to Search
|
||||||
|
|
||||||
type-to-search = Digite para pesquisar
|
type-to-search = Digitar para pesquisar
|
||||||
type-to-search-recursive = Pesquisa na pasta atual e em todas as subpastas
|
type-to-search-recursive = Pesquisa na pasta atual e em todas as subpastas
|
||||||
type-to-search-enter-path = Insere o caminho do diretório ou arquivo
|
type-to-search-enter-path = Insere o caminho do diretório ou arquivo
|
||||||
# Context menu
|
# Context menu
|
||||||
|
|
@ -365,6 +369,7 @@ open-in-terminal = Abrir no terminal
|
||||||
move-to-trash = Mover para a lixeira
|
move-to-trash = Mover para a lixeira
|
||||||
restore-from-trash = Restaurar da lixeira
|
restore-from-trash = Restaurar da lixeira
|
||||||
remove-from-sidebar = Remover da barra lateral
|
remove-from-sidebar = Remover da barra lateral
|
||||||
|
change-sidebar-label = Alterar legenda da barra lateral
|
||||||
sort-by-name = Ordenar por nome
|
sort-by-name = Ordenar por nome
|
||||||
sort-by-modified = Ordenar por data de modificação
|
sort-by-modified = Ordenar por data de modificação
|
||||||
sort-by-size = Ordenar por tamanho
|
sort-by-size = Ordenar por tamanho
|
||||||
|
|
@ -388,7 +393,7 @@ new-window = Nova janela
|
||||||
reload-folder = Recarregar pasta
|
reload-folder = Recarregar pasta
|
||||||
rename = Renomear...
|
rename = Renomear...
|
||||||
close-tab = Fechar aba
|
close-tab = Fechar aba
|
||||||
quit = Sair
|
quit = Encerrar
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -446,3 +451,7 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Executar
|
run = Executar
|
||||||
rename-confirm = Renomear
|
rename-confirm = Renomear
|
||||||
|
checksum = Soma de verificação { $kind }
|
||||||
|
calculate = Calcular
|
||||||
|
error = Erro
|
||||||
|
search-application = Pesquisar por nome de aplicativo
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,7 @@ unknown-folder = неизвестная папка
|
||||||
|
|
||||||
menu-open-with = Открыть с помощью…
|
menu-open-with = Открыть с помощью…
|
||||||
default-app = { $name } (по умолчанию)
|
default-app = { $name } (по умолчанию)
|
||||||
|
search-application = Поиск по названию приложения
|
||||||
|
|
||||||
## Show details
|
## Show details
|
||||||
|
|
||||||
|
|
@ -188,7 +189,7 @@ settings = Параметры
|
||||||
|
|
||||||
### Appearance
|
### Appearance
|
||||||
|
|
||||||
appearance = Оформление
|
appearance = Внешний вид
|
||||||
theme = Тема
|
theme = Тема
|
||||||
match-desktop = Как в системе
|
match-desktop = Как в системе
|
||||||
dark = Тёмная
|
dark = Тёмная
|
||||||
|
|
@ -218,7 +219,7 @@ new-tab = Новая вкладка
|
||||||
new-window = Новое окно
|
new-window = Новое окно
|
||||||
rename = Переименовать…
|
rename = Переименовать…
|
||||||
close-tab = Закрыть вкладку
|
close-tab = Закрыть вкладку
|
||||||
quit = Выйти
|
quit = Завершить
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -271,8 +272,8 @@ extract-to = Распаковать в…
|
||||||
extract-to-title = Распаковать в папку
|
extract-to-title = Распаковать в папку
|
||||||
mount-error = Не удалось получить доступ к диску
|
mount-error = Не удалось получить доступ к диску
|
||||||
create = Создать
|
create = Создать
|
||||||
open-with-title = Как вы хотите открыть «{ $name }»?
|
open-with-title = Как хотите открыть «{ $name }»?
|
||||||
browse-store = Искать в { $store }
|
browse-store = Перейти в { $store }
|
||||||
other-apps = Другие приложения
|
other-apps = Другие приложения
|
||||||
related-apps = Связанные приложения
|
related-apps = Связанные приложения
|
||||||
selected-items = { $items } выделенных элем.
|
selected-items = { $items } выделенных элем.
|
||||||
|
|
@ -320,7 +321,7 @@ type-to-search-enter-path = Ввод пути к каталогу или фай
|
||||||
delete-permanently = Удалить навсегда
|
delete-permanently = Удалить навсегда
|
||||||
eject = Извлечь
|
eject = Извлечь
|
||||||
remove-from-recents = Убрать из недавних
|
remove-from-recents = Убрать из недавних
|
||||||
change-wallpaper = Изменить обои…
|
change-wallpaper = Изменить фон...
|
||||||
desktop-appearance = Параметры оформления…
|
desktop-appearance = Параметры оформления…
|
||||||
display-settings = Параметры экрана…
|
display-settings = Параметры экрана…
|
||||||
reload-folder = Обновить папку
|
reload-folder = Обновить папку
|
||||||
|
|
@ -382,11 +383,16 @@ clear-recents-history = Очистить историю недавних
|
||||||
copy-path = Копировать путь
|
copy-path = Копировать путь
|
||||||
mixed = Смешанные
|
mixed = Смешанные
|
||||||
context-action = Контекстная команда
|
context-action = Контекстная команда
|
||||||
context-action-confirm-title = Выполнить «{ $name }»?
|
context-action-confirm-title = Запустить «{ $name }»?
|
||||||
context-action-confirm-warning =
|
context-action-confirm-warning =
|
||||||
Команда затронет { $items } { $items ->
|
Команда затронет { $items } { $items ->
|
||||||
[one] элемент
|
[one] элемент
|
||||||
*[other] элем.
|
*[other] элем.
|
||||||
}.
|
}.
|
||||||
run = Выполнить
|
run = Запустить
|
||||||
rename-confirm = Переименовать
|
rename-confirm = Переименовать
|
||||||
|
checksum = Хеш-сумма { $kind }
|
||||||
|
calculate = Вычислить
|
||||||
|
error = Ошибка
|
||||||
|
sidebar-label = Подпись в боковой панели
|
||||||
|
change-sidebar-label = Изменить подпись
|
||||||
|
|
|
||||||
3
i18n/sat/cosmic_files.ftl
Normal file
3
i18n/sat/cosmic_files.ftl
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cancel = ᱵᱟᱹᱛᱤᱞ
|
||||||
|
name = ᱧᱩᱛᱩᱢ
|
||||||
|
save = ᱥᱟᱧᱪᱟᱣ
|
||||||
|
|
@ -319,7 +319,7 @@ list-view = Listvy
|
||||||
show-hidden-files = Visa dolda filer
|
show-hidden-files = Visa dolda filer
|
||||||
list-directories-first = Lista mappar först
|
list-directories-first = Lista mappar först
|
||||||
gallery-preview = Galleri förhandsvisning
|
gallery-preview = Galleri förhandsvisning
|
||||||
menu-settings = Inställningar…
|
menu-settings = Inställningar...
|
||||||
menu-about = Om COSMIC Filer...
|
menu-about = Om COSMIC Filer...
|
||||||
|
|
||||||
## Sortera
|
## Sortera
|
||||||
|
|
@ -419,3 +419,9 @@ context-action-confirm-warning =
|
||||||
}.
|
}.
|
||||||
run = Kör
|
run = Kör
|
||||||
rename-confirm = Byt namn
|
rename-confirm = Byt namn
|
||||||
|
checksum = { $kind }-kontrollsumma
|
||||||
|
calculate = Beräkna
|
||||||
|
error = Fel
|
||||||
|
sidebar-label = Sidofältsetikett
|
||||||
|
search-application = Sök på programnamn
|
||||||
|
change-sidebar-label = Ändra sidofältsetikett
|
||||||
|
|
|
||||||
|
|
@ -202,17 +202,9 @@ moved =
|
||||||
*[other] ไฟล์
|
*[other] ไฟล์
|
||||||
} จาก "{ $from }" สู่ "{ $to }"
|
} จาก "{ $from }" สู่ "{ $to }"
|
||||||
renaming = กำลังเปลี่ยนชื่อจาก "{ $from }" เป็น "{ $to }"
|
renaming = กำลังเปลี่ยนชื่อจาก "{ $from }" เป็น "{ $to }"
|
||||||
renamed = Renamed "{ $from }" to "{ $to }"
|
renamed = เปลี่ยนชื่อจาก "{ $from }" เป็น "{ $to }" แล้ว
|
||||||
restoring =
|
restoring = กำลังกู้คืน { $items } รายการจาก { trash } ({ $progress })...
|
||||||
Restoring { $items } { $items ->
|
restored = กู้คืน { $items } รายการจาก { trash } แล้ว
|
||||||
[one] item
|
|
||||||
*[other] items
|
|
||||||
} from { trash } ({ $progress })...
|
|
||||||
restored =
|
|
||||||
Restored { $items } { $items ->
|
|
||||||
[one] item
|
|
||||||
*[other] items
|
|
||||||
} from { trash }
|
|
||||||
unknown-folder = แฟ้มที่ไม่รู้จัก
|
unknown-folder = แฟ้มที่ไม่รู้จัก
|
||||||
|
|
||||||
## Open with
|
## Open with
|
||||||
|
|
@ -240,8 +232,8 @@ settings = การตั้งค่า
|
||||||
appearance = ลักษณะ
|
appearance = ลักษณะ
|
||||||
theme = ธีม
|
theme = ธีม
|
||||||
match-desktop = ใช้ตามธีมหน้าจอหลัก
|
match-desktop = ใช้ตามธีมหน้าจอหลัก
|
||||||
dark = ธีมมืด
|
dark = มืด
|
||||||
light = ธีมสว่าง
|
light = สว่าง
|
||||||
# Context menu
|
# Context menu
|
||||||
add-to-sidebar = เพิ่มเข้าแถบด้านข้าง
|
add-to-sidebar = เพิ่มเข้าแถบด้านข้าง
|
||||||
compress = บีบอัด
|
compress = บีบอัด
|
||||||
|
|
@ -306,3 +298,4 @@ sort-newest-first = ไฟล์ใหม่ก่อน
|
||||||
sort-oldest-first = ไฟล์เก่าก่อน
|
sort-oldest-first = ไฟล์เก่าก่อน
|
||||||
sort-smallest-to-largest = ขนาดเล็กก่อน
|
sort-smallest-to-largest = ขนาดเล็กก่อน
|
||||||
sort-largest-to-smallest = ขนาดใหญ่ก่อน
|
sort-largest-to-smallest = ขนาดใหญ่ก่อน
|
||||||
|
remove = ลบ
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ new-tab = Нова вкладка
|
||||||
new-window = Нове вікно
|
new-window = Нове вікно
|
||||||
rename = Перейменувати...
|
rename = Перейменувати...
|
||||||
close-tab = Закрити вкладку
|
close-tab = Закрити вкладку
|
||||||
quit = Вийти
|
quit = Завершити
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ menu-settings = Налаштування...
|
||||||
menu-about = Про Файли COSMIC...
|
menu-about = Про Файли COSMIC...
|
||||||
repository = Сховище
|
repository = Сховище
|
||||||
support = Підтримка
|
support = Підтримка
|
||||||
details = Деталі
|
details = Подробиці
|
||||||
dismiss = Закрити повідомлення
|
dismiss = Закрити повідомлення
|
||||||
remove = Вилучити
|
remove = Вилучити
|
||||||
cancelled = Скасовані
|
cancelled = Скасовані
|
||||||
|
|
@ -389,3 +389,9 @@ context-action-confirm-warning =
|
||||||
context-action = Контекстна дія
|
context-action = Контекстна дія
|
||||||
rename-confirm = Перейменувати
|
rename-confirm = Перейменувати
|
||||||
mixed = Змішано
|
mixed = Змішано
|
||||||
|
checksum = контрольна сума { $kind }
|
||||||
|
calculate = Вирахувати
|
||||||
|
error = Помилка
|
||||||
|
sidebar-label = Назва бічної панелі
|
||||||
|
search-application = Пошук за назвою застосунку
|
||||||
|
change-sidebar-label = Змінити назву бічної панелі
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ modified = 修改时间
|
||||||
trashed-on = 删除时间
|
trashed-on = 删除时间
|
||||||
size = 大小
|
size = 大小
|
||||||
# Progress footer
|
# Progress footer
|
||||||
details = 详细信息
|
details = 详情
|
||||||
dismiss = 清除消息
|
dismiss = 清除消息
|
||||||
operations-running =
|
operations-running =
|
||||||
正在进行 { $running } { $running ->
|
正在进行 { $running } { $running ->
|
||||||
|
|
@ -169,8 +169,8 @@ read-write-execute = 读取、写入和执行
|
||||||
|
|
||||||
favorite-path-error = 打开目录时出错
|
favorite-path-error = 打开目录时出错
|
||||||
favorite-path-error-description =
|
favorite-path-error-description =
|
||||||
无法打开 "{ $path }" 。
|
无法打开“{ $path }” 。
|
||||||
"{ $path }" 可能不存在或您没有权限打开它。
|
“{ $path }”可能不存在或您没有权限打开它。
|
||||||
|
|
||||||
您想要从侧边栏中移除它吗?
|
您想要从侧边栏中移除它吗?
|
||||||
remove = 移除
|
remove = 移除
|
||||||
|
|
@ -267,10 +267,10 @@ extracted =
|
||||||
[one] 项目
|
[one] 项目
|
||||||
*[other] 项目
|
*[other] 项目
|
||||||
}到“{ $to }”
|
}到“{ $to }”
|
||||||
setting-executable-and-launching = 设置 "{ $name }" 为可执行文件并启动
|
setting-executable-and-launching = 设置 “{ $name }” 为可执行文件并启动
|
||||||
set-executable-and-launched = 已设 "{ $name }" 为可执行文件并且启动
|
set-executable-and-launched = 已设 “{ $name }” 为可执行文件并且启动
|
||||||
setting-permissions = 正在设置 "{ $name }" 的权限为 { $mode }
|
setting-permissions = 正在设置 “{ $name }” 的权限为 { $mode }
|
||||||
set-permissions = 设置 "{ $name }" 的权限为 { $mode }
|
set-permissions = 设置 “{ $name }” 的权限为 { $mode }
|
||||||
moving =
|
moving =
|
||||||
正在从“{ $from }”移动 { $items } { $items ->
|
正在从“{ $from }”移动 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 项目
|
||||||
|
|
@ -302,7 +302,7 @@ removed-from-recents =
|
||||||
*[other] 项目
|
*[other] 项目
|
||||||
}
|
}
|
||||||
renaming = 正在将“{ $from }”重命名为“{ $to }”
|
renaming = 正在将“{ $from }”重命名为“{ $to }”
|
||||||
renamed = 已重命名"{ $from }"为"{ $to }"
|
renamed = 已重命名 “{ $from }” 为 “{ $to }”
|
||||||
restoring =
|
restoring =
|
||||||
正在从{ trash }中还原 { $items } { $items ->
|
正在从{ trash }中还原 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 项目
|
||||||
|
|
@ -446,3 +446,9 @@ context-action-confirm-warning =
|
||||||
} 上运行。
|
} 上运行。
|
||||||
context-action = 环境行动
|
context-action = 环境行动
|
||||||
rename-confirm = 重命名
|
rename-confirm = 重命名
|
||||||
|
calculate = 计算
|
||||||
|
error = 错误
|
||||||
|
checksum = { $kind } 校验和
|
||||||
|
sidebar-label = 侧边栏标签
|
||||||
|
search-application = 使用应用名称搜索
|
||||||
|
change-sidebar-label = 更改侧边栏标签
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ undo = 復原
|
||||||
today = 今天
|
today = 今天
|
||||||
# List view
|
# List view
|
||||||
name = 名稱
|
name = 名稱
|
||||||
modified = 修改日期
|
modified = 修改時間
|
||||||
size = 大小
|
size = 大小
|
||||||
|
|
||||||
# Dialogs
|
# Dialogs
|
||||||
|
|
@ -42,7 +42,7 @@ name-no-slashes = 名稱不能包含斜線
|
||||||
## Open/Save Dialog
|
## Open/Save Dialog
|
||||||
|
|
||||||
cancel = 取消
|
cancel = 取消
|
||||||
create = 建立
|
create = 創作
|
||||||
open = 開啟
|
open = 開啟
|
||||||
open-file = 開啟檔案
|
open-file = 開啟檔案
|
||||||
open-folder = 開啟資料夾
|
open-folder = 開啟資料夾
|
||||||
|
|
@ -161,8 +161,8 @@ moved =
|
||||||
[one] 項目
|
[one] 項目
|
||||||
*[other] 項目
|
*[other] 項目
|
||||||
} 從「{ $from }」至「{ $to }」
|
} 從「{ $from }」至「{ $to }」
|
||||||
renaming = 正在重新命名「{ $from }」至「{ $to }」
|
renaming = 正在將「{ $from }」重新命名為「{ $to }」
|
||||||
renamed = 已經重新命名「{ $from }」至「{ $to }」
|
renamed = 已將「{ $from }」重新命名為「{ $to }」
|
||||||
restoring =
|
restoring =
|
||||||
正在還原 { $items } 項目 { $items ->
|
正在還原 { $items } 項目 { $items ->
|
||||||
[one] 項目
|
[one] 項目
|
||||||
|
|
@ -182,7 +182,7 @@ default-app = { $name } (預設)
|
||||||
|
|
||||||
## Show details
|
## Show details
|
||||||
|
|
||||||
show-details = 顯示詳細資料
|
show-details = 顯示詳細資訊
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
|
|
@ -196,13 +196,13 @@ match-desktop = 符合桌面
|
||||||
dark = 深色
|
dark = 深色
|
||||||
light = 淺色
|
light = 淺色
|
||||||
# Context menu
|
# Context menu
|
||||||
add-to-sidebar = 添加至側邊欄
|
add-to-sidebar = 加入側邊欄
|
||||||
compress = 壓縮…
|
compress = 壓縮…
|
||||||
extract-here = 解壓縮
|
extract-here = 解壓縮
|
||||||
new-file = 新建檔案...
|
new-file = 新增檔案...
|
||||||
new-folder = 新建資料夾...
|
new-folder = 新增資料夾...
|
||||||
open-in-terminal = 在終端機中開啟
|
open-in-terminal = 在終端機中開啟
|
||||||
move-to-trash = 移動至垃圾桶
|
move-to-trash = 丟入垃圾桶
|
||||||
restore-from-trash = 從垃圾桶還原
|
restore-from-trash = 從垃圾桶還原
|
||||||
remove-from-sidebar = 從側邊欄移除
|
remove-from-sidebar = 從側邊欄移除
|
||||||
sort-by-name = 依名稱排序
|
sort-by-name = 依名稱排序
|
||||||
|
|
@ -215,11 +215,11 @@ sort-by-size = 依大小排序
|
||||||
## File
|
## File
|
||||||
|
|
||||||
file = 檔案
|
file = 檔案
|
||||||
new-tab = 新建分頁
|
new-tab = 新增分頁
|
||||||
new-window = 新建視窗
|
new-window = 新增視窗
|
||||||
rename = 重新命名...
|
rename = 重新命名...
|
||||||
close-tab = 關閉分頁
|
close-tab = 關閉分頁
|
||||||
quit = 退出
|
quit = 結束
|
||||||
|
|
||||||
## Edit
|
## Edit
|
||||||
|
|
||||||
|
|
@ -258,18 +258,18 @@ deleted =
|
||||||
}從 { trash }
|
}從 { trash }
|
||||||
permanently-deleting =
|
permanently-deleting =
|
||||||
正在永久刪除 { $items } { $items ->
|
正在永久刪除 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 項目
|
||||||
*[other] 项目
|
*[other] 項目
|
||||||
}
|
}
|
||||||
permanently-deleted =
|
permanently-deleted =
|
||||||
已經永久刪除 { $items } { $items ->
|
已經永久刪除 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 項目
|
||||||
*[other] 项目
|
*[other] 項目
|
||||||
}
|
}
|
||||||
removing-from-recents =
|
removing-from-recents =
|
||||||
正在從 { recents } 中移除 { $items } { $items ->
|
正在從 { recents } 中移除 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 項目
|
||||||
*[other] 项目
|
*[other] 項目
|
||||||
}
|
}
|
||||||
deleting =
|
deleting =
|
||||||
正在刪除 { $items } { $items ->
|
正在刪除 { $items } { $items ->
|
||||||
|
|
@ -278,21 +278,21 @@ deleting =
|
||||||
}從 { trash }({ $progress })…
|
}從 { trash }({ $progress })…
|
||||||
removed-from-recents =
|
removed-from-recents =
|
||||||
已經從 { recents } 中移除 { $items } { $items ->
|
已經從 { recents } 中移除 { $items } { $items ->
|
||||||
[one] 项目
|
[one] 項目
|
||||||
*[other] 项目
|
*[other] 項目
|
||||||
}
|
}
|
||||||
repository = 軟體庫源
|
repository = 軟體庫
|
||||||
desktop-view-options = 桌面檢視選項...
|
desktop-view-options = 桌面檢視選項...
|
||||||
show-on-desktop = 顯示在桌面
|
show-on-desktop = 顯示在桌面
|
||||||
desktop-folder-content = 桌面資料夾內容
|
desktop-folder-content = 桌面資料夾內容
|
||||||
mounted-drives = 已經掛載的磁碟機
|
mounted-drives = 已經掛載的磁碟機
|
||||||
trash-folder-icon = 垃圾桶圖示
|
trash-folder-icon = 垃圾桶圖示
|
||||||
trashed-on = 遺棄時間
|
trashed-on = 丟入時間
|
||||||
icon-size-and-spacing = 圖示大小與間距
|
icon-size-and-spacing = 圖示大小與間距
|
||||||
icon-size = 圖示大小
|
icon-size = 圖示大小
|
||||||
grid-spacing = 網格間距
|
grid-spacing = 網格間距
|
||||||
details = 詳情
|
details = 詳細資訊
|
||||||
dismiss = 撤停訊息
|
dismiss = 關閉訊息
|
||||||
delete = 刪除
|
delete = 刪除
|
||||||
remove = 移除
|
remove = 移除
|
||||||
support = 支援
|
support = 支援
|
||||||
|
|
@ -393,3 +393,9 @@ context-action-confirm-warning =
|
||||||
} 上執行。
|
} 上執行。
|
||||||
run = 執行
|
run = 執行
|
||||||
rename-confirm = 重新命名
|
rename-confirm = 重新命名
|
||||||
|
checksum = { $kind } 核對和
|
||||||
|
calculate = 計算
|
||||||
|
error = 錯誤
|
||||||
|
sidebar-label = 側邊欄標籤
|
||||||
|
search-application = 依應用程式名稱搜尋
|
||||||
|
change-sidebar-label = 變更側邊欄標籤
|
||||||
|
|
|
||||||
17
justfile
17
justfile
|
|
@ -12,6 +12,10 @@ cargo-target-dir := env('CARGO_TARGET_DIR', 'target')
|
||||||
bin-src := cargo-target-dir / 'release' / name
|
bin-src := cargo-target-dir / 'release' / name
|
||||||
bin-dst := base-dir / 'bin' / name
|
bin-dst := base-dir / 'bin' / name
|
||||||
|
|
||||||
|
thumbnailer-bin-name := name + '-thumbnailer'
|
||||||
|
thumbnailer-bin-src := cargo-target-dir / 'release' / thumbnailer-bin-name
|
||||||
|
thumbnailer-bin-dst := base-dir / 'bin' / thumbnailer-bin-name
|
||||||
|
|
||||||
applet-name := name + '-applet'
|
applet-name := name + '-applet'
|
||||||
applet-src := cargo-target-dir / 'release' / applet-name
|
applet-src := cargo-target-dir / 'release' / applet-name
|
||||||
applet-dst := base-dir / 'bin' / applet-name
|
applet-dst := base-dir / 'bin' / applet-name
|
||||||
|
|
@ -24,6 +28,10 @@ metainfo := APPID + '.metainfo.xml'
|
||||||
metainfo-src := 'target/xdgen' / metainfo
|
metainfo-src := 'target/xdgen' / metainfo
|
||||||
metainfo-dst := clean(rootdir / prefix) / 'share' / 'metainfo' / metainfo
|
metainfo-dst := clean(rootdir / prefix) / 'share' / 'metainfo' / metainfo
|
||||||
|
|
||||||
|
thumbnailer := APPID + '.thumbnailer'
|
||||||
|
thumbnailer-src := 'res' / thumbnailer
|
||||||
|
thumbnailer-dst := clean(rootdir / prefix) / 'share' / 'thumbnailers' / thumbnailer
|
||||||
|
|
||||||
icons-src := 'res' / 'icons' / 'hicolor'
|
icons-src := 'res' / 'icons' / 'hicolor'
|
||||||
icons-dst := clean(rootdir / prefix) / 'share' / 'icons' / 'hicolor'
|
icons-dst := clean(rootdir / prefix) / 'share' / 'icons' / 'hicolor'
|
||||||
|
|
||||||
|
|
@ -45,14 +53,11 @@ clean-dist: clean clean-vendor
|
||||||
build-debug *args:
|
build-debug *args:
|
||||||
cargo build {{args}}
|
cargo build {{args}}
|
||||||
cargo build --package {{applet-name}} {{args}}
|
cargo build --package {{applet-name}} {{args}}
|
||||||
|
cargo build --package {{thumbnailer-bin-name}} {{args}}
|
||||||
|
|
||||||
# Compiles with release profile
|
# Compiles with release profile
|
||||||
build-release *args: (build-debug '--release' args)
|
build-release *args: (build-debug '--release' args)
|
||||||
|
|
||||||
# Compiles applet with release profile
|
|
||||||
build-release-applet *args:
|
|
||||||
cargo build --package {{applet-name}} --release {{args}}
|
|
||||||
|
|
||||||
# Compiles release profile with vendored dependencies
|
# Compiles release profile with vendored dependencies
|
||||||
build-vendored *args: vendor-extract (build-release '--frozen --offline' args)
|
build-vendored *args: vendor-extract (build-release '--frozen --offline' args)
|
||||||
|
|
||||||
|
|
@ -92,9 +97,11 @@ heaptrack *args:
|
||||||
# Installs files
|
# Installs files
|
||||||
install:
|
install:
|
||||||
install -Dm0755 {{bin-src}} {{bin-dst}}
|
install -Dm0755 {{bin-src}} {{bin-dst}}
|
||||||
|
install -Dm0755 {{thumbnailer-bin-src}} {{thumbnailer-bin-dst}}
|
||||||
install -Dm0755 {{applet-src}} {{applet-dst}}
|
install -Dm0755 {{applet-src}} {{applet-dst}}
|
||||||
install -Dm0644 {{desktop-src}} {{desktop-dst}}
|
install -Dm0644 {{desktop-src}} {{desktop-dst}}
|
||||||
install -Dm0644 {{metainfo-src}} {{metainfo-dst}}
|
install -Dm0644 {{metainfo-src}} {{metainfo-dst}}
|
||||||
|
install -Dm0644 {{thumbnailer-src}} {{thumbnailer-dst}}
|
||||||
for size in `ls {{icons-src}}`; do \
|
for size in `ls {{icons-src}}`; do \
|
||||||
install -Dm0644 "{{icons-src}}/$size/apps/{{APPID}}.svg" "{{icons-dst}}/$size/apps/{{APPID}}.svg"; \
|
install -Dm0644 "{{icons-src}}/$size/apps/{{APPID}}.svg" "{{icons-dst}}/$size/apps/{{APPID}}.svg"; \
|
||||||
done
|
done
|
||||||
|
|
@ -105,7 +112,7 @@ install-applet:
|
||||||
|
|
||||||
# Uninstalls installed files
|
# Uninstalls installed files
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f {{bin-dst}} {{applet-dst}}
|
rm -f {{bin-dst}} {{thumbnailer-bin-dst}} {{applet-dst}} {{thumbnailer-dst}}
|
||||||
|
|
||||||
# Vendor dependencies locally
|
# Vendor dependencies locally
|
||||||
vendor:
|
vendor:
|
||||||
|
|
|
||||||
4
res/com.system76.CosmicFiles.thumbnailer
Normal file
4
res/com.system76.CosmicFiles.thumbnailer
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[Thumbnailer Entry]
|
||||||
|
TryExec=cosmic-files-thumbnailer
|
||||||
|
Exec=cosmic-files-thumbnailer %o --size %s %i
|
||||||
|
MimeType=application/vnd.microsoft.portable-executable;application/x-msdownload;
|
||||||
453
src/app.rs
453
src/app.rs
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use cosmic::app::{self, Core, Task, context_drawer};
|
use cosmic::app::{self, Core, Task, context_drawer};
|
||||||
|
use cosmic::core::Auto;
|
||||||
use cosmic::cosmic_config::{self, ConfigSet};
|
use cosmic::cosmic_config::{self, ConfigSet};
|
||||||
use cosmic::iced::clipboard::dnd::DndAction;
|
use cosmic::iced::clipboard::dnd::DndAction;
|
||||||
use cosmic::iced::core::SmolStr;
|
use cosmic::iced::core::SmolStr;
|
||||||
|
|
@ -16,18 +17,16 @@ use cosmic::iced::widget::button::focus;
|
||||||
use cosmic::iced::widget::scrollable;
|
use cosmic::iced::widget::scrollable;
|
||||||
use cosmic::iced::widget::scrollable::AbsoluteOffset;
|
use cosmic::iced::widget::scrollable::AbsoluteOffset;
|
||||||
use cosmic::iced::window::{self, Event as WindowEvent, Id as WindowId};
|
use cosmic::iced::window::{self, Event as WindowEvent, Id as WindowId};
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{self, Alignment, Event, Length, Size, Subscription, event, mouse, stream};
|
||||||
self, Alignment, Event, Length, Rectangle, Size, Subscription, event, mouse, stream,
|
|
||||||
};
|
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
Limits, Point,
|
Limits, Point, Rectangle,
|
||||||
event::wayland::{Event as WaylandEvent, OutputEvent, OverlapNotifyEvent},
|
event::wayland::{Event as WaylandEvent, OutputEvent, OverlapNotifyEvent},
|
||||||
platform_specific::runtime::wayland::layer_surface::{
|
platform_specific::runtime::wayland::layer_surface::{
|
||||||
IcedMargin, IcedOutput, SctkLayerSurfaceSettings,
|
IcedMargin, IcedOutput, SctkLayerSurfaceSettings,
|
||||||
},
|
},
|
||||||
platform_specific::shell::wayland::commands::layer_surface::{
|
platform_specific::shell::wayland::commands::layer_surface::{
|
||||||
Anchor, KeyboardInteractivity, Layer, destroy_layer_surface, get_layer_surface,
|
Anchor, KeyboardInteractivity, Layer, destroy_layer_surface,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cosmic::widget::about::About;
|
use cosmic::widget::about::About;
|
||||||
|
|
@ -36,7 +35,7 @@ use cosmic::widget::menu::action::MenuAction;
|
||||||
use cosmic::widget::menu::key_bind::KeyBind;
|
use cosmic::widget::menu::key_bind::KeyBind;
|
||||||
use cosmic::widget::segmented_button::{self, Entity, ReorderEvent};
|
use cosmic::widget::segmented_button::{self, Entity, ReorderEvent};
|
||||||
use cosmic::widget::{self, icon, settings, space};
|
use cosmic::widget::{self, icon, settings, space};
|
||||||
use cosmic::{Application, ApplicationExt, Element, cosmic_theme, executor, style, surface, theme};
|
use cosmic::{Application, ApplicationExt, Element, cosmic_theme, executor, surface, theme};
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use notify_debouncer_full::notify::{self, RecommendedWatcher};
|
use notify_debouncer_full::notify::{self, RecommendedWatcher};
|
||||||
use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer};
|
use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer};
|
||||||
|
|
@ -427,6 +426,7 @@ pub enum NavMenuAction {
|
||||||
Preview(segmented_button::Entity),
|
Preview(segmented_button::Entity),
|
||||||
RunContextAction(segmented_button::Entity, usize),
|
RunContextAction(segmented_button::Entity, usize),
|
||||||
RemoveFromSidebar(segmented_button::Entity),
|
RemoveFromSidebar(segmented_button::Entity),
|
||||||
|
ChangeSidebarLabel(segmented_button::Entity),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MenuAction for NavMenuAction {
|
impl MenuAction for NavMenuAction {
|
||||||
|
|
@ -502,6 +502,7 @@ pub enum Message {
|
||||||
OpenWithBrowse,
|
OpenWithBrowse,
|
||||||
OpenWithDialog(Option<Entity>),
|
OpenWithDialog(Option<Entity>),
|
||||||
OpenWithSelection(usize),
|
OpenWithSelection(usize),
|
||||||
|
OpenWithSearchClear,
|
||||||
OpenWithToggleDefault(bool),
|
OpenWithToggleDefault(bool),
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
Overlap(window::Id, OverlapNotifyEvent),
|
Overlap(window::Id, OverlapNotifyEvent),
|
||||||
|
|
@ -605,7 +606,7 @@ pub enum Message {
|
||||||
OutputEvent(OutputEvent, WlOutput),
|
OutputEvent(OutputEvent, WlOutput),
|
||||||
Cosmic(app::Action),
|
Cosmic(app::Action),
|
||||||
None,
|
None,
|
||||||
Surface(surface::Action),
|
Surface(surface::Action<Message>),
|
||||||
CutPaths(Vec<PathBuf>),
|
CutPaths(Vec<PathBuf>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -690,6 +691,7 @@ pub enum DialogPage {
|
||||||
mime: mime_guess::Mime,
|
mime: mime_guess::Mime,
|
||||||
selected: usize,
|
selected: usize,
|
||||||
store_opt: Option<Arc<MimeApp>>,
|
store_opt: Option<Arc<MimeApp>>,
|
||||||
|
search_app_name: String,
|
||||||
/// When true, the chosen app is written to mimeapps.list as the
|
/// When true, the chosen app is written to mimeapps.list as the
|
||||||
/// default handler for `mime` after it spawns.
|
/// default handler for `mime` after it spawns.
|
||||||
set_default: bool,
|
set_default: bool,
|
||||||
|
|
@ -700,6 +702,10 @@ pub enum DialogPage {
|
||||||
DeleteTrash {
|
DeleteTrash {
|
||||||
items: Vec<TrashItem>,
|
items: Vec<TrashItem>,
|
||||||
},
|
},
|
||||||
|
ChangeSidebarLabel {
|
||||||
|
entity: Entity,
|
||||||
|
label: String,
|
||||||
|
},
|
||||||
RenameItem {
|
RenameItem {
|
||||||
from: PathBuf,
|
from: PathBuf,
|
||||||
parent: PathBuf,
|
parent: PathBuf,
|
||||||
|
|
@ -792,7 +798,6 @@ pub struct MounterData(MounterKey, MounterItem);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum WindowKind {
|
pub enum WindowKind {
|
||||||
ContextMenu(Entity, widget::Id),
|
|
||||||
Desktop(Entity),
|
Desktop(Entity),
|
||||||
DesktopViewOptions,
|
DesktopViewOptions,
|
||||||
Dialogs(widget::Id),
|
Dialogs(widget::Id),
|
||||||
|
|
@ -1585,12 +1590,6 @@ impl App {
|
||||||
fn remove_window(&mut self, id: &window::Id) {
|
fn remove_window(&mut self, id: &window::Id) {
|
||||||
if let Some(window) = self.windows.remove(id) {
|
if let Some(window) = self.windows.remove(id) {
|
||||||
match window.kind {
|
match window.kind {
|
||||||
WindowKind::ContextMenu(entity, _) => {
|
|
||||||
// Close context menu
|
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
|
||||||
tab.context_menu = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowKind::Desktop(entity) => {
|
WindowKind::Desktop(entity) => {
|
||||||
// Remove the tab from the tab model
|
// Remove the tab from the tab model
|
||||||
self.tab_model.remove(entity);
|
self.tab_model.remove(entity);
|
||||||
|
|
@ -1927,21 +1926,6 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_context_menus(&mut self) -> Task<Message> {
|
|
||||||
let active = self.tab_model.active();
|
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(active) {
|
|
||||||
tab.location_context_menu_index = None;
|
|
||||||
if tab.context_menu.is_some() {
|
|
||||||
return self.update(Message::TabMessage(
|
|
||||||
Some(active),
|
|
||||||
tab::Message::ContextMenu(None, None),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Task::none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_nav_model(&mut self) {
|
fn update_nav_model(&mut self) {
|
||||||
let mut nav_model = segmented_button::ModelBuilder::default();
|
let mut nav_model = segmented_button::ModelBuilder::default();
|
||||||
|
|
||||||
|
|
@ -1955,15 +1939,7 @@ impl App {
|
||||||
|
|
||||||
for (favorite_i, favorite) in self.config.favorites.iter().enumerate() {
|
for (favorite_i, favorite) in self.config.favorites.iter().enumerate() {
|
||||||
if let Some(path) = favorite.path_opt() {
|
if let Some(path) = favorite.path_opt() {
|
||||||
let name = if matches!(favorite, Favorite::Home) {
|
let name = favorite.display_name().unwrap_or_else(|| fl!("filesystem"));
|
||||||
fl!("home")
|
|
||||||
} else if let Favorite::Network { name, .. } = favorite {
|
|
||||||
name.clone()
|
|
||||||
} else if let Some(file_name) = path.file_name().and_then(|x| x.to_str()) {
|
|
||||||
file_name.to_string()
|
|
||||||
} else {
|
|
||||||
fl!("filesystem")
|
|
||||||
};
|
|
||||||
nav_model = nav_model.insert(move |b| {
|
nav_model = nav_model.insert(move |b| {
|
||||||
b.text(name.clone())
|
b.text(name.clone())
|
||||||
.icon(
|
.icon(
|
||||||
|
|
@ -2600,15 +2576,33 @@ impl App {
|
||||||
.favorites
|
.favorites
|
||||||
.iter()
|
.iter()
|
||||||
.map(|favorite| {
|
.map(|favorite| {
|
||||||
if let Favorite::Path(path) = favorite {
|
match favorite {
|
||||||
for (from, to) in path_changes.iter().map(|(f, t)| (f.as_ref(), t.as_ref())) {
|
Favorite::Path(path) => {
|
||||||
if path.starts_with(from)
|
for (from, to) in path_changes.iter().map(|(f, t)| (f.as_ref(), t.as_ref()))
|
||||||
&& let Ok(relative) = path.strip_prefix(from)
|
|
||||||
{
|
{
|
||||||
favorites_changed = true;
|
if path.starts_with(from)
|
||||||
return Favorite::from_path(to.join(relative));
|
&& let Ok(relative) = path.strip_prefix(from)
|
||||||
|
{
|
||||||
|
favorites_changed = true;
|
||||||
|
return Favorite::from_path(to.join(relative));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Favorite::Named { path, name } => {
|
||||||
|
for (from, to) in path_changes.iter().map(|(f, t)| (f.as_ref(), t.as_ref()))
|
||||||
|
{
|
||||||
|
if path.starts_with(from)
|
||||||
|
&& let Ok(relative) = path.strip_prefix(from)
|
||||||
|
{
|
||||||
|
favorites_changed = true;
|
||||||
|
return Favorite::Named {
|
||||||
|
path: to.join(relative),
|
||||||
|
name: name.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
favorite.clone()
|
favorite.clone()
|
||||||
})
|
})
|
||||||
|
|
@ -2718,6 +2712,9 @@ impl Application for App {
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if matches!(flags.mode, Mode::Desktop) {
|
||||||
|
core.set_auto_blur(Auto::Window | Auto::Popup);
|
||||||
|
}
|
||||||
let mut app = Self {
|
let mut app = Self {
|
||||||
core,
|
core,
|
||||||
about,
|
about,
|
||||||
|
|
@ -2836,8 +2833,16 @@ impl Application for App {
|
||||||
cosmic::Action::App(Message::NavMenuAction(NavMenuAction::OpenInNewTab(entity)))
|
cosmic::Action::App(Message::NavMenuAction(NavMenuAction::OpenInNewTab(entity)))
|
||||||
})
|
})
|
||||||
.context_menu(self.nav_context_menu())
|
.context_menu(self.nav_context_menu())
|
||||||
.close_icon(icon::from_name("media-eject-symbolic").size(16).icon())
|
.close_icon(icon::from_name("media-eject-symbolic").size(16).icon());
|
||||||
.into_container();
|
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
{
|
||||||
|
nav = nav
|
||||||
|
.window_id_maybe(self.core().main_window_id())
|
||||||
|
.on_surface_action(|action| cosmic::Action::Surface(action.flatten()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut nav = nav.into_container();
|
||||||
|
|
||||||
if !self.core.is_condensed() {
|
if !self.core.is_condensed() {
|
||||||
nav = nav.max_width(280);
|
nav = nav.max_width(280);
|
||||||
|
|
@ -2848,14 +2853,12 @@ impl Application for App {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nav_context_menu(
|
fn nav_context_menu(&self) -> Option<Vec<widget::menu::Tree<cosmic::Action<Self::Message>>>> {
|
||||||
&self,
|
|
||||||
) -> Option<Vec<widget::menu::Tree<cosmic::Action<Self::Message>>>> {
|
|
||||||
let items = self.nav_model.iter().map(|entity| {
|
let items = self.nav_model.iter().map(|entity| {
|
||||||
let favorite_index_opt = self.nav_model.data::<FavoriteIndex>(entity);
|
let favorite_index_opt = self.nav_model.data::<FavoriteIndex>(entity);
|
||||||
let location_opt = self.nav_model.data::<Location>(entity);
|
let location_opt = self.nav_model.data::<Location>(entity);
|
||||||
|
|
||||||
let mut items = Vec::with_capacity(7);
|
let mut items: Vec<widget::menu::Item<NavMenuAction, String>> = Vec::with_capacity(7);
|
||||||
|
|
||||||
if location_opt
|
if location_opt
|
||||||
.and_then(Location::path_opt)
|
.and_then(Location::path_opt)
|
||||||
|
|
@ -2915,6 +2918,11 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
items.push(cosmic::widget::menu::Item::Divider);
|
items.push(cosmic::widget::menu::Item::Divider);
|
||||||
if favorite_index_opt.is_some() {
|
if favorite_index_opt.is_some() {
|
||||||
|
items.push(cosmic::widget::menu::Item::Button(
|
||||||
|
fl!("change-sidebar-label"),
|
||||||
|
None,
|
||||||
|
NavMenuAction::ChangeSidebarLabel(entity),
|
||||||
|
));
|
||||||
items.push(cosmic::widget::menu::Item::Button(
|
items.push(cosmic::widget::menu::Item::Button(
|
||||||
fl!("remove-from-sidebar"),
|
fl!("remove-from-sidebar"),
|
||||||
None,
|
None,
|
||||||
|
|
@ -2982,10 +2990,14 @@ impl Application for App {
|
||||||
})
|
})
|
||||||
&& let Some(mounter) = MOUNTERS.get(&key)
|
&& let Some(mounter) = MOUNTERS.get(&key)
|
||||||
{
|
{
|
||||||
return mounter.network_drive(uri.clone()).map(move |()| {
|
return mounter.network_drive(uri.clone()).map(move |mounted| {
|
||||||
cosmic::Action::App(Message::NetworkDriveOpenEntityAfterMount {
|
if mounted {
|
||||||
entity,
|
cosmic::Action::App(Message::NetworkDriveOpenEntityAfterMount {
|
||||||
})
|
entity,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
cosmic::action::none()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3095,18 +3107,6 @@ impl Application for App {
|
||||||
return cosmic::task::message(cosmic::action::app(Message::SetShowDetails(false)));
|
return cosmic::task::message(cosmic::action::app(Message::SetShowDetails(false)));
|
||||||
}
|
}
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||||
if tab.location_context_menu_index.is_some() {
|
|
||||||
tab.location_context_menu_index = None;
|
|
||||||
return Task::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
if tab.context_menu.is_some() {
|
|
||||||
return self.update(Message::TabMessage(
|
|
||||||
Some(entity),
|
|
||||||
tab::Message::ContextMenu(None, None),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if tab.edit_location.is_some() {
|
if tab.edit_location.is_some() {
|
||||||
tab.edit_location = None;
|
tab.edit_location = None;
|
||||||
return Task::none();
|
return Task::none();
|
||||||
|
|
@ -3202,7 +3202,8 @@ impl Application for App {
|
||||||
} else {
|
} else {
|
||||||
Favorite::from_path(path)
|
Favorite::from_path(path)
|
||||||
};
|
};
|
||||||
if !favorites.contains(&favorite) {
|
let favorite_path = favorite.path_opt();
|
||||||
|
if !favorites.iter().any(|f| f.path_opt() == favorite_path) {
|
||||||
favorites.push(favorite);
|
favorites.push(favorite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3509,10 +3510,18 @@ impl Application for App {
|
||||||
path,
|
path,
|
||||||
mime,
|
mime,
|
||||||
selected,
|
selected,
|
||||||
|
search_app_name,
|
||||||
set_default,
|
set_default,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let available_apps = self.mime_app_cache.get_apps_for_mime(&mime, true);
|
let mut available_apps =
|
||||||
|
self.mime_app_cache.get_apps_for_mime(&mime, true);
|
||||||
|
available_apps.retain(|(app, _)| {
|
||||||
|
app.name
|
||||||
|
.to_lowercase()
|
||||||
|
.trim()
|
||||||
|
.contains(search_app_name.to_lowercase().as_str().trim())
|
||||||
|
});
|
||||||
|
|
||||||
if let Some((app, _)) = available_apps.get(selected) {
|
if let Some((app, _)) = available_apps.get(selected) {
|
||||||
if let Some(mut command) =
|
if let Some(mut command) =
|
||||||
|
|
@ -3558,6 +3567,18 @@ impl Application for App {
|
||||||
DialogPage::DeleteTrash { items } => {
|
DialogPage::DeleteTrash { items } => {
|
||||||
tasks.push(self.operation(Operation::DeleteTrash { items }));
|
tasks.push(self.operation(Operation::DeleteTrash { items }));
|
||||||
}
|
}
|
||||||
|
DialogPage::ChangeSidebarLabel { entity, label } => {
|
||||||
|
if let Some(FavoriteIndex(favorite_i)) =
|
||||||
|
self.nav_model.data::<FavoriteIndex>(entity)
|
||||||
|
{
|
||||||
|
let mut favorites = self.config.favorites.clone();
|
||||||
|
if let Some(favorite) = favorites.get_mut(*favorite_i) {
|
||||||
|
*favorite = favorite.with_label(label.trim());
|
||||||
|
config_set!(favorites, favorites);
|
||||||
|
tasks.push(self.update_config());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
DialogPage::RenameItem {
|
DialogPage::RenameItem {
|
||||||
from, parent, name, ..
|
from, parent, name, ..
|
||||||
} => {
|
} => {
|
||||||
|
|
@ -3843,7 +3864,7 @@ impl Application for App {
|
||||||
Message::Mouse(window_id, _button) => {
|
Message::Mouse(window_id, _button) => {
|
||||||
// Close context menu when clicking outside.
|
// Close context menu when clicking outside.
|
||||||
if self.core.main_window_id() == Some(window_id) {
|
if self.core.main_window_id() == Some(window_id) {
|
||||||
return self.close_context_menus();
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::MoveTo(entity_opt) => {
|
Message::MoveTo(entity_opt) => {
|
||||||
|
|
@ -3896,7 +3917,7 @@ impl Application for App {
|
||||||
Some((*mounter_key, self.network_drive_input.clone()));
|
Some((*mounter_key, self.network_drive_input.clone()));
|
||||||
return mounter
|
return mounter
|
||||||
.network_drive(self.network_drive_input.clone())
|
.network_drive(self.network_drive_input.clone())
|
||||||
.map(|()| cosmic::action::none());
|
.map(|_| cosmic::action::none());
|
||||||
}
|
}
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"no mounter found for connecting to {:?}",
|
"no mounter found for connecting to {:?}",
|
||||||
|
|
@ -4159,21 +4180,25 @@ impl Application for App {
|
||||||
let Some(path) = item.path_opt() else {
|
let Some(path) = item.path_opt() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
return self.push_dialog(
|
return Task::batch([
|
||||||
DialogPage::OpenWith {
|
self.push_dialog(
|
||||||
path: path.clone(),
|
DialogPage::OpenWith {
|
||||||
mime: item.mime.clone(),
|
path: path.clone(),
|
||||||
selected: 0,
|
mime: item.mime.clone(),
|
||||||
store_opt: "x-scheme-handler/mime"
|
selected: 0,
|
||||||
.parse::<mime_guess::Mime>()
|
store_opt: "x-scheme-handler/mime"
|
||||||
.ok()
|
.parse::<mime_guess::Mime>()
|
||||||
.and_then(|mime| {
|
.ok()
|
||||||
self.mime_app_cache.get(&mime).first().cloned()
|
.and_then(|mime| {
|
||||||
}),
|
self.mime_app_cache.get(&mime).first().cloned()
|
||||||
set_default: false,
|
}),
|
||||||
},
|
search_app_name: String::new(),
|
||||||
Some(CONFIRM_OPEN_WITH_BUTTON_ID.clone()),
|
set_default: false,
|
||||||
);
|
},
|
||||||
|
Some(CONFIRM_OPEN_WITH_BUTTON_ID.clone()),
|
||||||
|
),
|
||||||
|
widget::text_input::focus(self.dialog_text_input.clone()),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4189,6 +4214,14 @@ impl Application for App {
|
||||||
*set_default = enabled;
|
*set_default = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::OpenWithSearchClear => {
|
||||||
|
if let Some(DialogPage::OpenWith {
|
||||||
|
search_app_name, ..
|
||||||
|
}) = self.dialog_pages.front_mut()
|
||||||
|
{
|
||||||
|
*search_app_name = String::new();
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::Paste(entity_opt) => {
|
Message::Paste(entity_opt) => {
|
||||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity)
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity)
|
||||||
|
|
@ -4644,7 +4677,7 @@ impl Application for App {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Message::SearchActivate => {
|
Message::SearchActivate => {
|
||||||
let mut tasks = vec![self.close_context_menus()];
|
let mut tasks = vec![];
|
||||||
|
|
||||||
if self.search_get().is_none() {
|
if self.search_get().is_none() {
|
||||||
tasks.push(self.search_set_active(Some(String::new())));
|
tasks.push(self.search_set_active(Some(String::new())));
|
||||||
|
|
@ -4655,7 +4688,7 @@ impl Application for App {
|
||||||
return Task::batch(tasks);
|
return Task::batch(tasks);
|
||||||
}
|
}
|
||||||
Message::SearchClear => {
|
Message::SearchClear => {
|
||||||
return Task::batch([self.close_context_menus(), self.search_set_active(None)]);
|
return self.search_set_active(None);
|
||||||
}
|
}
|
||||||
Message::SearchInput(input) => {
|
Message::SearchInput(input) => {
|
||||||
return self.search_set_active(Some(input));
|
return self.search_set_active(Some(input));
|
||||||
|
|
@ -4756,7 +4789,7 @@ impl Application for App {
|
||||||
return self.update_config();
|
return self.update_config();
|
||||||
}
|
}
|
||||||
Message::TabActivate(entity) => {
|
Message::TabActivate(entity) => {
|
||||||
let mut tasks = vec![self.close_context_menus()];
|
let mut tasks = vec![];
|
||||||
|
|
||||||
// Activate new tab
|
// Activate new tab
|
||||||
self.tab_model.activate(entity);
|
self.tab_model.activate(entity);
|
||||||
|
|
@ -4818,7 +4851,9 @@ impl Application for App {
|
||||||
tasks.push(Task::future(async move {
|
tasks.push(Task::future(async move {
|
||||||
cosmic::action::app(Message::WindowClose)
|
cosmic::action::app(Message::WindowClose)
|
||||||
}));
|
}));
|
||||||
} else if let Some(position) = self.tab_model.position(entity) {
|
} else if entity == self.tab_model.active()
|
||||||
|
&& let Some(position) = self.tab_model.position(entity)
|
||||||
|
{
|
||||||
let new_position = if position > 0 {
|
let new_position = if position > 0 {
|
||||||
position - 1
|
position - 1
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -4855,6 +4890,8 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::TabMessage(entity_opt, tab_message) => {
|
Message::TabMessage(entity_opt, tab_message) => {
|
||||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||||
|
// The context menu opens on right-button release, so refresh paste availability now
|
||||||
|
let right_click = matches!(tab_message, tab::Message::RightClick(..));
|
||||||
|
|
||||||
let tab_commands = match self.tab_model.data_mut::<Tab>(entity) {
|
let tab_commands = match self.tab_model.data_mut::<Tab>(entity) {
|
||||||
Some(tab) => tab.update(tab_message, self.modifiers),
|
Some(tab) => tab.update(tab_message, self.modifiers),
|
||||||
|
|
@ -4862,6 +4899,9 @@ impl Application for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut commands = Vec::new();
|
let mut commands = Vec::new();
|
||||||
|
if right_click {
|
||||||
|
commands.push(self.update(Message::CheckClipboard));
|
||||||
|
}
|
||||||
for tab_command in tab_commands {
|
for tab_command in tab_commands {
|
||||||
match tab_command {
|
match tab_command {
|
||||||
tab::Command::Action(action) => {
|
tab::Command::Action(action) => {
|
||||||
|
|
@ -4874,7 +4914,8 @@ impl Application for App {
|
||||||
tab::Command::AddToSidebar(path) => {
|
tab::Command::AddToSidebar(path) => {
|
||||||
let mut favorites = self.config.favorites.clone();
|
let mut favorites = self.config.favorites.clone();
|
||||||
let favorite = Favorite::from_path(path);
|
let favorite = Favorite::from_path(path);
|
||||||
if !favorites.contains(&favorite) {
|
let favorite_path = favorite.path_opt();
|
||||||
|
if !favorites.iter().any(|f| f.path_opt() == favorite_path) {
|
||||||
favorites.push(favorite);
|
favorites.push(favorite);
|
||||||
}
|
}
|
||||||
config_set!(favorites, favorites);
|
config_set!(favorites, favorites);
|
||||||
|
|
@ -4901,78 +4942,11 @@ impl Application for App {
|
||||||
self.update_tab(entity, tab_path, selection_paths),
|
self.update_tab(entity, tab_path, selection_paths),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
tab::Command::ContextMenu(point_opt, parent_id) => {
|
tab::Command::Surface(action) => {
|
||||||
#[cfg(feature = "wayland")]
|
// re-type the tab's surface action the way its messages are re-typed
|
||||||
if let Some(point) = point_opt {
|
let action = action
|
||||||
if crate::is_wayland() {
|
.map(move |message| Message::TabMessage(Some(entity), message));
|
||||||
// Open context menu
|
commands.push(self.update(Message::Surface(action)));
|
||||||
use cctk::wayland_protocols::xdg::shell::client::xdg_positioner::{
|
|
||||||
Anchor, Gravity,
|
|
||||||
};
|
|
||||||
use cosmic::iced::runtime::platform_specific::wayland::popup::{
|
|
||||||
SctkPopupSettings, SctkPositioner,
|
|
||||||
};
|
|
||||||
let window_id = WindowId::unique();
|
|
||||||
self.windows.insert(
|
|
||||||
window_id,
|
|
||||||
Window::new(WindowKind::ContextMenu(
|
|
||||||
entity,
|
|
||||||
widget::Id::unique(),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
commands.push(self.update(Message::CheckClipboard));
|
|
||||||
commands.push(self.update(Message::Surface(
|
|
||||||
cosmic::surface::action::app_popup(
|
|
||||||
|_: &Self| cosmic::surface::action::LiveSettings::default(),
|
|
||||||
move |app: &mut Self| -> SctkPopupSettings {
|
|
||||||
let anchor_rect = Rectangle {
|
|
||||||
x: point.x as i32,
|
|
||||||
y: point.y as i32,
|
|
||||||
width: 1,
|
|
||||||
height: 1,
|
|
||||||
};
|
|
||||||
let positioner = SctkPositioner {
|
|
||||||
size: None,
|
|
||||||
anchor_rect,
|
|
||||||
anchor: Anchor::None,
|
|
||||||
gravity: Gravity::BottomRight,
|
|
||||||
reactive: true,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
SctkPopupSettings {
|
|
||||||
parent: parent_id.unwrap_or(
|
|
||||||
app.core
|
|
||||||
.main_window_id()
|
|
||||||
.unwrap_or(WindowId::NONE),
|
|
||||||
),
|
|
||||||
id: window_id,
|
|
||||||
positioner,
|
|
||||||
parent_size: None,
|
|
||||||
grab: true,
|
|
||||||
close_with_children: false,
|
|
||||||
input_zone: None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Destroy previous popup
|
|
||||||
let mut window_ids = Vec::new();
|
|
||||||
for (window_id, window) in &self.windows {
|
|
||||||
if let WindowKind::ContextMenu(e, _) = &window.kind
|
|
||||||
&& *e == entity
|
|
||||||
{
|
|
||||||
window_ids.push(*window_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for window_id in window_ids {
|
|
||||||
commands.push(self.update(Message::Surface(
|
|
||||||
cosmic::surface::action::destroy_popup(window_id),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tab::Command::Delete(paths) => commands.push(self.delete(paths)),
|
tab::Command::Delete(paths) => commands.push(self.delete(paths)),
|
||||||
tab::Command::DropFiles(to, from) => {
|
tab::Command::DropFiles(to, from) => {
|
||||||
|
|
@ -5022,7 +4996,6 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
tab::Command::OpenFile(paths) => commands.push(self.open_file(&paths)),
|
tab::Command::OpenFile(paths) => commands.push(self.open_file(&paths)),
|
||||||
tab::Command::OpenInNewTab(path) => {
|
tab::Command::OpenInNewTab(path) => {
|
||||||
commands.push(self.close_context_menus());
|
|
||||||
commands.push(self.open_tab(Location::Path(path), false, None));
|
commands.push(self.open_tab(Location::Path(path), false, None));
|
||||||
}
|
}
|
||||||
tab::Command::OpenInNewWindow(path) => match env::current_exe() {
|
tab::Command::OpenInNewWindow(path) => match env::current_exe() {
|
||||||
|
|
@ -5459,12 +5432,6 @@ impl Application for App {
|
||||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(tab_entity) {
|
if let Some(tab) = self.tab_model.data_mut::<Tab>(tab_entity) {
|
||||||
// Close location editing if enabled
|
// Close location editing if enabled
|
||||||
tab.edit_location = None;
|
tab.edit_location = None;
|
||||||
// Close other context menus.
|
|
||||||
tab.location_context_menu_index = None;
|
|
||||||
return Task::done(cosmic::Action::App(Message::TabMessage(
|
|
||||||
Some(tab_entity),
|
|
||||||
tab::Message::ContextMenu(None, None),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::NavMenuAction(action) => match action {
|
Message::NavMenuAction(action) => match action {
|
||||||
|
|
@ -5508,6 +5475,7 @@ impl Application for App {
|
||||||
.and_then(|mime| {
|
.and_then(|mime| {
|
||||||
self.mime_app_cache.get(&mime).first().cloned()
|
self.mime_app_cache.get(&mime).first().cloned()
|
||||||
}),
|
}),
|
||||||
|
search_app_name: String::new(),
|
||||||
set_default: false,
|
set_default: false,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
|
@ -5562,7 +5530,7 @@ impl Application for App {
|
||||||
_ => Task::none(),
|
_ => Task::none(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Task::batch([self.close_context_menus(), open_task]);
|
return open_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the selected path in a new cosmic-files window.
|
// Open the selected path in a new cosmic-files window.
|
||||||
|
|
@ -5643,6 +5611,20 @@ impl Application for App {
|
||||||
return self.update_config();
|
return self.update_config();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavMenuAction::ChangeSidebarLabel(entity) => {
|
||||||
|
if let Some(favorite) = self.nav_model.data::<FavoriteIndex>(entity).and_then(
|
||||||
|
|FavoriteIndex(favorite_i)| self.config.favorites.get(*favorite_i),
|
||||||
|
) {
|
||||||
|
let label = favorite.display_name().unwrap_or_else(|| fl!("filesystem"));
|
||||||
|
return Task::batch([
|
||||||
|
self.dialog_pages
|
||||||
|
.push_back(DialogPage::ChangeSidebarLabel { entity, label }),
|
||||||
|
widget::text_input::focus(self.dialog_text_input.clone()),
|
||||||
|
widget::text_input::select_all(self.dialog_text_input.clone()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Message::Recents => {
|
Message::Recents => {
|
||||||
if self.config.show_recents {
|
if self.config.show_recents {
|
||||||
|
|
@ -5694,24 +5676,33 @@ impl Application for App {
|
||||||
.insert(surface_id, Window::new(WindowKind::Desktop(entity)));
|
.insert(surface_id, Window::new(WindowKind::Desktop(entity)));
|
||||||
return Task::batch([
|
return Task::batch([
|
||||||
command,
|
command,
|
||||||
get_layer_surface(SctkLayerSurfaceSettings {
|
cosmic::task::message(cosmic::Action::Surface(
|
||||||
id: surface_id,
|
cosmic::surface::action::app_layer_shell(
|
||||||
layer: Layer::Bottom,
|
|_| Default::default(),
|
||||||
keyboard_interactivity: KeyboardInteractivity::OnDemand,
|
move |_: &mut App| SctkLayerSurfaceSettings {
|
||||||
input_zone: None,
|
id: surface_id,
|
||||||
anchor: Anchor::TOP | Anchor::BOTTOM | Anchor::LEFT | Anchor::RIGHT,
|
layer: Layer::Bottom,
|
||||||
output: IcedOutput::Output(output),
|
keyboard_interactivity: KeyboardInteractivity::OnDemand,
|
||||||
namespace: "cosmic-files-applet".into(),
|
input_zone: None,
|
||||||
size: Some((None, None)),
|
anchor: Anchor::TOP
|
||||||
margin: IcedMargin {
|
| Anchor::BOTTOM
|
||||||
top: 0,
|
| Anchor::LEFT
|
||||||
bottom: 0,
|
| Anchor::RIGHT,
|
||||||
left: 0,
|
output: IcedOutput::Output(output.clone()),
|
||||||
right: 0,
|
namespace: "cosmic-files-applet".into(),
|
||||||
},
|
size: Some((None, None)),
|
||||||
exclusive_zone: 0,
|
margin: IcedMargin {
|
||||||
size_limits: Limits::NONE.min_width(1.0).min_height(1.0),
|
top: 0,
|
||||||
}),
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
|
exclusive_zone: 0,
|
||||||
|
size_limits: Limits::NONE.min_width(1.0).min_height(1.0),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
)),
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
overlap_notify(surface_id, true),
|
overlap_notify(surface_id, true),
|
||||||
]);
|
]);
|
||||||
|
|
@ -5804,9 +5795,7 @@ impl Application for App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Message::Surface(action) => {
|
Message::Surface(action) => {
|
||||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
return cosmic::task::message(cosmic::Action::Surface(action));
|
||||||
cosmic::app::Action::Surface(action),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Message::SaveSortNames => {
|
Message::SaveSortNames => {
|
||||||
self.must_save_sort_names = false;
|
self.must_save_sort_names = false;
|
||||||
|
|
@ -6352,7 +6341,9 @@ impl Application for App {
|
||||||
mime,
|
mime,
|
||||||
selected,
|
selected,
|
||||||
store_opt,
|
store_opt,
|
||||||
|
search_app_name,
|
||||||
set_default,
|
set_default,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
let name = match path.file_name() {
|
let name = match path.file_name() {
|
||||||
Some(file_name) => file_name.to_str(),
|
Some(file_name) => file_name.to_str(),
|
||||||
|
|
@ -6360,7 +6351,13 @@ impl Application for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut column = widget::list_column();
|
let mut column = widget::list_column();
|
||||||
let available_apps = self.mime_app_cache.get_apps_for_mime(mime, true);
|
let mut available_apps = self.mime_app_cache.get_apps_for_mime(mime, true);
|
||||||
|
available_apps.retain(|(app, _)| {
|
||||||
|
app.name
|
||||||
|
.to_lowercase()
|
||||||
|
.trim()
|
||||||
|
.contains(search_app_name.to_lowercase().as_str().trim())
|
||||||
|
});
|
||||||
let item_height = 32.0;
|
let item_height = 32.0;
|
||||||
let mut displayed_default = false;
|
let mut displayed_default = false;
|
||||||
let mut last_kind = MimeAppMatch::Exact;
|
let mut last_kind = MimeAppMatch::Exact;
|
||||||
|
|
@ -6424,6 +6421,25 @@ impl Application for App {
|
||||||
.secondary_action(
|
.secondary_action(
|
||||||
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
||||||
)
|
)
|
||||||
|
.control(
|
||||||
|
widget::text_input::search_input(
|
||||||
|
fl!("search-application"),
|
||||||
|
search_app_name,
|
||||||
|
)
|
||||||
|
.id(self.dialog_text_input.clone())
|
||||||
|
.on_clear(Message::OpenWithSearchClear)
|
||||||
|
.on_input(move |search_app_name| {
|
||||||
|
Message::DialogUpdate(DialogPage::OpenWith {
|
||||||
|
path: path.clone(),
|
||||||
|
mime: mime.clone(),
|
||||||
|
selected: *selected,
|
||||||
|
store_opt: store_opt.clone(),
|
||||||
|
search_app_name,
|
||||||
|
set_default: *set_default,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.on_submit(|_| Message::DialogComplete),
|
||||||
|
)
|
||||||
.control(widget::scrollable(column).height({
|
.control(widget::scrollable(column).height({
|
||||||
let max_size = self
|
let max_size = self
|
||||||
.size
|
.size
|
||||||
|
|
@ -6512,6 +6528,40 @@ impl Application for App {
|
||||||
target = target
|
target = target
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
DialogPage::ChangeSidebarLabel { entity, label } => {
|
||||||
|
let entity = *entity;
|
||||||
|
let complete_maybe = if label.trim().is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Message::DialogComplete)
|
||||||
|
};
|
||||||
|
|
||||||
|
widget::dialog()
|
||||||
|
.title(fl!("change-sidebar-label"))
|
||||||
|
.primary_action(
|
||||||
|
widget::button::suggested(fl!("save"))
|
||||||
|
.on_press_maybe(complete_maybe.clone()),
|
||||||
|
)
|
||||||
|
.secondary_action(
|
||||||
|
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
||||||
|
)
|
||||||
|
.control(
|
||||||
|
widget::column::with_children([
|
||||||
|
widget::text::body(fl!("sidebar-label")).into(),
|
||||||
|
widget::text_input("", label.as_str())
|
||||||
|
.id(self.dialog_text_input.clone())
|
||||||
|
.on_input(move |label| {
|
||||||
|
Message::DialogUpdate(DialogPage::ChangeSidebarLabel {
|
||||||
|
entity,
|
||||||
|
label,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.on_submit_maybe(complete_maybe.map(|maybe| move |_| maybe.clone()))
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.spacing(space_xxs),
|
||||||
|
)
|
||||||
|
}
|
||||||
DialogPage::RenameItem {
|
DialogPage::RenameItem {
|
||||||
from,
|
from,
|
||||||
parent,
|
parent,
|
||||||
|
|
@ -6898,7 +6948,6 @@ impl Application for App {
|
||||||
})
|
})
|
||||||
.drag_id(self.tab_drag_id),
|
.drag_id(self.tab_drag_id),
|
||||||
)
|
)
|
||||||
.class(style::Container::Background)
|
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.padding([0, space_s]),
|
.padding([0, space_s]),
|
||||||
);
|
);
|
||||||
|
|
@ -6962,23 +7011,6 @@ impl Application for App {
|
||||||
fn view_window(&self, id: WindowId) -> Element<'_, Self::Message> {
|
fn view_window(&self, id: WindowId) -> Element<'_, Self::Message> {
|
||||||
let content = match self.windows.get(&id) {
|
let content = match self.windows.get(&id) {
|
||||||
Some(window) => match &window.kind {
|
Some(window) => match &window.kind {
|
||||||
WindowKind::ContextMenu(entity, id) => match self.tab_model.data::<Tab>(*entity) {
|
|
||||||
Some(tab) => {
|
|
||||||
return widget::autosize::autosize(
|
|
||||||
menu::context_menu(
|
|
||||||
tab,
|
|
||||||
&self.key_binds,
|
|
||||||
&window.modifiers,
|
|
||||||
self.clipboard_has_content(),
|
|
||||||
&self.config.context_actions,
|
|
||||||
)
|
|
||||||
.map(|x| Message::TabMessage(Some(*entity), x)),
|
|
||||||
id.clone(),
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
None => widget::text("Unknown tab ID").into(),
|
|
||||||
},
|
|
||||||
WindowKind::Desktop(entity) => {
|
WindowKind::Desktop(entity) => {
|
||||||
let mut tab_column = widget::column::with_capacity(3);
|
let mut tab_column = widget::column::with_capacity(3);
|
||||||
|
|
||||||
|
|
@ -7038,6 +7070,7 @@ impl Application for App {
|
||||||
return self.view_main().map(|message| match message {
|
return self.view_main().map(|message| match message {
|
||||||
cosmic::Action::App(app) => app,
|
cosmic::Action::App(app) => app,
|
||||||
cosmic::Action::Cosmic(cosmic) => Message::Cosmic(cosmic),
|
cosmic::Action::Cosmic(cosmic) => Message::Cosmic(cosmic),
|
||||||
|
cosmic::Action::Surface(action) => Message::Surface(action),
|
||||||
cosmic::Action::None => Message::None,
|
cosmic::Action::None => Message::None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
src/config.rs
102
src/config.rs
|
|
@ -70,6 +70,11 @@ pub enum Favorite {
|
||||||
name: String,
|
name: String,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
},
|
},
|
||||||
|
/// A path with a custom name chosen by the user
|
||||||
|
Named {
|
||||||
|
path: PathBuf,
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Favorite {
|
impl Favorite {
|
||||||
|
|
@ -98,6 +103,38 @@ impl Favorite {
|
||||||
Self::Videos => dirs::video_dir(),
|
Self::Videos => dirs::video_dir(),
|
||||||
Self::Path(path) => Some(path.clone()),
|
Self::Path(path) => Some(path.clone()),
|
||||||
Self::Network { path, .. } => Some(path.clone()),
|
Self::Network { path, .. } => Some(path.clone()),
|
||||||
|
Self::Named { path, .. } => Some(path.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name shown in the sidebar, or `None` if the path has no usable file name
|
||||||
|
pub fn display_name(&self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
Self::Home => Some(crate::fl!("home")),
|
||||||
|
Self::Named { name, .. } | Self::Network { name, .. } => Some(name.clone()),
|
||||||
|
_ => self
|
||||||
|
.path_opt()?
|
||||||
|
.file_name()
|
||||||
|
.and_then(|x| x.to_str())
|
||||||
|
.map(ToString::to_string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return this favorite with a custom sidebar label chosen by the user
|
||||||
|
pub fn with_label(&self, name: &str) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Network { uri, path, .. } => Self::Network {
|
||||||
|
uri: uri.clone(),
|
||||||
|
name: name.to_string(),
|
||||||
|
path: path.clone(),
|
||||||
|
},
|
||||||
|
other => match other.path_opt() {
|
||||||
|
Some(path) => Self::Named {
|
||||||
|
path,
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
None => other.clone(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +150,7 @@ pub enum TypeToSearch {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub sort_names: FxOrderMap<String, (HeadingOptions, bool)>,
|
pub sort_names: FxOrderMap<String, (HeadingOptions, bool)>,
|
||||||
|
pub dialog_sort_name: (HeadingOptions, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
|
|
@ -124,6 +162,7 @@ impl Default for State {
|
||||||
(HeadingOptions::Modified, false),
|
(HeadingOptions::Modified, false),
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
|
dialog_sort_name: (HeadingOptions::Modified, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -476,3 +515,66 @@ pub const TIME_CONFIG_ID: &str = "com.system76.CosmicAppletTime";
|
||||||
pub struct TimeConfig {
|
pub struct TimeConfig {
|
||||||
pub military_time: bool,
|
pub military_time: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn favorite_with_label_converts_path_to_named() {
|
||||||
|
let favorite = Favorite::Path(PathBuf::from("/some/dir"));
|
||||||
|
assert_eq!(
|
||||||
|
favorite.with_label("Custom"),
|
||||||
|
Favorite::Named {
|
||||||
|
path: PathBuf::from("/some/dir"),
|
||||||
|
name: "Custom".to_string(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn favorite_with_label_updates_network_in_place() {
|
||||||
|
let favorite = Favorite::Network {
|
||||||
|
uri: "sftp://example.com/".to_string(),
|
||||||
|
name: "example.com".to_string(),
|
||||||
|
path: PathBuf::from("/run/mount/example"),
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
favorite.with_label("Custom"),
|
||||||
|
Favorite::Network {
|
||||||
|
uri: "sftp://example.com/".to_string(),
|
||||||
|
name: "Custom".to_string(),
|
||||||
|
path: PathBuf::from("/run/mount/example"),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn favorite_with_label_converts_special_folder_to_named() {
|
||||||
|
let home = dirs::home_dir().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
Favorite::Home.with_label("Custom"),
|
||||||
|
Favorite::Named {
|
||||||
|
path: home,
|
||||||
|
name: "Custom".to_string(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn favorite_display_name() {
|
||||||
|
assert_eq!(
|
||||||
|
Favorite::Path(PathBuf::from("/some/dir")).display_name(),
|
||||||
|
Some("dir".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(Favorite::Path(PathBuf::from("/")).display_name(), None);
|
||||||
|
assert_eq!(
|
||||||
|
Favorite::Named {
|
||||||
|
path: PathBuf::from("/some/dir"),
|
||||||
|
name: "Custom".to_string(),
|
||||||
|
}
|
||||||
|
.display_name(),
|
||||||
|
Some("Custom".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
141
src/dialog.rs
141
src/dialog.rs
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use cosmic::app::cosmic::Cosmic;
|
use cosmic::app::cosmic::Cosmic;
|
||||||
use cosmic::app::{Core, Task, context_drawer};
|
use cosmic::app::{Core, Task, context_drawer};
|
||||||
|
use cosmic::cosmic_config::ConfigSet;
|
||||||
use cosmic::iced::core::SmolStr;
|
use cosmic::iced::core::SmolStr;
|
||||||
use cosmic::iced::core::widget::operation;
|
use cosmic::iced::core::widget::operation;
|
||||||
use cosmic::iced::futures::{self, SinkExt};
|
use cosmic::iced::futures::{self, SinkExt};
|
||||||
|
|
@ -33,12 +34,12 @@ use crate::app::{
|
||||||
Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind, REPLACE_BUTTON_ID,
|
Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind, REPLACE_BUTTON_ID,
|
||||||
};
|
};
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
Config, DialogConfig, Favorite, TIME_CONFIG_ID, ThumbCfg, TimeConfig, TypeToSearch,
|
Config, DialogConfig, State, TIME_CONFIG_ID, ThumbCfg, TimeConfig, TypeToSearch,
|
||||||
};
|
};
|
||||||
use crate::key_bind::key_binds;
|
use crate::key_bind::key_binds;
|
||||||
use crate::localize::LANGUAGE_SORTER;
|
use crate::localize::LANGUAGE_SORTER;
|
||||||
use crate::mounter::{MOUNTERS, MounterItem, MounterItems, MounterKey, MounterMessage};
|
use crate::mounter::{MOUNTERS, MounterItem, MounterItems, MounterKey, MounterMessage};
|
||||||
use crate::tab::{self, ItemMetadata, Location, SearchLocation, Tab};
|
use crate::tab::{self, HeadingOptions, ItemMetadata, Location, SearchLocation, Tab};
|
||||||
use crate::zoom::{zoom_in_view, zoom_out_view, zoom_to_default};
|
use crate::zoom::{zoom_in_view, zoom_out_view, zoom_to_default};
|
||||||
use crate::{fl, home_dir, menu, mime_icon};
|
use crate::{fl, home_dir, menu, mime_icon};
|
||||||
|
|
||||||
|
|
@ -253,6 +254,7 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
crate::localize::localize();
|
crate::localize::localize();
|
||||||
|
|
||||||
let (config_handler, config) = Config::load();
|
let (config_handler, config) = Config::load();
|
||||||
|
let (state_handler, state) = State::load();
|
||||||
|
|
||||||
let mut settings = window::Settings {
|
let mut settings = window::Settings {
|
||||||
decorations: false,
|
decorations: false,
|
||||||
|
|
@ -287,6 +289,8 @@ impl<M: Send + 'static> Dialog<M> {
|
||||||
window_id,
|
window_id,
|
||||||
config_handler,
|
config_handler,
|
||||||
config,
|
config,
|
||||||
|
state_handler,
|
||||||
|
state,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cosmic, cosmic_command) = Cosmic::<App>::init((core, flags));
|
let (cosmic, cosmic_command) = Cosmic::<App>::init((core, flags));
|
||||||
|
|
@ -441,6 +445,8 @@ struct Flags {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
config_handler: Option<cosmic_config::Config>,
|
config_handler: Option<cosmic_config::Config>,
|
||||||
config: Config,
|
config: Config,
|
||||||
|
state_handler: Option<cosmic_config::Config>,
|
||||||
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages that are used specifically by our [`App`].
|
/// Messages that are used specifically by our [`App`].
|
||||||
|
|
@ -470,7 +476,7 @@ enum Message {
|
||||||
SearchActivate,
|
SearchActivate,
|
||||||
SearchClear,
|
SearchClear,
|
||||||
SearchInput(String),
|
SearchInput(String),
|
||||||
Surface(cosmic::surface::Action),
|
Surface(cosmic::surface::Action<Message>),
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
TabMessage(tab::Message),
|
TabMessage(tab::Message),
|
||||||
TabRescan(
|
TabRescan(
|
||||||
|
|
@ -503,7 +509,7 @@ impl From<AppMessage> for Message {
|
||||||
AppMessage::ZoomIn(_entity_opt) => Self::ZoomIn,
|
AppMessage::ZoomIn(_entity_opt) => Self::ZoomIn,
|
||||||
AppMessage::ZoomOut(_entity_opt) => Self::ZoomOut,
|
AppMessage::ZoomOut(_entity_opt) => Self::ZoomOut,
|
||||||
AppMessage::NewItem(_entity_opt, true) => Self::NewFolder,
|
AppMessage::NewItem(_entity_opt, true) => Self::NewFolder,
|
||||||
AppMessage::Surface(action) => Self::Surface(action),
|
AppMessage::Surface(action) => Self::Surface(action.map(Self::from)),
|
||||||
unsupported => {
|
unsupported => {
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||||
Self::None
|
Self::None
|
||||||
|
|
@ -543,7 +549,6 @@ struct App {
|
||||||
title: String,
|
title: String,
|
||||||
accept_label: DialogLabel,
|
accept_label: DialogLabel,
|
||||||
choices: Vec<DialogChoice>,
|
choices: Vec<DialogChoice>,
|
||||||
context_menu_window: Option<window::Id>,
|
|
||||||
context_page: ContextPage,
|
context_page: ContextPage,
|
||||||
dialog_pages: VecDeque<DialogPage>,
|
dialog_pages: VecDeque<DialogPage>,
|
||||||
dialog_text_input: widget::Id,
|
dialog_text_input: widget::Id,
|
||||||
|
|
@ -873,15 +878,6 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_context_menus(&mut self) -> Task<Message> {
|
|
||||||
self.tab.location_context_menu_index = None;
|
|
||||||
if self.tab.context_menu.is_some() {
|
|
||||||
return self.update(Message::TabMessage(tab::Message::ContextMenu(None, None)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Task::none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_nav_model(&mut self) {
|
fn update_nav_model(&mut self) {
|
||||||
let mut nav_model = segmented_button::ModelBuilder::default();
|
let mut nav_model = segmented_button::ModelBuilder::default();
|
||||||
|
|
||||||
|
|
@ -895,13 +891,7 @@ impl App {
|
||||||
|
|
||||||
for favorite in &self.flags.config.favorites {
|
for favorite in &self.flags.config.favorites {
|
||||||
if let Some(path) = favorite.path_opt() {
|
if let Some(path) = favorite.path_opt() {
|
||||||
let name = if matches!(favorite, Favorite::Home) {
|
let Some(name) = favorite.display_name() else {
|
||||||
fl!("home")
|
|
||||||
} else if let Favorite::Network { name, .. } = favorite {
|
|
||||||
name.clone()
|
|
||||||
} else if let Some(file_name) = path.file_name().and_then(|x| x.to_str()) {
|
|
||||||
file_name.to_string()
|
|
||||||
} else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
nav_model = nav_model.insert(move |b| {
|
nav_model = nav_model.insert(move |b| {
|
||||||
|
|
@ -1051,8 +1041,7 @@ impl Application for App {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
tab.mode = tab::Mode::Dialog(flags.kind.clone());
|
tab.mode = tab::Mode::Dialog(flags.kind.clone());
|
||||||
tab.sort_name = tab::HeadingOptions::Modified;
|
(tab.sort_name, tab.sort_direction) = flags.state.dialog_sort_name;
|
||||||
tab.sort_direction = false;
|
|
||||||
|
|
||||||
let key_binds = key_binds(&tab.mode);
|
let key_binds = key_binds(&tab.mode);
|
||||||
|
|
||||||
|
|
@ -1062,7 +1051,6 @@ impl Application for App {
|
||||||
title,
|
title,
|
||||||
accept_label: DialogLabel::from(accept_label),
|
accept_label: DialogLabel::from(accept_label),
|
||||||
choices: Vec::new(),
|
choices: Vec::new(),
|
||||||
context_menu_window: None,
|
|
||||||
context_page: ContextPage::Preview(None, PreviewKind::Selected),
|
context_page: ContextPage::Preview(None, PreviewKind::Selected),
|
||||||
dialog_pages: VecDeque::new(),
|
dialog_pages: VecDeque::new(),
|
||||||
dialog_text_input: widget::Id::new("Dialog Text Input"),
|
dialog_text_input: widget::Id::new("Dialog Text Input"),
|
||||||
|
|
@ -1333,15 +1321,6 @@ impl Application for App {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tab.location_context_menu_index.is_some() {
|
|
||||||
self.tab.location_context_menu_index = None;
|
|
||||||
return Task::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.tab.context_menu.is_some() {
|
|
||||||
return self.update(Message::TabMessage(tab::Message::ContextMenu(None, None)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.tab.edit_location.is_some() {
|
if self.tab.edit_location.is_some() {
|
||||||
// Close location editing if enabled
|
// Close location editing if enabled
|
||||||
self.tab.edit_location = None;
|
self.tab.edit_location = None;
|
||||||
|
|
@ -1576,7 +1555,7 @@ impl Application for App {
|
||||||
Message::Mouse(window_id, _button) => {
|
Message::Mouse(window_id, _button) => {
|
||||||
// Close context menu when clicking outside.
|
// Close context menu when clicking outside.
|
||||||
if self.core.main_window_id() == Some(window_id) {
|
if self.core.main_window_id() == Some(window_id) {
|
||||||
return self.close_context_menus();
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::NewFolder => {
|
Message::NewFolder => {
|
||||||
|
|
@ -1736,7 +1715,7 @@ impl Application for App {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Message::SearchActivate => {
|
Message::SearchActivate => {
|
||||||
let mut tasks = vec![self.close_context_menus()];
|
let mut tasks = vec![];
|
||||||
|
|
||||||
if self.search_get().is_none() {
|
if self.search_get().is_none() {
|
||||||
tasks.push(self.search_set(Some(String::new())));
|
tasks.push(self.search_set(Some(String::new())));
|
||||||
|
|
@ -1747,7 +1726,7 @@ impl Application for App {
|
||||||
return Task::batch(tasks);
|
return Task::batch(tasks);
|
||||||
}
|
}
|
||||||
Message::SearchClear => {
|
Message::SearchClear => {
|
||||||
return Task::batch([self.close_context_menus(), self.search_set(None)]);
|
return self.search_set(None);
|
||||||
}
|
}
|
||||||
Message::SearchInput(input) => {
|
Message::SearchInput(input) => {
|
||||||
return self.search_set(Some(input));
|
return self.search_set(Some(input));
|
||||||
|
|
@ -1783,78 +1762,9 @@ impl Application for App {
|
||||||
self.rescan_tab(selection_paths),
|
self.rescan_tab(selection_paths),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
tab::Command::ContextMenu(point_opt, parent_id) => {
|
tab::Command::Surface(action) => {
|
||||||
#[cfg(feature = "wayland")]
|
let action = action.map(Message::TabMessage);
|
||||||
match point_opt {
|
commands.push(self.update(Message::Surface(action)));
|
||||||
Some(point) => {
|
|
||||||
if crate::is_wayland() {
|
|
||||||
// Open context menu
|
|
||||||
use cctk::wayland_protocols::xdg::shell::client::xdg_positioner::{
|
|
||||||
Anchor, Gravity,
|
|
||||||
};
|
|
||||||
use cosmic::iced::runtime::platform_specific::wayland::popup::{
|
|
||||||
SctkPopupSettings, SctkPositioner,
|
|
||||||
};
|
|
||||||
use cosmic::iced::Rectangle;
|
|
||||||
let window_id = window::Id::unique();
|
|
||||||
self.context_menu_window = Some(window_id);
|
|
||||||
let autosize_id = widget::Id::unique();
|
|
||||||
commands.push(self.update(Message::Surface(
|
|
||||||
cosmic::surface::action::app_popup(
|
|
||||||
|_: &Self| cosmic::surface::action::LiveSettings::default(),
|
|
||||||
move |app: &mut Self| -> SctkPopupSettings {
|
|
||||||
let anchor_rect = Rectangle {
|
|
||||||
x: point.x as i32,
|
|
||||||
y: point.y as i32,
|
|
||||||
width: 1,
|
|
||||||
height: 1,
|
|
||||||
};
|
|
||||||
let positioner = SctkPositioner {
|
|
||||||
size: None,
|
|
||||||
anchor_rect,
|
|
||||||
anchor: Anchor::None,
|
|
||||||
gravity: Gravity::BottomRight,
|
|
||||||
reactive: true,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
SctkPopupSettings {
|
|
||||||
parent: parent_id
|
|
||||||
.unwrap_or(app.flags.window_id),
|
|
||||||
id: window_id,
|
|
||||||
positioner,
|
|
||||||
parent_size: None,
|
|
||||||
grab: true,
|
|
||||||
close_with_children: false,
|
|
||||||
input_zone: None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(Box::new(move |app: &Self| {
|
|
||||||
widget::autosize::autosize(
|
|
||||||
menu::context_menu(
|
|
||||||
&app.tab,
|
|
||||||
&app.key_binds,
|
|
||||||
&app.modifiers,
|
|
||||||
false, // Paste not used in dialogs
|
|
||||||
&app.flags.config.context_actions,
|
|
||||||
)
|
|
||||||
.map(Message::TabMessage)
|
|
||||||
.map(cosmic::Action::App),
|
|
||||||
autosize_id.clone(),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Some(window_id) = self.context_menu_window.take() {
|
|
||||||
commands.push(self.update(Message::Surface(
|
|
||||||
cosmic::surface::action::destroy_popup(window_id),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tab::Command::Iced(iced_command) => {
|
tab::Command::Iced(iced_command) => {
|
||||||
commands.push(iced_command.0.map(|tab_message| {
|
commands.push(iced_command.0.map(|tab_message| {
|
||||||
|
|
@ -1889,6 +1799,17 @@ impl Application for App {
|
||||||
self.auto_scroll_speed = None;
|
self.auto_scroll_speed = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tab::Command::SetSort(_, heading_options, direction) => {
|
||||||
|
self.flags.state.dialog_sort_name = (heading_options, direction);
|
||||||
|
if let Some(state_handler) = self.flags.state_handler.as_ref()
|
||||||
|
&& let Err(err) = state_handler.set::<&(HeadingOptions, bool)>(
|
||||||
|
"dialog_sort_name",
|
||||||
|
&self.flags.state.dialog_sort_name,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
log::warn!("Failed to save dialog sort name: {err:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
unsupported => {
|
unsupported => {
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||||
}
|
}
|
||||||
|
|
@ -2009,9 +1930,7 @@ impl Application for App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Message::Surface(action) => {
|
Message::Surface(action) => {
|
||||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
return cosmic::task::message(cosmic::Action::Surface(action));
|
||||||
cosmic::app::Action::Surface(action),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
416
src/menu.rs
416
src/menu.rs
|
|
@ -1,16 +1,12 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use cosmic::{Element, theme};
|
||||||
use cosmic::app::Core;
|
use cosmic::app::Core;
|
||||||
use cosmic::iced::advanced::widget::text::Style as TextStyle;
|
|
||||||
use cosmic::iced::keyboard::Modifiers;
|
use cosmic::iced::keyboard::Modifiers;
|
||||||
use cosmic::iced::{Alignment, Background, Border, Length};
|
use cosmic::widget::menu::action::MenuAction;
|
||||||
use cosmic::widget::menu::key_bind::KeyBind;
|
use cosmic::widget::menu::key_bind::KeyBind;
|
||||||
use cosmic::widget::menu::{self, ItemHeight, ItemWidth, MenuBar};
|
use cosmic::widget::menu::{self, ItemHeight, ItemWidth, MenuBar};
|
||||||
use cosmic::widget::{
|
use cosmic::widget::{self, responsive_menu_bar};
|
||||||
self, Row, button, column, container, divider, responsive_menu_bar, space, text,
|
|
||||||
};
|
|
||||||
use cosmic::{Element, theme};
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
use i18n_embed::LanguageLoader;
|
use i18n_embed::LanguageLoader;
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -27,21 +23,6 @@ use crate::trash::{Trash, TrashExt};
|
||||||
static MENU_ID: LazyLock<cosmic::widget::Id> =
|
static MENU_ID: LazyLock<cosmic::widget::Id> =
|
||||||
LazyLock::new(|| cosmic::widget::Id::new("responsive-menu"));
|
LazyLock::new(|| cosmic::widget::Id::new("responsive-menu"));
|
||||||
|
|
||||||
macro_rules! menu_button {
|
|
||||||
($($x:expr),+ $(,)?) => (
|
|
||||||
button::custom(
|
|
||||||
Row::with_children(
|
|
||||||
[$(Element::from($x)),+]
|
|
||||||
)
|
|
||||||
.height(Length::Fixed(24.0))
|
|
||||||
.align_y(Alignment::Center)
|
|
||||||
)
|
|
||||||
.padding([theme::spacing().space_xxs, 16])
|
|
||||||
.width(Length::Fill)
|
|
||||||
.class(theme::Button::MenuItem)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn menu_button_optional(
|
const fn menu_button_optional(
|
||||||
label: String,
|
label: String,
|
||||||
action: Action,
|
action: Action,
|
||||||
|
|
@ -54,82 +35,46 @@ const fn menu_button_optional(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A menu action dispatched to the tab the menu was opened on.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct TabAction(pub Action);
|
||||||
|
|
||||||
|
impl MenuAction for TabAction {
|
||||||
|
type Message = tab::Message;
|
||||||
|
|
||||||
|
fn message(&self) -> tab::Message {
|
||||||
|
tab::Message::ContextAction(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn context_menu<'a>(
|
pub fn context_menu<'a>(
|
||||||
tab: &Tab,
|
tab: &Tab,
|
||||||
key_binds: &HashMap<KeyBind, Action>,
|
key_binds: &HashMap<KeyBind, Action>,
|
||||||
modifiers: &Modifiers,
|
modifiers: &Modifiers,
|
||||||
clipboard_paste_available: bool,
|
clipboard_paste_available: bool,
|
||||||
context_actions: &[ContextActionPreset],
|
context_actions: &[ContextActionPreset],
|
||||||
) -> Element<'a, tab::Message> {
|
) -> Vec<menu::Tree<tab::Message>> {
|
||||||
let find_key = |action: &Action| -> String {
|
let menu_item =
|
||||||
for (key_bind, key_action) in key_binds {
|
|label: String, action: Action| menu::Item::Button(label, None, TabAction(action));
|
||||||
if action == key_action {
|
let menu_item_disabled =
|
||||||
return key_bind.to_string();
|
|label: String, action: Action| menu::Item::ButtonDisabled(label, None, TabAction(action));
|
||||||
}
|
|
||||||
}
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
fn key_style(theme: &cosmic::Theme) -> TextStyle {
|
|
||||||
let mut color = theme.cosmic().background(false).component.on;
|
|
||||||
color.alpha *= 0.75;
|
|
||||||
TextStyle {
|
|
||||||
color: Some(color.into()),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn disabled_style(theme: &cosmic::Theme) -> TextStyle {
|
|
||||||
let mut color = theme.cosmic().background(false).component.on;
|
|
||||||
color.alpha *= 0.5;
|
|
||||||
TextStyle {
|
|
||||||
color: Some(color.into()),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let menu_item = |label, action| {
|
|
||||||
let key = find_key(&action);
|
|
||||||
menu_button!(
|
|
||||||
text::body(label),
|
|
||||||
space::horizontal(),
|
|
||||||
text::body(key).class(theme::Text::Custom(key_style))
|
|
||||||
)
|
|
||||||
.on_press(tab::Message::ContextAction(action))
|
|
||||||
};
|
|
||||||
|
|
||||||
let menu_item_disabled = |label, action: Action| {
|
|
||||||
let key = find_key(&action);
|
|
||||||
menu_button!(
|
|
||||||
text::body(label).class(theme::Text::Custom(disabled_style)),
|
|
||||||
space::horizontal(),
|
|
||||||
text::body(key).class(theme::Text::Custom(disabled_style))
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow paste when clipboard has data and we're in a location that supports it
|
// Allow paste when clipboard has data and we're in a location that supports it
|
||||||
let can_paste = clipboard_paste_available && tab.location.supports_paste();
|
let can_paste = clipboard_paste_available && tab.location.supports_paste();
|
||||||
|
|
||||||
let (sort_name, sort_direction, _) = tab.sort_options();
|
let (sort_name, sort_direction, _) = tab.sort_options();
|
||||||
let sort_item = |label, variant| {
|
let sort_item = |label: String, variant| {
|
||||||
let key = find_key(&Action::ToggleSort(variant));
|
let entry = menu::Entry::new(label, TabAction(Action::ToggleSort(variant)));
|
||||||
let leading: Element<'a, tab::Message> = if sort_name == variant {
|
menu::Item::Entry(if sort_name == variant {
|
||||||
let icon_name = if sort_direction {
|
let icon_name = if sort_direction {
|
||||||
"view-sort-ascending-symbolic"
|
"view-sort-ascending-symbolic"
|
||||||
} else {
|
} else {
|
||||||
"view-sort-descending-symbolic"
|
"view-sort-descending-symbolic"
|
||||||
};
|
};
|
||||||
widget::icon::from_name(icon_name).size(14).into()
|
entry.icon(widget::icon::from_name(icon_name).size(14).handle())
|
||||||
} else {
|
} else {
|
||||||
space::horizontal().width(Length::Fixed(14.0)).into()
|
entry.reserve_icon()
|
||||||
};
|
})
|
||||||
menu_button!(
|
|
||||||
leading,
|
|
||||||
space::horizontal().width(Length::Fixed(theme::spacing().space_xxs.into())),
|
|
||||||
text::body(label),
|
|
||||||
space::horizontal(),
|
|
||||||
text::body(key).class(theme::Text::Custom(key_style))
|
|
||||||
)
|
|
||||||
.on_press(tab::Message::ContextAction(Action::ToggleSort(variant)))
|
|
||||||
.into()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut selected_dir = 0;
|
let mut selected_dir = 0;
|
||||||
|
|
@ -174,8 +119,8 @@ pub fn context_menu<'a>(
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, action)| action.matches_selection(selected, selected_dir))
|
.filter(|(_, action)| action.matches_selection(selected, selected_dir))
|
||||||
.map(|(i, action)| menu_item(action.name.clone(), Action::RunContextAction(i)).into())
|
.map(|(i, action)| menu_item(action.name.clone(), Action::RunContextAction(i)))
|
||||||
.collect::<Vec<Element<'a, tab::Message>>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
// Parse the desktop entry if it is the only selection
|
// Parse the desktop entry if it is the only selection
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
|
|
@ -190,7 +135,7 @@ pub fn context_menu<'a>(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut children: Vec<Element<_>> = Vec::new();
|
let mut children: Vec<menu::Item<TabAction, String>> = Vec::new();
|
||||||
match (&tab.mode, &tab.location) {
|
match (&tab.mode, &tab.location) {
|
||||||
(
|
(
|
||||||
tab::Mode::App | tab::Mode::Desktop,
|
tab::Mode::App | tab::Mode::Desktop,
|
||||||
|
|
@ -202,108 +147,114 @@ pub fn context_menu<'a>(
|
||||||
| Location::Network(_, _, Some(_)),
|
| Location::Network(_, _, Some(_)),
|
||||||
) => {
|
) => {
|
||||||
if selected_trash_only {
|
if selected_trash_only {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open));
|
||||||
if !Trash::is_empty() {
|
if !Trash::is_empty() {
|
||||||
children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into());
|
children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash));
|
||||||
}
|
}
|
||||||
} else if let Some(_entry) = selected_desktop_entry {
|
} else if let Some(entry) = selected_desktop_entry {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open));
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
{
|
{
|
||||||
children.extend(_entry.desktop_actions.into_iter().enumerate().map(
|
children.extend(
|
||||||
|(i, action)| menu_item(action.name, Action::ExecEntryAction(i)).into(),
|
entry
|
||||||
));
|
.desktop_actions
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, action)| menu_item(action.name, Action::ExecEntryAction(i))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
children
|
children.push(menu_item(fl!("edit-desktop-entry"), Action::EditDesktopEntry));
|
||||||
.push(menu_item(fl!("edit-desktop-entry"), Action::EditDesktopEntry).into());
|
children.push(menu::Item::Divider);
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu_item(fl!("rename"), Action::Rename));
|
||||||
children.push(menu_item(fl!("rename"), Action::Rename).into());
|
children.push(menu_item(fl!("cut"), Action::Cut));
|
||||||
children.push(menu_item(fl!("cut"), Action::Cut).into());
|
|
||||||
if modifiers.shift() && !modifiers.control() {
|
if modifiers.shift() && !modifiers.control() {
|
||||||
children.push(menu_item(fl!("copy-path"), Action::CopyPath).into());
|
children.push(menu_item(fl!("copy-path"), Action::CopyPath));
|
||||||
} else {
|
} else {
|
||||||
children.push(menu_item(fl!("copy"), Action::Copy).into());
|
children.push(menu_item(fl!("copy"), Action::Copy));
|
||||||
}
|
}
|
||||||
// Should this simply bypass trash and remove the shortcut?
|
// Should this simply bypass trash and remove the shortcut?
|
||||||
children.push(menu_item(fl!("move-to-trash"), Action::Delete).into());
|
children.push(menu_item(fl!("move-to-trash"), Action::Delete));
|
||||||
let action_items = context_action_items(selected, selected_dir);
|
let action_items = context_action_items(selected, selected_dir);
|
||||||
if !action_items.is_empty() {
|
if !action_items.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.extend(action_items);
|
children.extend(action_items);
|
||||||
}
|
}
|
||||||
} else if selected > 0 {
|
} else if selected > 0 {
|
||||||
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open));
|
||||||
}
|
}
|
||||||
if selected == 1 {
|
if selected == 1 {
|
||||||
children.push(menu_item(fl!("menu-open-with"), Action::OpenWith).into());
|
children.push(menu_item(fl!("menu-open-with"), Action::OpenWith));
|
||||||
if selected_dir == 1 {
|
if selected_dir == 1 {
|
||||||
children
|
children.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal));
|
||||||
.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tab.location.is_recents() || matches!(tab.location, Location::Search(..)) {
|
if tab.location.is_recents() || matches!(tab.location, Location::Search(..)) {
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("open-item-location"), Action::OpenItemLocation).into(),
|
fl!("open-item-location"),
|
||||||
);
|
Action::OpenItemLocation,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
// All selected items are directories
|
// All selected items are directories
|
||||||
if selected == selected_dir && matches!(tab.mode, tab::Mode::App) {
|
if selected == selected_dir && matches!(tab.mode, tab::Mode::App) {
|
||||||
children.push(menu_item(fl!("open-in-new-tab"), Action::OpenInNewTab).into());
|
children.push(menu_item(fl!("open-in-new-tab"), Action::OpenInNewTab));
|
||||||
children
|
children.push(menu_item(
|
||||||
.push(menu_item(fl!("open-in-new-window"), Action::OpenInNewWindow).into());
|
fl!("open-in-new-window"),
|
||||||
|
Action::OpenInNewWindow,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let action_items = context_action_items(selected, selected_dir);
|
let action_items = context_action_items(selected, selected_dir);
|
||||||
if !action_items.is_empty() {
|
if !action_items.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.extend(action_items);
|
children.extend(action_items);
|
||||||
}
|
}
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
if selected_mount_point == 0 {
|
if selected_mount_point == 0 {
|
||||||
children.push(menu_item(fl!("rename"), Action::Rename).into());
|
children.push(menu_item(fl!("rename"), Action::Rename));
|
||||||
children.push(menu_item(fl!("cut"), Action::Cut).into());
|
children.push(menu_item(fl!("cut"), Action::Cut));
|
||||||
}
|
}
|
||||||
if modifiers.shift() && !modifiers.control() {
|
if modifiers.shift() && !modifiers.control() {
|
||||||
children.push(menu_item(fl!("copy-path"), Action::CopyPath).into());
|
children.push(menu_item(fl!("copy-path"), Action::CopyPath));
|
||||||
} else {
|
} else {
|
||||||
children.push(menu_item(fl!("copy"), Action::Copy).into());
|
children.push(menu_item(fl!("copy"), Action::Copy));
|
||||||
}
|
}
|
||||||
if selected_mount_point == 0 {
|
if selected_mount_point == 0 {
|
||||||
children.push(menu_item(fl!("move-to"), Action::MoveTo).into());
|
children.push(menu_item(fl!("move-to"), Action::MoveTo));
|
||||||
}
|
}
|
||||||
children.push(menu_item(fl!("copy-to"), Action::CopyTo).into());
|
children.push(menu_item(fl!("copy-to"), Action::CopyTo));
|
||||||
|
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
let supported_archive_types = crate::archive::SUPPORTED_ARCHIVE_TYPES;
|
let supported_archive_types = crate::archive::SUPPORTED_ARCHIVE_TYPES;
|
||||||
selected_types.retain(|t| supported_archive_types.iter().copied().all(|m| *t != m));
|
selected_types.retain(|t| supported_archive_types.iter().copied().all(|m| *t != m));
|
||||||
if selected_types.is_empty() {
|
if selected_types.is_empty() {
|
||||||
children.push(menu_item(fl!("extract-here"), Action::ExtractHere).into());
|
children.push(menu_item(fl!("extract-here"), Action::ExtractHere));
|
||||||
children.push(menu_item(fl!("extract-to"), Action::ExtractTo).into());
|
children.push(menu_item(fl!("extract-to"), Action::ExtractTo));
|
||||||
}
|
}
|
||||||
children.push(menu_item(fl!("compress"), Action::Compress).into());
|
children.push(menu_item(fl!("compress"), Action::Compress));
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
|
|
||||||
//TODO: Print?
|
//TODO: Print?
|
||||||
children.push(menu_item(fl!("show-details"), Action::Preview).into());
|
children.push(menu_item(fl!("show-details"), Action::Preview));
|
||||||
if any_trash_item {
|
if any_trash_item {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("restore-from-trash"), Action::RestoreFromTrash).into(),
|
fl!("restore-from-trash"),
|
||||||
);
|
Action::RestoreFromTrash,
|
||||||
children.push(divider::horizontal::light().into());
|
));
|
||||||
children.push(menu_item(fl!("delete-permanently"), Action::Delete).into());
|
children.push(menu::Item::Divider);
|
||||||
|
children.push(menu_item(fl!("delete-permanently"), Action::Delete));
|
||||||
} else {
|
} else {
|
||||||
if matches!(tab.mode, tab::Mode::App) {
|
if matches!(tab.mode, tab::Mode::App) {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children
|
children.push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar));
|
||||||
.push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar).into());
|
|
||||||
}
|
}
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
if tab.location.is_recents() {
|
if tab.location.is_recents() {
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("remove-from-recents"), Action::RemoveFromRecents).into(),
|
fl!("remove-from-recents"),
|
||||||
);
|
Action::RemoveFromRecents,
|
||||||
children.push(divider::horizontal::light().into());
|
));
|
||||||
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
if selected_mount_point == 0 {
|
if selected_mount_point == 0 {
|
||||||
if modifiers.shift() && !modifiers.control() {
|
if modifiers.shift() && !modifiers.control() {
|
||||||
|
|
@ -312,55 +263,59 @@ pub fn context_menu<'a>(
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
children.push(menu_item(fl!("move-to-trash"), Action::Delete).into());
|
children.push(menu_item(fl!("move-to-trash"), Action::Delete));
|
||||||
}
|
}
|
||||||
} else if selected == 1 {
|
} else if selected == 1 {
|
||||||
children.push(menu_item(fl!("eject"), Action::Eject).into());
|
children.push(menu_item(fl!("eject"), Action::Eject));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//TODO: need better designs for menu with no selection
|
//TODO: need better designs for menu with no selection
|
||||||
//TODO: have things like properties but they apply to the folder?
|
//TODO: have things like properties but they apply to the folder?
|
||||||
if tab.location != Location::Recents {
|
if tab.location != Location::Recents {
|
||||||
children.push(menu_item(fl!("new-folder"), Action::NewFolder).into());
|
children.push(menu_item(fl!("new-folder"), Action::NewFolder));
|
||||||
children.push(menu_item(fl!("new-file"), Action::NewFile).into());
|
children.push(menu_item(fl!("new-file"), Action::NewFile));
|
||||||
children.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal).into());
|
children.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal));
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
if tab.mode.multiple() {
|
if tab.mode.multiple() {
|
||||||
children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
|
children.push(menu_item(fl!("select-all"), Action::SelectAll));
|
||||||
}
|
}
|
||||||
if can_paste {
|
if can_paste {
|
||||||
children.push(menu_item(fl!("paste"), Action::Paste).into());
|
children.push(menu_item(fl!("paste"), Action::Paste));
|
||||||
} else {
|
} else {
|
||||||
children.push(menu_item_disabled(fl!("paste"), Action::Paste).into());
|
children.push(menu_item_disabled(fl!("paste"), Action::Paste));
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: only show if cosmic-settings is found?
|
//TODO: only show if cosmic-settings is found?
|
||||||
if matches!(tab.mode, tab::Mode::Desktop) {
|
if matches!(tab.mode, tab::Mode::Desktop) {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("change-wallpaper"), Action::CosmicSettingsWallpaper).into(),
|
fl!("change-wallpaper"),
|
||||||
);
|
Action::CosmicSettingsWallpaper,
|
||||||
children.push(
|
));
|
||||||
menu_item(fl!("desktop-appearance"), Action::CosmicSettingsDesktop).into(),
|
children.push(menu_item(
|
||||||
);
|
fl!("desktop-appearance"),
|
||||||
children.push(
|
Action::CosmicSettingsDesktop,
|
||||||
menu_item(fl!("display-settings"), Action::CosmicSettingsDisplays).into(),
|
));
|
||||||
);
|
children.push(menu_item(
|
||||||
|
fl!("display-settings"),
|
||||||
|
Action::CosmicSettingsDisplays,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
// TODO: Nested menu
|
// TODO: Nested menu
|
||||||
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
||||||
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
||||||
children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size));
|
children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size));
|
||||||
if matches!(tab.location, Location::Desktop(..)) {
|
if matches!(tab.location, Location::Desktop(..)) {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("desktop-view-options"), Action::DesktopViewOptions).into(),
|
fl!("desktop-view-options"),
|
||||||
);
|
Action::DesktopViewOptions,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,24 +330,25 @@ pub fn context_menu<'a>(
|
||||||
) => {
|
) => {
|
||||||
if selected > 0 {
|
if selected > 0 {
|
||||||
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open));
|
||||||
}
|
}
|
||||||
if matches!(tab.location, Location::Search(..)) || tab.location.is_recents() {
|
if matches!(tab.location, Location::Search(..)) || tab.location.is_recents() {
|
||||||
children.push(
|
children.push(menu_item(
|
||||||
menu_item(fl!("open-item-location"), Action::OpenItemLocation).into(),
|
fl!("open-item-location"),
|
||||||
);
|
Action::OpenItemLocation,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children.push(menu_item(fl!("show-details"), Action::Preview).into());
|
children.push(menu_item(fl!("show-details"), Action::Preview));
|
||||||
} else {
|
} else {
|
||||||
if dialog_kind.save() {
|
if dialog_kind.save() {
|
||||||
children.push(menu_item(fl!("new-folder"), Action::NewFolder).into());
|
children.push(menu_item(fl!("new-folder"), Action::NewFolder));
|
||||||
}
|
}
|
||||||
if tab.mode.multiple() {
|
if tab.mode.multiple() {
|
||||||
children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
|
children.push(menu_item(fl!("select-all"), Action::SelectAll));
|
||||||
}
|
}
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
||||||
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
||||||
|
|
@ -402,14 +358,14 @@ pub fn context_menu<'a>(
|
||||||
(_, Location::Network(..)) => {
|
(_, Location::Network(..)) => {
|
||||||
if selected > 0 {
|
if selected > 0 {
|
||||||
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
||||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
children.push(menu_item(fl!("open"), Action::Open));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if tab.mode.multiple() {
|
if tab.mode.multiple() {
|
||||||
children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
|
children.push(menu_item(fl!("select-all"), Action::SelectAll));
|
||||||
}
|
}
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
||||||
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified));
|
||||||
|
|
@ -418,24 +374,26 @@ pub fn context_menu<'a>(
|
||||||
}
|
}
|
||||||
(_, Location::Trash | Location::Search(SearchLocation::Trash, ..)) => {
|
(_, Location::Trash | Location::Search(SearchLocation::Trash, ..)) => {
|
||||||
if tab.mode.multiple() {
|
if tab.mode.multiple() {
|
||||||
children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
|
children.push(menu_item(fl!("select-all"), Action::SelectAll));
|
||||||
}
|
}
|
||||||
if !Trash::is_empty() {
|
if !Trash::is_empty() {
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into());
|
children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash));
|
||||||
}
|
}
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
}
|
}
|
||||||
if selected > 0 {
|
if selected > 0 {
|
||||||
children.push(menu_item(fl!("show-details"), Action::Preview).into());
|
children.push(menu_item(fl!("show-details"), Action::Preview));
|
||||||
children.push(divider::horizontal::light().into());
|
children.push(menu::Item::Divider);
|
||||||
children
|
children.push(menu_item(
|
||||||
.push(menu_item(fl!("restore-from-trash"), Action::RestoreFromTrash).into());
|
fl!("restore-from-trash"),
|
||||||
children.push(divider::horizontal::light().into());
|
Action::RestoreFromTrash,
|
||||||
children.push(menu_item(fl!("delete-permanently"), Action::Delete).into());
|
));
|
||||||
|
children.push(menu::Item::Divider);
|
||||||
|
children.push(menu_item(fl!("delete-permanently"), Action::Delete));
|
||||||
} else {
|
} else {
|
||||||
// TODO: Nested menu
|
// TODO: Nested menu
|
||||||
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name));
|
||||||
|
|
@ -445,26 +403,11 @@ pub fn context_menu<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container(column::with_children(children))
|
let key_binds: HashMap<KeyBind, TabAction> = key_binds
|
||||||
.padding(1)
|
.iter()
|
||||||
//TODO: move style to libcosmic
|
.map(|(key_bind, action)| (key_bind.clone(), TabAction(*action)))
|
||||||
.style(|theme| {
|
.collect();
|
||||||
let cosmic = theme.cosmic();
|
menu::items(&key_binds, children)
|
||||||
let component = &cosmic.background(false).component;
|
|
||||||
container::Style {
|
|
||||||
icon_color: Some(component.on.into()),
|
|
||||||
text_color: Some(component.on.into()),
|
|
||||||
background: Some(Background::Color(component.base.into())),
|
|
||||||
border: Border {
|
|
||||||
radius: cosmic.radius_s().map(|x| x + 1.0).into(),
|
|
||||||
width: 1.0,
|
|
||||||
color: component.divider.into(),
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.width(Length::Fixed(360.0))
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dialog_menu(
|
pub fn dialog_menu(
|
||||||
|
|
@ -813,50 +756,33 @@ pub fn menu_bar<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn location_context_menu<'a>(ancestor_index: usize) -> Element<'a, tab::Message> {
|
pub fn location_context_menu(ancestor_index: usize) -> Vec<menu::Tree<tab::Message>> {
|
||||||
//TODO: only add some of these when in App mode
|
//TODO: only add some of these when in App mode
|
||||||
let children = [
|
menu::items(
|
||||||
menu_button!(text::body(fl!("open-in-new-tab")))
|
&HashMap::new(),
|
||||||
.on_press(tab::Message::LocationMenuAction(
|
vec![
|
||||||
|
menu::Item::Button(
|
||||||
|
fl!("open-in-new-tab"),
|
||||||
|
None,
|
||||||
LocationMenuAction::OpenInNewTab(ancestor_index),
|
LocationMenuAction::OpenInNewTab(ancestor_index),
|
||||||
))
|
),
|
||||||
.into(),
|
menu::Item::Button(
|
||||||
menu_button!(text::body(fl!("open-in-new-window")))
|
fl!("open-in-new-window"),
|
||||||
.on_press(tab::Message::LocationMenuAction(
|
None,
|
||||||
LocationMenuAction::OpenInNewWindow(ancestor_index),
|
LocationMenuAction::OpenInNewWindow(ancestor_index),
|
||||||
))
|
),
|
||||||
.into(),
|
menu::Item::Divider,
|
||||||
divider::horizontal::light().into(),
|
menu::Item::Button(
|
||||||
menu_button!(text::body(fl!("show-details")))
|
fl!("show-details"),
|
||||||
.on_press(tab::Message::LocationMenuAction(
|
None,
|
||||||
LocationMenuAction::Preview(ancestor_index),
|
LocationMenuAction::Preview(ancestor_index),
|
||||||
))
|
),
|
||||||
.into(),
|
menu::Item::Divider,
|
||||||
divider::horizontal::light().into(),
|
menu::Item::Button(
|
||||||
menu_button!(text::body(fl!("add-to-sidebar")))
|
fl!("add-to-sidebar"),
|
||||||
.on_press(tab::Message::LocationMenuAction(
|
None,
|
||||||
LocationMenuAction::AddToSidebar(ancestor_index),
|
LocationMenuAction::AddToSidebar(ancestor_index),
|
||||||
))
|
),
|
||||||
.into(),
|
],
|
||||||
];
|
)
|
||||||
|
|
||||||
container(column::with_children(children))
|
|
||||||
.padding(1)
|
|
||||||
.style(|theme| {
|
|
||||||
let cosmic = theme.cosmic();
|
|
||||||
let component = &cosmic.background(false).component;
|
|
||||||
container::Style {
|
|
||||||
icon_color: Some(component.on.into()),
|
|
||||||
text_color: Some(component.on.into()),
|
|
||||||
background: Some(Background::Color(component.base.into())),
|
|
||||||
border: Border {
|
|
||||||
radius: cosmic.radius_s().map(|x| x + 1.0).into(),
|
|
||||||
width: 1.0,
|
|
||||||
color: component.divider.into(),
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.width(Length::Fixed(360.0))
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ use crate::tab::{self, ChecksumState, DirSize, ItemMetadata, ItemThumbnail, Loca
|
||||||
|
|
||||||
const TARGET_URI_ATTRIBUTE: &str = "standard::target-uri";
|
const TARGET_URI_ATTRIBUTE: &str = "standard::target-uri";
|
||||||
|
|
||||||
|
// Attributes requested when listing a network directory.
|
||||||
|
const SCAN_ATTRIBUTES: &str = "standard::name,\
|
||||||
|
standard::display-name,\
|
||||||
|
standard::type,\
|
||||||
|
standard::size,\
|
||||||
|
standard::icon,\
|
||||||
|
standard::is-hidden,\
|
||||||
|
time::modified";
|
||||||
|
|
||||||
fn resolve_uri(uri: &str) -> (String, gio::File) {
|
fn resolve_uri(uri: &str) -> (String, gio::File) {
|
||||||
let file = gio::File::for_uri(uri);
|
let file = gio::File::for_uri(uri);
|
||||||
// Resolve the target-uri if it exists
|
// Resolve the target-uri if it exists
|
||||||
|
|
@ -119,9 +128,27 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
|
||||||
Box::from([])
|
Box::from([])
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// `filesystem::remote` belongs to the filesystem namespace, which `enumerate_children`
|
||||||
|
// never fills in, so it has to be queried once for the directory being listed.
|
||||||
|
let remote = file
|
||||||
|
.query_filesystem_info(
|
||||||
|
gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE,
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)
|
||||||
|
.map(|info| info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE))
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
log::warn!("failed to get GIO filesystem info for {uri}: {err}");
|
||||||
|
// Assume remote, so per-entry work is skipped rather than retried
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
for info_res in file
|
for info_res in file
|
||||||
.enumerate_children("*", gio::FileQueryInfoFlags::NONE, gio::Cancellable::NONE)
|
.enumerate_children(
|
||||||
|
SCAN_ATTRIBUTES,
|
||||||
|
gio::FileQueryInfoFlags::NONE,
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
)
|
||||||
.map_err(err_str)?
|
.map_err(err_str)?
|
||||||
{
|
{
|
||||||
let info = info_res.map_err(err_str)?;
|
let info = info_res.map_err(err_str)?;
|
||||||
|
|
@ -133,13 +160,17 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
|
||||||
//TODO: what is the best way to resolve shortcuts?
|
//TODO: what is the best way to resolve shortcuts?
|
||||||
let location = Location::Network(uri, display_name.clone(), file.child(&name).path());
|
let location = Location::Network(uri, display_name.clone(), file.child(&name).path());
|
||||||
|
|
||||||
let metadata = if !force_dir && !info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE) {
|
let metadata = if force_dir {
|
||||||
|
ItemMetadata::SimpleDir { entries: 0 }
|
||||||
|
} else {
|
||||||
let mtime = info.attribute_uint64(gio::FILE_ATTRIBUTE_TIME_MODIFIED);
|
let mtime = info.attribute_uint64(gio::FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
let is_dir = matches!(info.file_type(), gio::FileType::Directory);
|
let is_dir = matches!(info.file_type(), gio::FileType::Directory);
|
||||||
let size_opt = (!is_dir).then_some(info.size() as u64);
|
let size_opt = (!is_dir).then_some(info.size() as u64);
|
||||||
let mut children_opt = None;
|
let mut children_opt = None;
|
||||||
|
|
||||||
if is_dir {
|
// Counting children costs a directory listing per entry, which is far too
|
||||||
|
// expensive on a remote filesystem
|
||||||
|
if is_dir && !remote {
|
||||||
if let Some(path) = file.child(&name).path() {
|
if let Some(path) = file.child(&name).path() {
|
||||||
//TODO: calculate children in the background (and make it cancellable?)
|
//TODO: calculate children in the background (and make it cancellable?)
|
||||||
match std::fs::read_dir(&path) {
|
match std::fs::read_dir(&path) {
|
||||||
|
|
@ -159,9 +190,8 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
|
||||||
mtime,
|
mtime,
|
||||||
size_opt,
|
size_opt,
|
||||||
children_opt,
|
children_opt,
|
||||||
|
is_dir,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ItemMetadata::SimpleDir { entries: 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) = {
|
let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) = {
|
||||||
|
|
@ -659,7 +689,7 @@ impl Mounter for Gvfs {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn network_drive(&self, uri: String) -> Task<()> {
|
fn network_drive(&self, uri: String) -> Task<bool> {
|
||||||
let command_tx = self.command_tx.clone();
|
let command_tx = self.command_tx.clone();
|
||||||
Task::perform(
|
Task::perform(
|
||||||
async move {
|
async move {
|
||||||
|
|
@ -668,9 +698,15 @@ impl Mounter for Gvfs {
|
||||||
command_tx.send(Cmd::NetworkDrive(uri, res_tx)).unwrap();
|
command_tx.send(Cmd::NetworkDrive(uri, res_tx)).unwrap();
|
||||||
res_rx.await
|
res_rx.await
|
||||||
},
|
},
|
||||||
|x| {
|
|result| match result {
|
||||||
if let Err(err) = x {
|
Ok(Ok(())) => true,
|
||||||
|
Ok(Err(err)) => {
|
||||||
log::error!("{err:?}");
|
log::error!("{err:?}");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("{err:?}");
|
||||||
|
false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ pub trait Mounter: Send + Sync {
|
||||||
fn items(&self, sizes: IconSizes) -> Option<MounterItems>;
|
fn items(&self, sizes: IconSizes) -> Option<MounterItems>;
|
||||||
//TODO: send result
|
//TODO: send result
|
||||||
fn mount(&self, item: MounterItem) -> Task<()>;
|
fn mount(&self, item: MounterItem) -> Task<()>;
|
||||||
fn network_drive(&self, uri: String) -> Task<()>;
|
fn network_drive(&self, uri: String) -> Task<bool>;
|
||||||
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>>;
|
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>>;
|
||||||
fn dir_info(&self, uri: &str) -> Option<(String, String, Option<PathBuf>)>;
|
fn dir_info(&self, uri: &str) -> Option<(String, String, Option<PathBuf>)>;
|
||||||
fn unmount(&self, item: MounterItem) -> Task<()>;
|
fn unmount(&self, item: MounterItem) -> Task<()>;
|
||||||
|
|
|
||||||
|
|
@ -214,8 +214,9 @@ impl<'a, Message, F> OnAutoScroll<'a, Message> for F where F: Fn(Option<f32>) ->
|
||||||
pub trait OnMouseButton<'a, Message>: Fn(Option<Point>) -> Message + 'a {}
|
pub trait OnMouseButton<'a, Message>: Fn(Option<Point>) -> Message + 'a {}
|
||||||
impl<'a, Message, F> OnMouseButton<'a, Message> for F where F: Fn(Option<Point>) -> Message + 'a {}
|
impl<'a, Message, F> OnMouseButton<'a, Message> for F where F: Fn(Option<Point>) -> Message + 'a {}
|
||||||
|
|
||||||
pub trait OnDrag<'a, Message>: Fn(Option<Rectangle>) -> Message + 'a {}
|
pub trait OnDrag<'a, Message>: Fn(Option<Rectangle>) -> Option<Message> + 'a {}
|
||||||
impl<'a, Message, F> OnDrag<'a, Message> for F where F: Fn(Option<Rectangle>) -> Message + 'a {}
|
impl<'a, Message, F> OnDrag<'a, Message> for F where F: Fn(Option<Rectangle>) -> Option<Message> + 'a
|
||||||
|
{}
|
||||||
|
|
||||||
pub trait OnResize<'a, Message>: Fn(Rectangle) -> Message + 'a {}
|
pub trait OnResize<'a, Message>: Fn(Rectangle) -> Message + 'a {}
|
||||||
impl<'a, Message, F> OnResize<'a, Message> for F where F: Fn(Rectangle) -> Message + 'a {}
|
impl<'a, Message, F> OnResize<'a, Message> for F where F: Fn(Rectangle) -> Message + 'a {}
|
||||||
|
|
@ -563,6 +564,16 @@ fn update<Message: Clone>(
|
||||||
state.last_position = position_in;
|
state.last_position = position_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if state.drag_initiated.is_some()
|
||||||
|
&& matches!(
|
||||||
|
event,
|
||||||
|
Event::Mouse(mouse::Event::CursorMoved { .. })
|
||||||
|
| Event::Touch(touch::Event::FingerMoved { .. })
|
||||||
|
)
|
||||||
|
{
|
||||||
|
shell.request_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
if let Event::Mouse(mouse::Event::CursorMoved { position }) = event {
|
if let Event::Mouse(mouse::Event::CursorMoved { position }) = event {
|
||||||
let virtual_position = Point::new(
|
let virtual_position = Point::new(
|
||||||
viewport.x - layout_bounds.x + position.x,
|
viewport.x - layout_bounds.x + position.x,
|
||||||
|
|
@ -639,6 +650,7 @@ fn update<Message: Clone>(
|
||||||
{
|
{
|
||||||
state.drag_initiated = None;
|
state.drag_initiated = None;
|
||||||
state.prev_click = None;
|
state.prev_click = None;
|
||||||
|
shell.request_redraw();
|
||||||
if let Some(message) = widget.on_drag_end.as_ref() {
|
if let Some(message) = widget.on_drag_end.as_ref() {
|
||||||
shell.publish(message(cursor.position_in(layout_bounds)));
|
shell.publish(message(cursor.position_in(layout_bounds)));
|
||||||
}
|
}
|
||||||
|
|
@ -658,7 +670,9 @@ fn update<Message: Clone>(
|
||||||
state.prev_click = None;
|
state.prev_click = None;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.drag_initiated = None;
|
if state.drag_initiated.take().is_some() {
|
||||||
|
shell.request_redraw();
|
||||||
|
}
|
||||||
if let Some(message) = widget.on_release.as_ref() {
|
if let Some(message) = widget.on_release.as_ref() {
|
||||||
shell.publish(message(cursor.position_in(layout_bounds)));
|
shell.publish(message(cursor.position_in(layout_bounds)));
|
||||||
|
|
||||||
|
|
@ -785,12 +799,13 @@ fn update<Message: Clone>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((message, drag_rect)) = widget.on_drag.as_ref().zip(state.drag_rect(cursor)) {
|
if let Some((message, drag_rect)) = widget.on_drag.as_ref().zip(state.drag_rect(cursor)) {
|
||||||
shell.publish(message(drag_rect.intersection(&layout_bounds).map(
|
let rect_opt = drag_rect.intersection(&layout_bounds).map(|mut rect| {
|
||||||
|mut rect| {
|
rect.x -= layout_bounds.x;
|
||||||
rect.x -= layout_bounds.x;
|
rect.y -= layout_bounds.y;
|
||||||
rect.y -= layout_bounds.y;
|
rect
|
||||||
rect
|
});
|
||||||
},
|
if let Some(message) = message(rect_opt) {
|
||||||
)));
|
shell.publish(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ impl Op {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (from_file, metadata, to_file) = cosmic::iced::futures::join!(
|
let (from_file_open_result, metadata, to_file_open_result) = cosmic::iced::futures::join!(
|
||||||
async {
|
async {
|
||||||
compio::fs::OpenOptions::new()
|
compio::fs::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
|
|
@ -470,12 +470,30 @@ impl Op {
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(&self.to)
|
.open(&self.to)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to open {} for writing", self.to.display()))
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let from_file = from_file?;
|
let from_file = from_file_open_result?;
|
||||||
let mut to_file = to_file?;
|
|
||||||
|
let mut to_file = match to_file_open_result {
|
||||||
|
Ok(file) => file,
|
||||||
|
#[cfg(not(feature = "gvfs"))]
|
||||||
|
Err(why) => {
|
||||||
|
_ = from_file.close().await;
|
||||||
|
return Err(why)
|
||||||
|
.with_context(|| format!("failed to open {} for writing", self.to.display()))
|
||||||
|
.map_err(Into::into);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "gvfs")]
|
||||||
|
Err(_why) => {
|
||||||
|
_ = from_file.close().await;
|
||||||
|
return self
|
||||||
|
.gio_file_copy(ctx, progress)
|
||||||
|
.await
|
||||||
|
.map(|()| true)
|
||||||
|
.map_err(Into::into);
|
||||||
|
}
|
||||||
|
};
|
||||||
progress.total_bytes = metadata.as_ref().map(|m| m.len());
|
progress.total_bytes = metadata.as_ref().map(|m| m.len());
|
||||||
(ctx.on_progress)(self, &progress);
|
(ctx.on_progress)(self, &progress);
|
||||||
|
|
||||||
|
|
|
||||||
538
src/tab.rs
538
src/tab.rs
|
|
@ -181,7 +181,9 @@ fn button_appearance(
|
||||||
appearance.icon_color = Some(Color::from(cosmic.on_bg_component_color()));
|
appearance.icon_color = Some(Color::from(cosmic.on_bg_component_color()));
|
||||||
appearance.text_color = Some(Color::from(cosmic.on_bg_component_color()));
|
appearance.text_color = Some(Color::from(cosmic.on_bg_component_color()));
|
||||||
if cut {
|
if cut {
|
||||||
appearance.text_color = Some(Color::from(cosmic.background(false).component.on_disabled));
|
appearance.text_color = Some(Color::from(
|
||||||
|
cosmic.background(theme.transparent).component.on_disabled,
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
appearance.text_color = Some(Color::from(cosmic.on_bg_component_color()));
|
appearance.text_color = Some(Color::from(cosmic.on_bg_component_color()));
|
||||||
}
|
}
|
||||||
|
|
@ -192,12 +194,16 @@ fn button_appearance(
|
||||||
appearance.background = Some(Color::from(cosmic.bg_color()).into());
|
appearance.background = Some(Color::from(cosmic.bg_color()).into());
|
||||||
appearance.icon_color = Some(Color::from(cosmic.on_bg_color()));
|
appearance.icon_color = Some(Color::from(cosmic.on_bg_color()));
|
||||||
if cut {
|
if cut {
|
||||||
appearance.text_color = Some(Color::from(cosmic.background(false).component.disabled));
|
appearance.text_color = Some(Color::from(
|
||||||
|
cosmic.background(theme.transparent).component.disabled,
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
appearance.text_color = Some(Color::from(cosmic.on_bg_color()));
|
appearance.text_color = Some(Color::from(cosmic.on_bg_color()));
|
||||||
}
|
}
|
||||||
} else if cut {
|
} else if cut {
|
||||||
appearance.text_color = Some(Color::from(cosmic.background(false).component.on_disabled));
|
appearance.text_color = Some(Color::from(
|
||||||
|
cosmic.background(theme.transparent).component.on_disabled,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if focused && accent {
|
if focused && accent {
|
||||||
appearance.outline_width = 1.0;
|
appearance.outline_width = 1.0;
|
||||||
|
|
@ -452,7 +458,9 @@ impl<'a> FormatTime<'a> {
|
||||||
|
|
||||||
impl Display for FormatTime<'_> {
|
impl Display for FormatTime<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let zoned = jiff::Zoned::try_from(self.time).unwrap();
|
let Ok(zoned) = jiff::Zoned::try_from(self.time) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
let now = jiff::Zoned::now();
|
let now = jiff::Zoned::now();
|
||||||
let icu_datetime = DateTime::convert_from(zoned.datetime());
|
let icu_datetime = DateTime::convert_from(zoned.datetime());
|
||||||
if zoned.date() == now.date() {
|
if zoned.date() == now.date() {
|
||||||
|
|
@ -655,6 +663,41 @@ fn display_name_for_file(path: &Path, name: &str, get_from_gvfs: bool, is_deskto
|
||||||
Item::display_name(name)
|
Item::display_name(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether a dir lives on a remote filesystem, according to GIO.
|
||||||
|
#[cfg(feature = "gvfs")]
|
||||||
|
fn gvfs_dir_is_remote(dir: &Path) -> bool {
|
||||||
|
static REMOTE_CACHE: LazyLock<RwLock<FxHashMap<PathBuf, bool>>> =
|
||||||
|
LazyLock::new(|| RwLock::new(FxHashMap::default()));
|
||||||
|
|
||||||
|
if let Some(remote) = REMOTE_CACHE.read().unwrap().get(dir) {
|
||||||
|
return *remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
let remote = match gio::prelude::FileExt::query_filesystem_info(
|
||||||
|
&gio::File::for_path(dir),
|
||||||
|
gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE,
|
||||||
|
gio::Cancellable::NONE,
|
||||||
|
) {
|
||||||
|
Ok(info) => info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE),
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"failed to get GIO filesystem info for {}: {}",
|
||||||
|
dir.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
//Assume remote so that the "expensive tasks" are rather skipped then actually executed.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
REMOTE_CACHE
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert(dir.to_path_buf(), remote);
|
||||||
|
remote
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gvfs")]
|
#[cfg(feature = "gvfs")]
|
||||||
pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconSizes) -> Item {
|
pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconSizes) -> Item {
|
||||||
let file_name = file_info
|
let file_name = file_info
|
||||||
|
|
@ -662,7 +705,7 @@ pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconS
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let mtime = file_info.attribute_uint64(gio::FILE_ATTRIBUTE_TIME_MODIFIED);
|
let mtime = file_info.attribute_uint64(gio::FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
let mut is_desktop = false;
|
let mut is_desktop = false;
|
||||||
let remote = file_info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE);
|
let remote = path.parent().is_none_or(gvfs_dir_is_remote);
|
||||||
let is_dir = matches!(file_info.file_type(), gio::FileType::Directory);
|
let is_dir = matches!(file_info.file_type(), gio::FileType::Directory);
|
||||||
|
|
||||||
let size_opt = (!is_dir).then_some(file_info.size() as u64);
|
let size_opt = (!is_dir).then_some(file_info.size() as u64);
|
||||||
|
|
@ -723,6 +766,7 @@ pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconS
|
||||||
mtime,
|
mtime,
|
||||||
size_opt,
|
size_opt,
|
||||||
children_opt,
|
children_opt,
|
||||||
|
is_dir,
|
||||||
},
|
},
|
||||||
hidden,
|
hidden,
|
||||||
image_dimensions: (!remote && mime.type_() == mime::IMAGE)
|
image_dimensions: (!remote && mime.type_() == mime::IMAGE)
|
||||||
|
|
@ -777,23 +821,7 @@ pub fn item_from_entry(
|
||||||
#[cfg(feature = "gvfs")]
|
#[cfg(feature = "gvfs")]
|
||||||
FsKind::Gvfs => {
|
FsKind::Gvfs => {
|
||||||
is_gvfs = true;
|
is_gvfs = true;
|
||||||
let file = gio::File::for_path(&path);
|
path.parent().is_none_or(gvfs_dir_is_remote)
|
||||||
|
|
||||||
match gio::prelude::FileExt::query_filesystem_info(
|
|
||||||
&file,
|
|
||||||
gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
) {
|
|
||||||
Ok(info) => info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE),
|
|
||||||
Err(err) => {
|
|
||||||
log::warn!(
|
|
||||||
"failed to get GIO filesystem info for {}: {}",
|
|
||||||
path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "gvfs"))]
|
#[cfg(not(feature = "gvfs"))]
|
||||||
FsKind::Gvfs => {
|
FsKind::Gvfs => {
|
||||||
|
|
@ -945,11 +973,24 @@ fn item_from_trash_child(
|
||||||
metadata: fs::Metadata,
|
metadata: fs::Metadata,
|
||||||
sizes: IconSizes,
|
sizes: IconSizes,
|
||||||
) -> Option<Item> {
|
) -> Option<Item> {
|
||||||
let original_path = crate::trash::original_path_for_trash_child(&path)?;
|
let Some(original_path) = crate::trash::original_path_for_trash_child(&path) else {
|
||||||
|
log::warn!(
|
||||||
|
"failed to resolve original path for trash item {}, skipping entry",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(original_parent) = original_path.parent() else {
|
||||||
|
log::warn!(
|
||||||
|
"trash item {} has no original parent, skipping entry",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
let entry = trash::TrashItem {
|
let entry = trash::TrashItem {
|
||||||
id: path.as_os_str().to_os_string(),
|
id: path.as_os_str().to_os_string(),
|
||||||
name: std::ffi::OsString::from(&name),
|
name: std::ffi::OsString::from(&name),
|
||||||
original_parent: original_path.parent()?.to_path_buf(),
|
original_parent: original_parent.to_path_buf(),
|
||||||
time_deleted: 0,
|
time_deleted: 0,
|
||||||
};
|
};
|
||||||
let size = if metadata.is_dir() {
|
let size = if metadata.is_dir() {
|
||||||
|
|
@ -1005,7 +1046,6 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
// gio crate expects a comma delimited string
|
// gio crate expects a comma delimited string
|
||||||
let attr_string = [
|
let attr_string = [
|
||||||
gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.as_str(),
|
gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.as_str(),
|
||||||
gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE.as_str(),
|
|
||||||
gio::FILE_ATTRIBUTE_TIME_MODIFIED.as_str(),
|
gio::FILE_ATTRIBUTE_TIME_MODIFIED.as_str(),
|
||||||
gio::FILE_ATTRIBUTE_STANDARD_SIZE.as_str(),
|
gio::FILE_ATTRIBUTE_STANDARD_SIZE.as_str(),
|
||||||
gio::FILE_ATTRIBUTE_STANDARD_TYPE.as_str(),
|
gio::FILE_ATTRIBUTE_STANDARD_TYPE.as_str(),
|
||||||
|
|
@ -1042,6 +1082,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
if !remote_scannable {
|
if !remote_scannable {
|
||||||
match fs::read_dir(tab_path) {
|
match fs::read_dir(tab_path) {
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
|
let trash = crate::trash::is_trash_path(tab_path);
|
||||||
items = entries
|
items = entries
|
||||||
.filter_map(|entry_res| {
|
.filter_map(|entry_res| {
|
||||||
let entry = entry_res
|
let entry = entry_res
|
||||||
|
|
@ -1082,7 +1123,6 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
|
||||||
})
|
})
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
let trash = crate::trash::is_trash_path(tab_path);
|
|
||||||
if trash {
|
if trash {
|
||||||
item_from_trash_child(path, name, metadata, sizes)
|
item_from_trash_child(path, name, metadata, sizes)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1717,11 +1757,11 @@ impl fmt::Debug for TaskWrapper {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Action(Action),
|
Action(Action),
|
||||||
|
Surface(cosmic::surface::Action<Message>),
|
||||||
AddNetworkDrive,
|
AddNetworkDrive,
|
||||||
AddToSidebar(PathBuf),
|
AddToSidebar(PathBuf),
|
||||||
AutoScroll(Option<f32>),
|
AutoScroll(Option<f32>),
|
||||||
ChangeLocation(String, Location, Option<Vec<PathBuf>>),
|
ChangeLocation(String, Location, Option<Vec<PathBuf>>),
|
||||||
ContextMenu(Option<Point>, Option<window::Id>),
|
|
||||||
Delete(Vec<PathBuf>),
|
Delete(Vec<PathBuf>),
|
||||||
DropFiles(PathBuf, ClipboardPaste),
|
DropFiles(PathBuf, ClipboardPaste),
|
||||||
ClearRecents,
|
ClearRecents,
|
||||||
|
|
@ -1752,9 +1792,9 @@ pub enum Message {
|
||||||
ClickRelease(Option<usize>),
|
ClickRelease(Option<usize>),
|
||||||
Config(TabConfig),
|
Config(TabConfig),
|
||||||
ContextAction(Action),
|
ContextAction(Action),
|
||||||
ContextMenu(Option<Point>, Option<window::Id>),
|
RightClickBackground,
|
||||||
LocationContextMenuPoint(Option<Point>),
|
Surface(cosmic::surface::Action<Message>),
|
||||||
LocationContextMenuIndex(Option<Point>, Option<usize>),
|
LocationContextMenuIndex(Option<usize>),
|
||||||
LocationMenuAction(LocationMenuAction),
|
LocationMenuAction(LocationMenuAction),
|
||||||
Drag(Option<Rectangle>),
|
Drag(Option<Rectangle>),
|
||||||
DragEnd,
|
DragEnd,
|
||||||
|
|
@ -1814,6 +1854,8 @@ pub enum Message {
|
||||||
HighlightDeactivate(usize),
|
HighlightDeactivate(usize),
|
||||||
HighlightActivate(usize),
|
HighlightActivate(usize),
|
||||||
DirectorySize(PathBuf, DirSize),
|
DirectorySize(PathBuf, DirSize),
|
||||||
|
#[cfg(feature = "gvfs")]
|
||||||
|
DirectoryChildren(PathBuf, usize),
|
||||||
Checksums(PathBuf, ChecksumState),
|
Checksums(PathBuf, ChecksumState),
|
||||||
CalculateChecksums(PathBuf),
|
CalculateChecksums(PathBuf),
|
||||||
CopyChecksum(String),
|
CopyChecksum(String),
|
||||||
|
|
@ -1882,6 +1924,7 @@ pub enum ItemMetadata {
|
||||||
mtime: u64,
|
mtime: u64,
|
||||||
size_opt: Option<u64>,
|
size_opt: Option<u64>,
|
||||||
children_opt: Option<usize>,
|
children_opt: Option<usize>,
|
||||||
|
is_dir: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1896,7 +1939,7 @@ impl ItemMetadata {
|
||||||
Self::SimpleDir { .. } => true,
|
Self::SimpleDir { .. } => true,
|
||||||
Self::SimpleFile { .. } => false,
|
Self::SimpleFile { .. } => false,
|
||||||
#[cfg(feature = "gvfs")]
|
#[cfg(feature = "gvfs")]
|
||||||
Self::GvfsPath { children_opt, .. } => children_opt.is_some(),
|
Self::GvfsPath { is_dir, .. } => *is_dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1905,7 +1948,7 @@ impl ItemMetadata {
|
||||||
Self::Path { metadata, .. } => metadata.modified().ok(),
|
Self::Path { metadata, .. } => metadata.modified().ok(),
|
||||||
#[cfg(feature = "gvfs")]
|
#[cfg(feature = "gvfs")]
|
||||||
Self::GvfsPath { mtime, .. } => {
|
Self::GvfsPath { mtime, .. } => {
|
||||||
Some(SystemTime::UNIX_EPOCH + Duration::from_secs(*mtime))
|
SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(*mtime))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -2327,6 +2370,7 @@ impl Item {
|
||||||
) -> widget::Text<'a, cosmic::Theme, cosmic::Renderer> {
|
) -> widget::Text<'a, cosmic::Theme, cosmic::Renderer> {
|
||||||
widget::text::body(name)
|
widget::text::body(name)
|
||||||
.wrapping(text::Wrapping::WordOrGlyph)
|
.wrapping(text::Wrapping::WordOrGlyph)
|
||||||
|
.align_x(text::Alignment::Center)
|
||||||
.ellipsize(text::Ellipsize::Middle(text::EllipsizeHeightLimit::Lines(
|
.ellipsize(text::Ellipsize::Middle(text::EllipsizeHeightLimit::Lines(
|
||||||
3,
|
3,
|
||||||
)))
|
)))
|
||||||
|
|
@ -2382,10 +2426,8 @@ impl Item {
|
||||||
widget::image(handle.clone()).into()
|
widget::image(handle.clone()).into()
|
||||||
}
|
}
|
||||||
ItemThumbnail::Svg(handle) => widget::svg(handle.clone()).into(),
|
ItemThumbnail::Svg(handle) => widget::svg(handle.clone()).into(),
|
||||||
ItemThumbnail::Text(content) => widget::text_editor(content)
|
ItemThumbnail::Text(content) => widget::text_editor::text_editor(content)
|
||||||
.class(cosmic::theme::iced::TextEditor::Custom(Box::new(
|
.style(text_editor_class)
|
||||||
text_editor_class,
|
|
||||||
)))
|
|
||||||
.width(THUMBNAIL_SIZE as f32)
|
.width(THUMBNAIL_SIZE as f32)
|
||||||
.height(Length::Fixed(THUMBNAIL_SIZE as f32))
|
.height(Length::Fixed(THUMBNAIL_SIZE as f32))
|
||||||
.padding(spacing.space_xxs)
|
.padding(spacing.space_xxs)
|
||||||
|
|
@ -2436,7 +2478,7 @@ impl Item {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut details = widget::column::with_capacity(8).spacing(space_xxxs);
|
let mut details = widget::column::with_capacity(8).spacing(space_xxxs);
|
||||||
details = details.push(widget::text::heading(self.name.clone()));
|
details = details.push(widget::selectable_text::heading(self.name.clone()));
|
||||||
details = details.push(widget::text::body(fl!(
|
details = details.push(widget::text::body(fl!(
|
||||||
"type",
|
"type",
|
||||||
mime = self.mime.to_string()
|
mime = self.mime.to_string()
|
||||||
|
|
@ -2493,21 +2535,21 @@ impl Item {
|
||||||
let time_formatter = time_formatter(military_time);
|
let time_formatter = time_formatter(military_time);
|
||||||
|
|
||||||
if let Ok(time) = metadata.created() {
|
if let Ok(time) = metadata.created() {
|
||||||
details = details.push(widget::text::body(fl!(
|
details = details.push(widget::selectable_text::body(fl!(
|
||||||
"item-created",
|
"item-created",
|
||||||
created = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
created = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(time) = metadata.modified() {
|
if let Ok(time) = metadata.modified() {
|
||||||
details = details.push(widget::text::body(fl!(
|
details = details.push(widget::selectable_text::body(fl!(
|
||||||
"item-modified",
|
"item-modified",
|
||||||
modified = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
modified = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(time) = metadata.accessed() {
|
if let Ok(time) = metadata.accessed() {
|
||||||
details = details.push(widget::text::body(fl!(
|
details = details.push(widget::selectable_text::body(fl!(
|
||||||
"item-accessed",
|
"item-accessed",
|
||||||
accessed = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
accessed = format_time(time, &date_time_formatter, &time_formatter).to_string()
|
||||||
)));
|
)));
|
||||||
|
|
@ -2778,9 +2820,8 @@ pub struct Tab {
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
pub location_ancestors: Vec<(Location, String)>,
|
pub location_ancestors: Vec<(Location, String)>,
|
||||||
pub location_title: String,
|
pub location_title: String,
|
||||||
pub location_context_menu_point: Option<Point>,
|
/// Breadcrumb whose context menu is open, drawn as active while it shows
|
||||||
pub location_context_menu_index: Option<usize>,
|
pub location_context_menu_index: Option<usize>,
|
||||||
pub context_menu: Option<Point>,
|
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
pub scroll_opt: Option<AbsoluteOffset>,
|
pub scroll_opt: Option<AbsoluteOffset>,
|
||||||
pub size_opt: Cell<Option<Size>>,
|
pub size_opt: Cell<Option<Size>>,
|
||||||
|
|
@ -2808,7 +2849,6 @@ pub struct Tab {
|
||||||
search_context: Option<SearchContext>,
|
search_context: Option<SearchContext>,
|
||||||
date_time_formatter: DateTimeFormatter<fieldsets::YMDT>,
|
date_time_formatter: DateTimeFormatter<fieldsets::YMDT>,
|
||||||
time_formatter: DateTimeFormatter<fieldsets::T>,
|
time_formatter: DateTimeFormatter<fieldsets::T>,
|
||||||
watch_drag: bool,
|
|
||||||
window_id: Option<window::Id>,
|
window_id: Option<window::Id>,
|
||||||
large_image_manager: LargeImageManager,
|
large_image_manager: LargeImageManager,
|
||||||
}
|
}
|
||||||
|
|
@ -2925,8 +2965,6 @@ impl Tab {
|
||||||
location,
|
location,
|
||||||
location_ancestors,
|
location_ancestors,
|
||||||
location_title,
|
location_title,
|
||||||
context_menu: None,
|
|
||||||
location_context_menu_point: None,
|
|
||||||
location_context_menu_index: None,
|
location_context_menu_index: None,
|
||||||
mode: Mode::App,
|
mode: Mode::App,
|
||||||
scroll_opt: None,
|
scroll_opt: None,
|
||||||
|
|
@ -2955,7 +2993,6 @@ impl Tab {
|
||||||
search_context: None,
|
search_context: None,
|
||||||
date_time_formatter: date_time_formatter(config.military_time),
|
date_time_formatter: date_time_formatter(config.military_time),
|
||||||
time_formatter: time_formatter(config.military_time),
|
time_formatter: time_formatter(config.military_time),
|
||||||
watch_drag: true,
|
|
||||||
window_id,
|
window_id,
|
||||||
large_image_manager: LargeImageManager::new(),
|
large_image_manager: LargeImageManager::new(),
|
||||||
}
|
}
|
||||||
|
|
@ -3468,7 +3505,6 @@ impl Tab {
|
||||||
self.location = location.normalize();
|
self.location = location.normalize();
|
||||||
self.location_ancestors = self.location.ancestors();
|
self.location_ancestors = self.location.ancestors();
|
||||||
self.location_title = self.location.title();
|
self.location_title = self.location.title();
|
||||||
self.context_menu = None;
|
|
||||||
self.edit_location = None;
|
self.edit_location = None;
|
||||||
self.items_opt = None;
|
self.items_opt = None;
|
||||||
//TODO: remember scroll by location?
|
//TODO: remember scroll by location?
|
||||||
|
|
@ -3513,7 +3549,6 @@ impl Tab {
|
||||||
let mut history_i_opt = None;
|
let mut history_i_opt = None;
|
||||||
let mod_ctrl = modifiers.contains(Modifiers::CTRL) && self.mode.multiple();
|
let mod_ctrl = modifiers.contains(Modifiers::CTRL) && self.mode.multiple();
|
||||||
let mod_shift = modifiers.contains(Modifiers::SHIFT) && self.mode.multiple();
|
let mod_shift = modifiers.contains(Modifiers::SHIFT) && self.mode.multiple();
|
||||||
let last_context_menu = self.context_menu;
|
|
||||||
match message {
|
match message {
|
||||||
Message::AddNetworkDrive => {
|
Message::AddNetworkDrive => {
|
||||||
commands.push(Command::AddNetworkDrive);
|
commands.push(Command::AddNetworkDrive);
|
||||||
|
|
@ -3548,8 +3583,6 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
if click_i_opt != self.clicked.take() {
|
if click_i_opt != self.clicked.take() {
|
||||||
self.context_menu = None;
|
|
||||||
self.location_context_menu_index = None;
|
|
||||||
if let Some(ref mut items) = self.items_opt {
|
if let Some(ref mut items) = self.items_opt {
|
||||||
for (i, item) in items.iter_mut().enumerate() {
|
for (i, item) in items.iter_mut().enumerate() {
|
||||||
if mod_ctrl {
|
if mod_ctrl {
|
||||||
|
|
@ -3566,7 +3599,6 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Message::DragEnd => {
|
Message::DragEnd => {
|
||||||
self.clicked = None;
|
self.clicked = None;
|
||||||
self.watch_drag = true;
|
|
||||||
}
|
}
|
||||||
Message::DoubleClick(click_i_opt) => {
|
Message::DoubleClick(click_i_opt) => {
|
||||||
if let Some(clicked_item) = self
|
if let Some(clicked_item) = self
|
||||||
|
|
@ -3591,9 +3623,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Message::Click(click_i_opt) => {
|
Message::Click(click_i_opt) => {
|
||||||
self.selected_clicked = false;
|
self.selected_clicked = false;
|
||||||
self.context_menu = None;
|
|
||||||
self.edit_location = None;
|
self.edit_location = None;
|
||||||
self.location_context_menu_index = None;
|
|
||||||
if click_i_opt.is_none() {
|
if click_i_opt.is_none() {
|
||||||
self.clicked = click_i_opt;
|
self.clicked = click_i_opt;
|
||||||
}
|
}
|
||||||
|
|
@ -3735,24 +3765,16 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ContextAction(action) => {
|
Message::ContextAction(action) => {
|
||||||
// Close context menu
|
|
||||||
self.context_menu = None;
|
|
||||||
|
|
||||||
commands.push(Command::Action(action));
|
commands.push(Command::Action(action));
|
||||||
}
|
}
|
||||||
Message::RunContextAction(action) => {
|
Message::RunContextAction(action) => {
|
||||||
self.context_menu = None;
|
|
||||||
|
|
||||||
commands.push(Command::RunContextAction(action));
|
commands.push(Command::RunContextAction(action));
|
||||||
}
|
}
|
||||||
Message::ContextMenu(point_opt, _) => {
|
Message::RightClickBackground => {
|
||||||
self.edit_location = None;
|
self.edit_location = None;
|
||||||
self.context_menu = point_opt;
|
|
||||||
self.location_context_menu_index = None;
|
|
||||||
|
|
||||||
//TODO: hack for clearing selecting when right clicking empty space
|
//TODO: hack for clearing selecting when right clicking empty space
|
||||||
if self.context_menu.is_some()
|
if self.last_right_click.take().is_none()
|
||||||
&& self.last_right_click.take().is_none()
|
|
||||||
&& let Some(ref mut items) = self.items_opt
|
&& let Some(ref mut items) = self.items_opt
|
||||||
{
|
{
|
||||||
for item in items.iter_mut() {
|
for item in items.iter_mut() {
|
||||||
|
|
@ -3760,17 +3782,13 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::LocationContextMenuPoint(point_opt) => {
|
Message::Surface(action) => {
|
||||||
self.context_menu = None;
|
commands.push(Command::Surface(action));
|
||||||
self.location_context_menu_point = point_opt;
|
|
||||||
}
|
}
|
||||||
Message::LocationContextMenuIndex(p, index_opt) => {
|
Message::LocationContextMenuIndex(index) => {
|
||||||
self.context_menu = None;
|
self.location_context_menu_index = index;
|
||||||
self.location_context_menu_point = p;
|
|
||||||
self.location_context_menu_index = index_opt;
|
|
||||||
}
|
}
|
||||||
Message::LocationMenuAction(action) => {
|
Message::LocationMenuAction(action) => {
|
||||||
self.location_context_menu_index = None;
|
|
||||||
let path_for_index = |ancestor_index| {
|
let path_for_index = |ancestor_index| {
|
||||||
self.location
|
self.location
|
||||||
.path_opt()
|
.path_opt()
|
||||||
|
|
@ -3820,10 +3838,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Drag(rect_opt) => {
|
Message::Drag(rect_opt) => {
|
||||||
self.watch_drag = false;
|
|
||||||
if let Some(rect) = rect_opt {
|
if let Some(rect) = rect_opt {
|
||||||
self.context_menu = None;
|
|
||||||
self.location_context_menu_index = None;
|
|
||||||
if self.mode.multiple() {
|
if self.mode.multiple() {
|
||||||
self.select_rect(rect, mod_ctrl, mod_shift);
|
self.select_rect(rect, mod_ctrl, mod_shift);
|
||||||
}
|
}
|
||||||
|
|
@ -3859,6 +3874,28 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Message::EditLocationSubmit => {
|
Message::EditLocationSubmit => {
|
||||||
if let Some(mut edit_location) = self.edit_location.take() {
|
if let Some(mut edit_location) = self.edit_location.take() {
|
||||||
|
let typed_opt = match &edit_location.location {
|
||||||
|
Location::Path(path) => path.to_str().map(str::to_string),
|
||||||
|
Location::Network(uri, ..) => Some(uri.clone()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let mut typed_uri = false;
|
||||||
|
if let Some(typed) = typed_opt {
|
||||||
|
match typed.trim().parse::<url::Url>() {
|
||||||
|
Ok(url) if url.scheme() != "file" && url.has_host() => {
|
||||||
|
let uri = url.as_str().to_string();
|
||||||
|
edit_location =
|
||||||
|
Location::Network(uri.clone(), uri, None).normalize().into();
|
||||||
|
typed_uri = true;
|
||||||
|
}
|
||||||
|
Err(_) if matches!(edit_location.location, Location::Network(..)) => {
|
||||||
|
edit_location =
|
||||||
|
Location::Path(PathBuf::from(typed)).normalize().into();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Select first completion if current location does not exist
|
// Select first completion if current location does not exist
|
||||||
if edit_location.selected.is_none()
|
if edit_location.selected.is_none()
|
||||||
&& edit_location
|
&& edit_location
|
||||||
|
|
@ -3874,6 +3911,9 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
cd = edit_location.resolve();
|
cd = edit_location.resolve();
|
||||||
|
if cd.is_none() && typed_uri {
|
||||||
|
cd = Some(edit_location.location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::EditLocationTab => {
|
Message::EditLocationTab => {
|
||||||
|
|
@ -4435,13 +4475,11 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::HighlightDeactivate(i) => {
|
Message::HighlightDeactivate(i) => {
|
||||||
self.watch_drag = true;
|
|
||||||
if let Some(item) = self.items_opt.as_mut().and_then(|f| f.get_mut(i)) {
|
if let Some(item) = self.items_opt.as_mut().and_then(|f| f.get_mut(i)) {
|
||||||
item.highlighted = false;
|
item.highlighted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::HighlightActivate(i) => {
|
Message::HighlightActivate(i) => {
|
||||||
self.watch_drag = true;
|
|
||||||
if let Some(item) = self.items_opt.as_mut().and_then(|f| f.get_mut(i)) {
|
if let Some(item) = self.items_opt.as_mut().and_then(|f| f.get_mut(i)) {
|
||||||
item.highlighted = true;
|
item.highlighted = true;
|
||||||
}
|
}
|
||||||
|
|
@ -4467,7 +4505,6 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Message::Scroll(viewport) => {
|
Message::Scroll(viewport) => {
|
||||||
self.scroll_opt = Some(viewport.absolute_offset());
|
self.scroll_opt = Some(viewport.absolute_offset());
|
||||||
self.watch_drag = true;
|
|
||||||
}
|
}
|
||||||
Message::ScrollTab(scroll_speed) => {
|
Message::ScrollTab(scroll_speed) => {
|
||||||
commands.push(Command::Iced(
|
commands.push(Command::Iced(
|
||||||
|
|
@ -4800,6 +4837,20 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "gvfs")]
|
||||||
|
Message::DirectoryChildren(path, children) => {
|
||||||
|
if let Some(ref mut items) = self.items_opt {
|
||||||
|
for item in items.iter_mut() {
|
||||||
|
if item.path_opt() == Some(&path) {
|
||||||
|
if let ItemMetadata::GvfsPath { children_opt, .. } = &mut item.metadata
|
||||||
|
{
|
||||||
|
*children_opt = Some(children);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::Checksums(path, checksum_state) => {
|
Message::Checksums(path, checksum_state) => {
|
||||||
let location = Location::Path(path);
|
let location = Location::Path(path);
|
||||||
if let Some(ref mut item) = self.parent_item_opt
|
if let Some(ref mut item) = self.parent_item_opt
|
||||||
|
|
@ -4906,16 +4957,6 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update context menu popup
|
|
||||||
if self.context_menu != last_context_menu {
|
|
||||||
if last_context_menu.is_some() {
|
|
||||||
commands.push(Command::ContextMenu(None, self.window_id));
|
|
||||||
}
|
|
||||||
if let Some(point) = self.context_menu {
|
|
||||||
commands.push(Command::ContextMenu(Some(point), self.window_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commands
|
commands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4961,11 +5002,15 @@ impl Tab {
|
||||||
ItemMetadata::GvfsPath {
|
ItemMetadata::GvfsPath {
|
||||||
size_opt,
|
size_opt,
|
||||||
children_opt,
|
children_opt,
|
||||||
|
is_dir,
|
||||||
..
|
..
|
||||||
} => match children_opt {
|
} => {
|
||||||
Some(child_count) => (true, *child_count as u64),
|
if *is_dir {
|
||||||
None => (false, size_opt.unwrap_or_default()),
|
(true, children_opt.unwrap_or_default() as u64)
|
||||||
},
|
} else {
|
||||||
|
(false, size_opt.unwrap_or_default())
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let (a_is_entry, a_size) = get_size(a.1);
|
let (a_is_entry, a_size) = get_size(a.1);
|
||||||
let (b_is_entry, b_size) = get_size(b.1);
|
let (b_is_entry, b_size) = get_size(b.1);
|
||||||
|
|
@ -5174,9 +5219,11 @@ impl Tab {
|
||||||
}
|
}
|
||||||
ItemThumbnail::Text(text) => {
|
ItemThumbnail::Text(text) => {
|
||||||
element_opt = Some(
|
element_opt = Some(
|
||||||
widget::container(widget::text_editor(text).padding(space_xxs).class(
|
widget::container(
|
||||||
cosmic::theme::iced::TextEditor::Custom(Box::new(text_editor_class)),
|
widget::text_editor::text_editor(text)
|
||||||
))
|
.padding(space_xxs)
|
||||||
|
.style(text_editor_class),
|
||||||
|
)
|
||||||
.center(Length::Fill)
|
.center(Length::Fill)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
@ -5520,10 +5567,14 @@ impl Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = self.location.with_path(ancestor.to_path_buf());
|
let location = self.location.with_path(ancestor.to_path_buf());
|
||||||
let mut mouse_area = crate::mouse_area::MouseArea::new(
|
let mouse_area = crate::mouse_area::MouseArea::new(
|
||||||
widget::button::custom(row)
|
widget::button::custom(row)
|
||||||
.padding(space_xxxs)
|
.padding(space_xxxs)
|
||||||
.class(theme::Button::Link)
|
.class(if self.location_context_menu_index == Some(index) {
|
||||||
|
theme::Button::LinkActive
|
||||||
|
} else {
|
||||||
|
theme::Button::Link
|
||||||
|
})
|
||||||
.on_press(if ancestor == path {
|
.on_press(if ancestor == path {
|
||||||
Message::EditLocation(Some(self.location.clone().into()))
|
Message::EditLocation(Some(self.location.clone().into()))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -5531,21 +5582,6 @@ impl Tab {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.location_context_menu_index.is_some() {
|
|
||||||
mouse_area = mouse_area
|
|
||||||
.on_right_press(move |point_opt| {
|
|
||||||
Message::LocationContextMenuIndex(point_opt, None)
|
|
||||||
})
|
|
||||||
.wayland_on_right_press_window_position();
|
|
||||||
} else {
|
|
||||||
mouse_area = mouse_area
|
|
||||||
.on_right_press_no_capture()
|
|
||||||
.on_right_press(move |point_opt| {
|
|
||||||
Message::LocationContextMenuIndex(point_opt, Some(index))
|
|
||||||
})
|
|
||||||
.wayland_on_right_press_window_position();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouse_area = if let Location::Path(_) = &self.location {
|
let mouse_area = if let Location::Path(_) = &self.location {
|
||||||
mouse_area
|
mouse_area
|
||||||
.on_middle_press(move |_| Message::OpenInNewTab(ancestor.to_path_buf()))
|
.on_middle_press(move |_| Message::OpenInNewTab(ancestor.to_path_buf()))
|
||||||
|
|
@ -5553,7 +5589,16 @@ impl Tab {
|
||||||
mouse_area
|
mouse_area
|
||||||
};
|
};
|
||||||
|
|
||||||
children.push(self.dnd_dest(&location, mouse_area));
|
// Each breadcrumb carries the menu for its own ancestor index
|
||||||
|
let mut context_menu =
|
||||||
|
widget::context_menu(mouse_area, Some(menu::location_context_menu(index)))
|
||||||
|
.on_open(Message::LocationContextMenuIndex(Some(index)))
|
||||||
|
.on_close(Message::LocationContextMenuIndex(None))
|
||||||
|
.on_surface_action(Message::Surface);
|
||||||
|
if let Some(window_id) = self.window_id {
|
||||||
|
context_menu = context_menu.window_id(window_id);
|
||||||
|
}
|
||||||
|
children.push(self.dnd_dest(&location, context_menu));
|
||||||
|
|
||||||
if found_home || overflow {
|
if found_home || overflow {
|
||||||
break;
|
break;
|
||||||
|
|
@ -5604,20 +5649,7 @@ impl Tab {
|
||||||
column = column.push(heading_rule);
|
column = column.push(heading_rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mouse_area = crate::mouse_area::MouseArea::new(column)
|
column.into()
|
||||||
.on_right_press(Message::LocationContextMenuPoint);
|
|
||||||
|
|
||||||
let mut popover = widget::popover(mouse_area);
|
|
||||||
if let (Some(point), Some(index)) = (
|
|
||||||
self.location_context_menu_point,
|
|
||||||
self.location_context_menu_index,
|
|
||||||
) {
|
|
||||||
popover = popover
|
|
||||||
.popup(menu::location_context_menu(index))
|
|
||||||
.position(widget::popover::Position::Point(point));
|
|
||||||
}
|
|
||||||
|
|
||||||
popover.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty_view(&self, has_hidden: bool) -> Element<'_, Message> {
|
pub fn empty_view(&self, has_hidden: bool) -> Element<'_, Message> {
|
||||||
|
|
@ -5806,18 +5838,13 @@ impl Tab {
|
||||||
.height(Length::Fixed(item_height as f32))
|
.height(Length::Fixed(item_height as f32))
|
||||||
.width(Length::Fixed(item_width as f32));
|
.width(Length::Fixed(item_width as f32));
|
||||||
for button in buttons {
|
for button in buttons {
|
||||||
if self.context_menu.is_some() {
|
column = column.push(
|
||||||
column = column.push(button);
|
mouse_area::MouseArea::new(button)
|
||||||
} else {
|
.on_right_press_no_capture()
|
||||||
column = column.push(
|
.on_right_press(move |point_opt| {
|
||||||
mouse_area::MouseArea::new(button)
|
Message::RightClick(point_opt, Some(i))
|
||||||
.on_right_press_no_capture()
|
}),
|
||||||
.wayland_on_right_press_window_position()
|
);
|
||||||
.on_right_press(move |point_opt| {
|
|
||||||
Message::RightClick(point_opt, Some(i))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let column: Element<Message> =
|
let column: Element<Message> =
|
||||||
|
|
@ -5984,15 +6011,13 @@ impl Tab {
|
||||||
Element::from(dnd_grid)
|
Element::from(dnd_grid)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut mouse_area = mouse_area::MouseArea::new(column.width(Length::Fill))
|
let mouse_area = mouse_area::MouseArea::new(column.width(Length::Fill))
|
||||||
.on_press(|_| Message::Click(None))
|
.on_press(|_| Message::Click(None))
|
||||||
.on_auto_scroll(Message::AutoScroll)
|
.on_auto_scroll(Message::AutoScroll)
|
||||||
|
.on_drag(move |rect_opt| self.on_drag(rect_opt))
|
||||||
.on_drag_end(|_| Message::DragEnd)
|
.on_drag_end(|_| Message::DragEnd)
|
||||||
.show_drag_rect(self.mode.multiple())
|
.show_drag_rect(self.mode.multiple())
|
||||||
.on_release(|_| Message::ClickRelease(None));
|
.on_release(|_| Message::ClickRelease(None));
|
||||||
if self.watch_drag {
|
|
||||||
mouse_area = mouse_area.on_drag(Message::Drag);
|
|
||||||
}
|
|
||||||
|
|
||||||
(drag_list, mouse_area.into(), true)
|
(drag_list, mouse_area.into(), true)
|
||||||
}
|
}
|
||||||
|
|
@ -6141,17 +6166,21 @@ impl Tab {
|
||||||
ItemMetadata::GvfsPath {
|
ItemMetadata::GvfsPath {
|
||||||
size_opt,
|
size_opt,
|
||||||
children_opt,
|
children_opt,
|
||||||
|
is_dir,
|
||||||
..
|
..
|
||||||
} => match children_opt {
|
} => {
|
||||||
Some(child_count) => {
|
if *is_dir {
|
||||||
if *child_count == 1 {
|
// Children are not counted on remote filesystems
|
||||||
format!("{child_count} item")
|
match children_opt {
|
||||||
} else {
|
//TODO: translate
|
||||||
format!("{child_count} items")
|
Some(1) => "1 item".to_string(),
|
||||||
|
Some(child_count) => format!("{child_count} items"),
|
||||||
|
None => String::new(),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
format_size(size_opt.unwrap_or_default())
|
||||||
}
|
}
|
||||||
None => format_size(size_opt.unwrap_or_default()),
|
}
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let row = if condensed {
|
let row = if condensed {
|
||||||
|
|
@ -6218,39 +6247,33 @@ impl Tab {
|
||||||
.spacing(space_xxs)
|
.spacing(space_xxs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let button = |row| {
|
let button =
|
||||||
let mouse_area = crate::mouse_area::MouseArea::new(
|
|row| {
|
||||||
widget::button::custom(row)
|
let mouse_area = crate::mouse_area::MouseArea::new(
|
||||||
.width(Length::Fill)
|
widget::button::custom(row)
|
||||||
.id(item.button_id.clone())
|
.width(Length::Fill)
|
||||||
.padding([0, space_xxs])
|
.id(item.button_id.clone())
|
||||||
.class(button_style(
|
.padding([0, space_xxs])
|
||||||
item.selected,
|
.class(button_style(
|
||||||
item.highlighted,
|
item.selected,
|
||||||
item.cut,
|
item.highlighted,
|
||||||
true,
|
item.cut,
|
||||||
true,
|
true,
|
||||||
false,
|
true,
|
||||||
)),
|
false,
|
||||||
)
|
)),
|
||||||
.on_press(move |_| Message::Click(Some(i)))
|
)
|
||||||
.on_double_click(move |_| Message::DoubleClick(Some(i)))
|
.on_press(move |_| Message::Click(Some(i)))
|
||||||
.on_release(move |_| Message::ClickRelease(Some(i)))
|
.on_double_click(move |_| Message::DoubleClick(Some(i)))
|
||||||
.on_middle_press(move |_| Message::MiddleClick(i))
|
.on_release(move |_| Message::ClickRelease(Some(i)))
|
||||||
.on_enter(move || Message::HighlightActivate(i))
|
.on_middle_press(move |_| Message::MiddleClick(i))
|
||||||
.on_exit(move || Message::HighlightDeactivate(i));
|
.on_enter(move || Message::HighlightActivate(i))
|
||||||
|
.on_exit(move || Message::HighlightDeactivate(i));
|
||||||
|
|
||||||
if self.context_menu.is_some() {
|
mouse_area.on_right_press_no_capture().on_right_press(
|
||||||
mouse_area
|
move |point_opt| Message::RightClick(point_opt, Some(i)),
|
||||||
} else {
|
)
|
||||||
mouse_area
|
};
|
||||||
.on_right_press_no_capture()
|
|
||||||
.wayland_on_right_press_window_position()
|
|
||||||
.on_right_press(move |point_opt| {
|
|
||||||
Message::RightClick(point_opt, Some(i))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let button_row = button(row.into());
|
let button_row = button(row.into());
|
||||||
let button_row: Element<_> = if item.metadata.is_dir()
|
let button_row: Element<_> = if item.metadata.is_dir()
|
||||||
|
|
@ -6378,16 +6401,14 @@ impl Tab {
|
||||||
let drag_col = (!drag_items.is_empty())
|
let drag_col = (!drag_items.is_empty())
|
||||||
.then(|| Element::from(widget::column::with_children(drag_items)));
|
.then(|| Element::from(widget::column::with_children(drag_items)));
|
||||||
|
|
||||||
let mut mouse_area = mouse_area::MouseArea::new(column.padding([0, space_s]))
|
let mouse_area = mouse_area::MouseArea::new(column.padding([0, space_s]))
|
||||||
.with_id(Id::new("list-view"))
|
.with_id(Id::new("list-view"))
|
||||||
.on_press(|_| Message::Click(None))
|
.on_press(|_| Message::Click(None))
|
||||||
.on_auto_scroll(Message::AutoScroll)
|
.on_auto_scroll(Message::AutoScroll)
|
||||||
|
.on_drag(move |rect_opt| self.on_drag(rect_opt))
|
||||||
.on_drag_end(|_| Message::DragEnd)
|
.on_drag_end(|_| Message::DragEnd)
|
||||||
.show_drag_rect(self.mode.multiple())
|
.show_drag_rect(self.mode.multiple())
|
||||||
.on_release(|_| Message::ClickRelease(None));
|
.on_release(|_| Message::ClickRelease(None));
|
||||||
if self.watch_drag {
|
|
||||||
mouse_area = mouse_area.on_drag(Message::Drag);
|
|
||||||
}
|
|
||||||
|
|
||||||
(drag_col, mouse_area.into(), true)
|
(drag_col, mouse_area.into(), true)
|
||||||
}
|
}
|
||||||
|
|
@ -6474,51 +6495,47 @@ impl Tab {
|
||||||
.on_back_press(move |_point_opt| Message::GoPrevious)
|
.on_back_press(move |_point_opt| Message::GoPrevious)
|
||||||
.on_forward_press(move |_point_opt| Message::GoNext)
|
.on_forward_press(move |_point_opt| Message::GoNext)
|
||||||
.on_scroll(|delta| respond_to_scroll_direction(delta, modifiers))
|
.on_scroll(|delta| respond_to_scroll_direction(delta, modifiers))
|
||||||
.on_right_press(move |p| {
|
.on_right_press(|_| Message::RightClickBackground);
|
||||||
Message::ContextMenu(
|
|
||||||
if self.context_menu.is_some() { None } else { p },
|
|
||||||
self.window_id,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.wayland_on_right_press_window_position();
|
|
||||||
|
|
||||||
let mut popover = widget::popover(mouse_area);
|
let items_area: Element<'_, Message> = if can_scroll {
|
||||||
if let Some(point) = self.context_menu
|
// FIXME: new responsive widget will remove the state from the scrollable
|
||||||
&& (!cfg!(feature = "wayland") || !crate::is_wayland())
|
// id_container with custom id forces the state to be extracted in a diff
|
||||||
{
|
// pre-processing step
|
||||||
let context_menu = menu::context_menu(
|
widget::id_container(
|
||||||
|
widget::scrollable(mouse_area)
|
||||||
|
.id(self.scrollable_id.clone())
|
||||||
|
.on_scroll(Message::Scroll)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill),
|
||||||
|
widget::Id::new(format!("{}-scrollable", self.scrollable_id)),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
mouse_area.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap the scrollable, not its content, so the popup anchors in window coordinates
|
||||||
|
let mut context_menu = widget::context_menu(
|
||||||
|
items_area,
|
||||||
|
Some(menu::context_menu(
|
||||||
self,
|
self,
|
||||||
key_binds,
|
key_binds,
|
||||||
modifiers,
|
modifiers,
|
||||||
clipboard_paste_available,
|
clipboard_paste_available,
|
||||||
context_actions,
|
context_actions,
|
||||||
);
|
)),
|
||||||
popover = popover
|
)
|
||||||
.popup(context_menu)
|
.item_width(cosmic::widget::menu::ItemWidth::Uniform(360))
|
||||||
.position(widget::popover::Position::Point(point));
|
.on_surface_action(Message::Surface);
|
||||||
|
if let Some(window_id) = self.window_id {
|
||||||
|
context_menu = context_menu.window_id(window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tab_column = widget::column::with_capacity(3);
|
let mut tab_column = widget::column::with_capacity(3);
|
||||||
if let Some(location_view) = location_view_opt {
|
if let Some(location_view) = location_view_opt {
|
||||||
tab_column = tab_column.push(location_view);
|
tab_column = tab_column.push(location_view);
|
||||||
}
|
}
|
||||||
if can_scroll {
|
tab_column = tab_column.push(context_menu);
|
||||||
tab_column = tab_column.push(
|
|
||||||
// FIXME: new responsive widget will remove the state from the scrollable
|
|
||||||
// id_container with custom id forces the state to be extracted in a diff
|
|
||||||
// pre-processing step
|
|
||||||
widget::id_container(
|
|
||||||
widget::scrollable(popover)
|
|
||||||
.id(self.scrollable_id.clone())
|
|
||||||
.on_scroll(Message::Scroll)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.height(Length::Fill),
|
|
||||||
widget::Id::new(format!("{}-scrollable", self.scrollable_id)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
tab_column = tab_column.push(popover);
|
|
||||||
}
|
|
||||||
match &self.location {
|
match &self.location {
|
||||||
Location::Trash | Location::Search(SearchLocation::Trash, ..) => {
|
Location::Trash | Location::Search(SearchLocation::Trash, ..) => {
|
||||||
if let Some(items) = self.items_opt()
|
if let Some(items) = self.items_opt()
|
||||||
|
|
@ -6917,6 +6934,74 @@ impl Tab {
|
||||||
Rectangle::new(point, size)
|
Rectangle::new(point, size)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Count the children of visible directories in the background. Doing it while
|
||||||
|
// scanning costs one directory listing per entry, which stalls remote filesystems.
|
||||||
|
#[cfg(feature = "gvfs")]
|
||||||
|
for item in items {
|
||||||
|
let ItemMetadata::GvfsPath {
|
||||||
|
children_opt: None,
|
||||||
|
is_dir: true,
|
||||||
|
..
|
||||||
|
} = &item.metadata
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Skip items that are not visible, or have no determined rect
|
||||||
|
match item.rect_opt.get() {
|
||||||
|
Some(rect) if rect.intersects(&visible_rect) => {}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(path) = item.path_opt().cloned() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChildrenWrapper(PathBuf);
|
||||||
|
impl Hash for ChildrenWrapper {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptions.push(Subscription::run_with(
|
||||||
|
ChildrenWrapper(path),
|
||||||
|
|ChildrenWrapper(path)| {
|
||||||
|
let path = path.clone();
|
||||||
|
stream::channel(
|
||||||
|
1,
|
||||||
|
move |mut output: futures::channel::mpsc::Sender<_>| async move {
|
||||||
|
let message = {
|
||||||
|
let path = path.clone();
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let children = match fs::read_dir(&path) {
|
||||||
|
Ok(entries) => entries.count(),
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"failed to read directory {}: {}",
|
||||||
|
path.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Message::DirectoryChildren(path, children)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = output.send(message).await {
|
||||||
|
log::warn!("failed to send directory children: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::future::pending().await
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
if item.thumbnail_opt.is_some() {
|
if item.thumbnail_opt.is_some() {
|
||||||
// Skip items that already have a mime type and thumbnail
|
// Skip items that already have a mime type and thumbnail
|
||||||
|
|
@ -7012,7 +7097,7 @@ impl Tab {
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
|
|
||||||
// Acquire semaphore permit
|
// Acquire semaphore permit
|
||||||
_ = THUMB_SEMAPHORE.acquire().await;
|
let _permit = THUMB_SEMAPHORE.acquire().await.unwrap();
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
@ -7316,6 +7401,19 @@ impl Tab {
|
||||||
const fn format_time(&self, time: SystemTime) -> FormatTime<'_> {
|
const fn format_time(&self, time: SystemTime) -> FormatTime<'_> {
|
||||||
format_time(time, &self.date_time_formatter, &self.time_formatter)
|
format_time(time, &self.date_time_formatter, &self.time_formatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_drag<'a>(&self, rect_opt: Option<Rectangle>) -> Option<Message> {
|
||||||
|
let rect = rect_opt?;
|
||||||
|
// We only want to publish a drag message if the overlapped items of the drag rect change,
|
||||||
|
// otherwise a view rebuild is triggered on every drag event.
|
||||||
|
let changed = self.items_opt.as_ref().is_some_and(|items| {
|
||||||
|
items.iter().any(|item| {
|
||||||
|
let overlaps = item.rect_opt.get().is_some_and(|r| r.intersects(&rect));
|
||||||
|
overlaps != item.overlaps_drag_rect
|
||||||
|
})
|
||||||
|
});
|
||||||
|
changed.then_some(Message::Drag(Some(rect)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn respond_to_scroll_direction(delta: ScrollDelta, modifiers: &Modifiers) -> Option<Message> {
|
pub fn respond_to_scroll_direction(delta: ScrollDelta, modifiers: &Modifiers) -> Option<Message> {
|
||||||
|
|
|
||||||
|
|
@ -175,3 +175,25 @@ pub fn thumbnailer(mime: &Mime) -> Vec<Thumbnailer> {
|
||||||
let thumbnailer_cache = THUMBNAILER_CACHE.lock().unwrap();
|
let thumbnailer_cache = THUMBNAILER_CACHE.lock().unwrap();
|
||||||
thumbnailer_cache.get(mime)
|
thumbnailer_cache.get(mime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, feature = "desktop"))]
|
||||||
|
mod tests {
|
||||||
|
use super::Thumbnailer;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_expands_thumbnailer_arguments() {
|
||||||
|
let thumbnailer = Thumbnailer {
|
||||||
|
exec: "cosmic-files-thumbnailer %o --size %s %i".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let command = thumbnailer
|
||||||
|
.command(Path::new("input.exe"), Path::new("output.png"), 128)
|
||||||
|
.expect("valid thumbnailer command");
|
||||||
|
assert_eq!(command.get_program(), "cosmic-files-thumbnailer");
|
||||||
|
assert_eq!(
|
||||||
|
command.get_args().collect::<Vec<_>>(),
|
||||||
|
["output.png", "--size", "128", "input.exe"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
30
src/trash.rs
30
src/trash.rs
|
|
@ -2,6 +2,7 @@ use cosmic::widget;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use crate::config::IconSizes;
|
use crate::config::IconSizes;
|
||||||
use crate::tab::{Item, SearchItem};
|
use crate::tab::{Item, SearchItem};
|
||||||
|
|
@ -89,11 +90,12 @@ pub fn trash_item_path(item: &trash::TrashItem) -> Option<PathBuf> {
|
||||||
/// - Read `~/.local/share/Trash/info/folder.trashinfo` to get the original path
|
/// - Read `~/.local/share/Trash/info/folder.trashinfo` to get the original path
|
||||||
/// - Compute: `<original_path>/sub/file.txt`
|
/// - Compute: `<original_path>/sub/file.txt`
|
||||||
pub fn original_path_for_trash_child(p: &Path) -> Option<PathBuf> {
|
pub fn original_path_for_trash_child(p: &Path) -> Option<PathBuf> {
|
||||||
let files = p.ancestors().find(|a| a.ends_with("files"))?;
|
let files = trash_files_dir(p)?;
|
||||||
let root = files.parent()?;
|
let root = files.parent()?;
|
||||||
let top = p.strip_prefix(files).ok()?.components().next()?;
|
let top = p.strip_prefix(files).ok()?.components().next()?;
|
||||||
let info =
|
let mut trashinfo_name = top.as_os_str().to_os_string();
|
||||||
std::fs::read_to_string(root.join("info").join(top).with_extension("trashinfo")).ok()?;
|
trashinfo_name.push(".trashinfo");
|
||||||
|
let info = std::fs::read_to_string(root.join("info").join(trashinfo_name)).ok()?;
|
||||||
let orig = percent_decode(info.lines().find_map(|l| l.strip_prefix("Path="))?.trim())?;
|
let orig = percent_decode(info.lines().find_map(|l| l.strip_prefix("Path="))?.trim())?;
|
||||||
let rel = p.strip_prefix(files.join(top)).ok()?;
|
let rel = p.strip_prefix(files.join(top)).ok()?;
|
||||||
let mut result = PathBuf::from(&orig);
|
let mut result = PathBuf::from(&orig);
|
||||||
|
|
@ -103,9 +105,29 @@ pub fn original_path_for_trash_child(p: &Path) -> Option<PathBuf> {
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TRASH_FOLDERS: LazyLock<HashSet<PathBuf>> = LazyLock::new(|| {
|
||||||
|
Trash::folders().unwrap_or_else(|e| {
|
||||||
|
log::warn!("failed to list trash folders: {}", e);
|
||||||
|
HashSet::new()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
fn is_trash_root(root: &Path) -> bool {
|
||||||
|
if TRASH_FOLDERS.is_empty() {
|
||||||
|
root.join("info").is_dir()
|
||||||
|
} else {
|
||||||
|
TRASH_FOLDERS.contains(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trash_files_dir(path: &Path) -> Option<&Path> {
|
||||||
|
path.ancestors()
|
||||||
|
.find(|a| a.ends_with("files") && a.parent().is_some_and(is_trash_root))
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether a path is inside any trash `files/` directory.
|
/// Check whether a path is inside any trash `files/` directory.
|
||||||
pub fn is_trash_path(path: &Path) -> bool {
|
pub fn is_trash_path(path: &Path) -> bool {
|
||||||
path.ancestors().any(|a| a.ends_with("files"))
|
trash_files_dir(path).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Trash;
|
pub struct Trash;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue