Adjust executable permission to use Operation and adjust text per UX
This commit is contained in:
parent
00857511ca
commit
5624f37a36
3 changed files with 107 additions and 74 deletions
|
|
@ -66,10 +66,10 @@ apply-to-all = Apply to all
|
|||
keep-both = Keep both
|
||||
skip = Skip
|
||||
|
||||
## Execution permission Dialog
|
||||
add-permission-title = Add execution permission
|
||||
add-permission-control = Add execution permission to {$path}
|
||||
add-permission = Add permission
|
||||
## Set as Executable and Launch Dialog
|
||||
set-executable-and-launch = Set as executable and launch
|
||||
set-executable-and-launch-description = Do you want to set "{$name}" as executable and launch it?
|
||||
set-and-launch = Set and launch
|
||||
|
||||
## Metadata Dialog
|
||||
owner = Owner
|
||||
|
|
@ -145,6 +145,8 @@ extracted = Extracted {$items} {$items ->
|
|||
[one] item
|
||||
*[other] items
|
||||
} from {$from} to {$to}
|
||||
setting-executable-and-launching = Setting "{$name}" as executable and launching
|
||||
set-executable-and-launched = Set "{$name}" as executable and launched
|
||||
moving = Moving {$items} {$items ->
|
||||
[one] item
|
||||
*[other] items
|
||||
|
|
|
|||
133
src/app.rs
133
src/app.rs
|
|
@ -43,13 +43,10 @@ use slotmap::Key as SlotMapKey;
|
|||
use std::{
|
||||
any::TypeId,
|
||||
collections::{BTreeMap, HashMap, HashSet, VecDeque},
|
||||
env,
|
||||
ffi::OsStr,
|
||||
fmt, fs,
|
||||
env, fmt, fs,
|
||||
future::pending,
|
||||
io::{BufRead, BufReader},
|
||||
io,
|
||||
num::NonZeroU16,
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::PathBuf,
|
||||
process,
|
||||
sync::{Arc, Mutex},
|
||||
|
|
@ -415,10 +412,6 @@ pub enum DialogPage {
|
|||
name: String,
|
||||
dir: bool,
|
||||
},
|
||||
AddExecutablePermission {
|
||||
file_path: PathBuf,
|
||||
run: bool,
|
||||
},
|
||||
Replace {
|
||||
from: tab::Item,
|
||||
to: tab::Item,
|
||||
|
|
@ -426,6 +419,9 @@ pub enum DialogPage {
|
|||
apply_to_all: bool,
|
||||
tx: mpsc::Sender<ReplaceResult>,
|
||||
},
|
||||
SetExecutableAndLaunch {
|
||||
path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct FavoriteIndex(usize);
|
||||
|
|
@ -1465,25 +1461,12 @@ impl Application for App {
|
|||
let to = parent.join(name);
|
||||
self.operation(Operation::Rename { from, to });
|
||||
}
|
||||
DialogPage::AddExecutablePermission { file_path, run } => {
|
||||
let mut perms = fs::metadata(&file_path)
|
||||
.expect("Failed to get metadata")
|
||||
.permissions();
|
||||
|
||||
let current_mode = perms.mode();
|
||||
let new_mode = current_mode | 0o100;
|
||||
perms.set_mode(new_mode);
|
||||
fs::set_permissions(&file_path, perms)
|
||||
.expect("Failed to set permissions");
|
||||
|
||||
if run {
|
||||
log::info!("running app: {:?}", file_path);
|
||||
let _ = std::process::Command::new(file_path).spawn();
|
||||
}
|
||||
}
|
||||
DialogPage::Replace { .. } => {
|
||||
log::warn!("replace dialog should be completed with replace result");
|
||||
}
|
||||
DialogPage::SetExecutableAndLaunch { path } => {
|
||||
self.operation(Operation::SetExecutableAndLaunch { path });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2242,7 +2225,8 @@ impl Application for App {
|
|||
}
|
||||
tab::Command::OpenFile(path) => {
|
||||
let mut found_desktop_exec = false;
|
||||
if mime_icon::mime_for_path(&path) == "application/x-desktop" {
|
||||
let mime = mime_icon::mime_for_path(&path);
|
||||
if mime == "application/x-desktop" {
|
||||
match freedesktop_entry_parser::parse_entry(&path) {
|
||||
Ok(entry) => {
|
||||
match entry.section("Desktop Entry").attr("Exec") {
|
||||
|
|
@ -2275,37 +2259,43 @@ impl Application for App {
|
|||
Err(err) => {
|
||||
log::warn!("failed to parse {:?}: {}", path, err);
|
||||
}
|
||||
};
|
||||
}
|
||||
if !found_desktop_exec {
|
||||
let file_extension = path.extension();
|
||||
match file_extension {
|
||||
Some(ext) if ext == OsStr::new("AppImage") => {
|
||||
let mut perms = fs::metadata(&path)
|
||||
.expect("Failed to get metadata")
|
||||
.permissions();
|
||||
|
||||
self.dialog_pages.push_back(
|
||||
DialogPage::AddExecutablePermission {
|
||||
file_path: path.clone(),
|
||||
run: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
_ => match open::that_detached(&path) {
|
||||
Ok(()) => {
|
||||
let _ = recently_used_xbel::update_recently_used(
|
||||
&path,
|
||||
App::APP_ID.to_string(),
|
||||
"cosmic-files".to_string(),
|
||||
None,
|
||||
}
|
||||
} else if mime == "application/x-executable"
|
||||
|| mime == "application/vnd.appimage"
|
||||
{
|
||||
let mut command = std::process::Command::new(&path);
|
||||
match spawn_detached(&mut command) {
|
||||
Ok(()) => {}
|
||||
Err(err) => match err.kind() {
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
// If permission is denied, try marking as executable, then running
|
||||
self.dialog_pages.push_back(
|
||||
DialogPage::SetExecutableAndLaunch {
|
||||
path: path.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to open {:?}: {}", path, err);
|
||||
_ => {
|
||||
log::warn!("failed to execute {:?}: {}", path, err);
|
||||
}
|
||||
},
|
||||
}
|
||||
found_desktop_exec = true;
|
||||
}
|
||||
if !found_desktop_exec {
|
||||
match open::that_detached(&path) {
|
||||
Ok(()) => {
|
||||
let _ = recently_used_xbel::update_recently_used(
|
||||
&path,
|
||||
App::APP_ID.to_string(),
|
||||
"cosmic-files".to_string(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to open {:?}: {}", path, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tab::Command::OpenInNewTab(path) => {
|
||||
|
|
@ -3088,24 +3078,6 @@ impl Application for App {
|
|||
.spacing(space_xxs),
|
||||
)
|
||||
}
|
||||
DialogPage::AddExecutablePermission { file_path, run } => {
|
||||
let mut dialog = widget::dialog(fl!("add-permission-title"))
|
||||
.primary_action(
|
||||
widget::button::text(fl!("add-permission"))
|
||||
.style(theme::Button::Suggested)
|
||||
.on_press(Message::DialogComplete),
|
||||
)
|
||||
.secondary_action(
|
||||
widget::button::text(fl!("cancel"))
|
||||
.style(theme::Button::Destructive)
|
||||
.on_press(Message::DialogCancel),
|
||||
)
|
||||
.control(widget::column().push(widget::text::text(fl!(
|
||||
"add-permission-control",
|
||||
path = file_path.as_os_str().to_str()
|
||||
))));
|
||||
dialog
|
||||
}
|
||||
DialogPage::RenameItem {
|
||||
from,
|
||||
parent,
|
||||
|
|
@ -3231,6 +3203,27 @@ impl Application for App {
|
|||
)
|
||||
}
|
||||
}
|
||||
DialogPage::SetExecutableAndLaunch { path } => {
|
||||
let name = match path.file_name() {
|
||||
Some(file_name) => file_name.to_str(),
|
||||
None => path.as_os_str().to_str(),
|
||||
};
|
||||
widget::dialog(fl!("set-executable-and-launch"))
|
||||
.primary_action(
|
||||
widget::button::text(fl!("set-and-launch"))
|
||||
.style(theme::Button::Suggested)
|
||||
.on_press(Message::DialogComplete),
|
||||
)
|
||||
.secondary_action(
|
||||
widget::button::text(fl!("cancel"))
|
||||
.style(theme::Button::Standard)
|
||||
.on_press(Message::DialogCancel),
|
||||
)
|
||||
.control(widget::text::text(fl!(
|
||||
"set-executable-and-launch-description",
|
||||
name = name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
Some(dialog.into())
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use crate::{
|
|||
config::IconSizes,
|
||||
err_str, fl,
|
||||
mime_icon::mime_for_path,
|
||||
spawn_detached::spawn_detached,
|
||||
tab,
|
||||
};
|
||||
|
||||
|
|
@ -176,6 +177,10 @@ pub enum Operation {
|
|||
Restore {
|
||||
paths: Vec<trash::TrashItem>,
|
||||
},
|
||||
/// Set executable and launch
|
||||
SetExecutableAndLaunch {
|
||||
path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
async fn copy_or_move(
|
||||
|
|
@ -473,6 +478,9 @@ impl Operation {
|
|||
fl!("renaming", from = file_name(from), to = file_name(to))
|
||||
}
|
||||
Self::Restore { paths } => fl!("restoring", items = paths.len()),
|
||||
Self::SetExecutableAndLaunch { path } => {
|
||||
fl!("setting-executable-and-launching", name = file_name(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -521,6 +529,9 @@ impl Operation {
|
|||
),
|
||||
Self::Rename { from, to } => fl!("renamed", from = file_name(from), to = file_name(to)),
|
||||
Self::Restore { paths } => fl!("restored", items = paths.len()),
|
||||
Self::SetExecutableAndLaunch { path } => {
|
||||
fl!("set-executable-and-launched", name = file_name(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -841,6 +852,33 @@ impl Operation {
|
|||
.await;
|
||||
}
|
||||
}
|
||||
Self::SetExecutableAndLaunch { path } => {
|
||||
tokio::task::spawn_blocking(move || -> io::Result<()> {
|
||||
//TODO: what to do on non-Unix systems?
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = fs::metadata(&path)?.permissions();
|
||||
let current_mode = perms.mode();
|
||||
let new_mode = current_mode | 0o111;
|
||||
perms.set_mode(new_mode);
|
||||
fs::set_permissions(&path, perms)?;
|
||||
}
|
||||
|
||||
let mut command = std::process::Command::new(path);
|
||||
spawn_detached(&mut command)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.map_err(err_str)?
|
||||
.map_err(err_str)?;
|
||||
let _ = msg_tx
|
||||
.lock()
|
||||
.await
|
||||
.send(Message::PendingProgress(id, 100.0))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = msg_tx
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue