Merge pull request #1728 from darkfated/add-context-actions
Add user-defined context actions
This commit is contained in:
commit
175f8ba724
8 changed files with 252 additions and 9 deletions
104
src/app.rs
104
src/app.rs
|
|
@ -81,6 +81,7 @@ use crate::{
|
|||
AppTheme, Config, DesktopConfig, Favorite, IconSizes, State, TIME_CONFIG_ID, TabConfig,
|
||||
TimeConfig, TypeToSearch,
|
||||
},
|
||||
context_action,
|
||||
dialog::{Dialog, DialogKind, DialogMessage, DialogResult, DialogSettings},
|
||||
fl, home_dir,
|
||||
key_bind::key_binds,
|
||||
|
|
@ -110,6 +111,9 @@ static DELETE_TRASH_BUTTON_ID: LazyLock<widget::Id> =
|
|||
static CONFIRM_OPEN_WITH_BUTTON_ID: LazyLock<widget::Id> =
|
||||
LazyLock::new(|| widget::Id::new("confirm-open-with-button"));
|
||||
|
||||
static CONFIRM_CONTEXT_ACTION_BUTTON_ID: LazyLock<widget::Id> =
|
||||
LazyLock::new(|| widget::Id::new("confirm-context-action-button"));
|
||||
|
||||
static EMPTY_TRASH_BUTTON_ID: LazyLock<widget::Id> =
|
||||
LazyLock::new(|| widget::Id::new("empty-trash-button"));
|
||||
|
||||
|
|
@ -181,6 +185,7 @@ pub enum Action {
|
|||
OpenItemLocation,
|
||||
OpenTerminal,
|
||||
OpenWith,
|
||||
RunContextAction(usize),
|
||||
Paste,
|
||||
PermanentlyDelete,
|
||||
Preview,
|
||||
|
|
@ -253,6 +258,9 @@ impl Action {
|
|||
Self::OpenItemLocation => Message::OpenItemLocation(entity_opt),
|
||||
Self::OpenTerminal => Message::OpenTerminal(entity_opt),
|
||||
Self::OpenWith => Message::OpenWithDialog(entity_opt),
|
||||
Self::RunContextAction(action) => {
|
||||
Message::TabMessage(entity_opt, tab::Message::RunContextAction(*action))
|
||||
}
|
||||
Self::Paste => Message::Paste(entity_opt),
|
||||
Self::PermanentlyDelete => Message::PermanentlyDelete(entity_opt),
|
||||
Self::Preview => Message::Preview(entity_opt),
|
||||
|
|
@ -324,6 +332,7 @@ pub enum NavMenuAction {
|
|||
OpenInNewTab(segmented_button::Entity),
|
||||
OpenInNewWindow(segmented_button::Entity),
|
||||
Preview(segmented_button::Entity),
|
||||
RunContextAction(segmented_button::Entity, usize),
|
||||
RemoveFromSidebar(segmented_button::Entity),
|
||||
}
|
||||
|
||||
|
|
@ -559,6 +568,10 @@ pub enum DialogPage {
|
|||
name: String,
|
||||
dir: bool,
|
||||
},
|
||||
RunContextAction {
|
||||
action: usize,
|
||||
paths: Box<[PathBuf]>,
|
||||
},
|
||||
OpenWith {
|
||||
path: PathBuf,
|
||||
mime: mime_guess::Mime,
|
||||
|
|
@ -2594,6 +2607,28 @@ impl Application for App {
|
|||
NavMenuAction::OpenInNewWindow(entity),
|
||||
));
|
||||
}
|
||||
if let Some(path) = location_opt.and_then(Location::path_opt) {
|
||||
let selected_dir = usize::from(path.is_dir());
|
||||
let action_items: Vec<_> = self
|
||||
.config
|
||||
.context_actions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, action)| action.matches_selection(1, selected_dir))
|
||||
.map(|(i, action)| {
|
||||
cosmic::widget::menu::Item::Button(
|
||||
action.name.clone(),
|
||||
None,
|
||||
NavMenuAction::RunContextAction(entity, i),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !action_items.is_empty() {
|
||||
items.push(cosmic::widget::menu::Item::Divider);
|
||||
items.extend(action_items);
|
||||
}
|
||||
}
|
||||
items.push(cosmic::widget::menu::Item::Divider);
|
||||
if matches!(location_opt, Some(Location::Path(..))) {
|
||||
items.push(cosmic::widget::menu::Item::Button(
|
||||
|
|
@ -3186,6 +3221,9 @@ impl Application for App {
|
|||
Operation::NewFile { path }
|
||||
}));
|
||||
}
|
||||
DialogPage::RunContextAction { action, paths } => {
|
||||
context_action::run(&self.config.context_actions, action, &paths);
|
||||
}
|
||||
DialogPage::OpenWith {
|
||||
path,
|
||||
mime,
|
||||
|
|
@ -4506,6 +4544,25 @@ impl Application for App {
|
|||
tab::Command::ExecEntryAction(entry, action) => {
|
||||
Self::exec_entry_action(&entry, action);
|
||||
}
|
||||
tab::Command::RunContextAction(action) => {
|
||||
let paths: Box<[_]> = self.selected_paths(Some(entity)).collect();
|
||||
if let Some(preset) = self.config.context_actions.get(action) {
|
||||
if preset.confirm {
|
||||
commands.push(self.push_dialog(
|
||||
DialogPage::RunContextAction { action, paths },
|
||||
Some(CONFIRM_CONTEXT_ACTION_BUTTON_ID.clone()),
|
||||
));
|
||||
} else {
|
||||
context_action::run(
|
||||
&self.config.context_actions,
|
||||
action,
|
||||
&paths,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::warn!("invalid context action index `{action}`");
|
||||
}
|
||||
}
|
||||
tab::Command::Iced(iced_command) => {
|
||||
commands.push(iced_command.0.map(move |x| {
|
||||
cosmic::action::app(Message::TabMessage(Some(entity), x))
|
||||
|
|
@ -5013,6 +5070,30 @@ impl Application for App {
|
|||
}
|
||||
}
|
||||
}
|
||||
NavMenuAction::RunContextAction(entity, action) => {
|
||||
if let Some(path) = self
|
||||
.nav_model
|
||||
.data::<Location>(entity)
|
||||
.and_then(Location::path_opt)
|
||||
.cloned()
|
||||
{
|
||||
let paths = vec![path];
|
||||
if let Some(preset) = self.config.context_actions.get(action) {
|
||||
if preset.confirm {
|
||||
return self.push_dialog(
|
||||
DialogPage::RunContextAction {
|
||||
action,
|
||||
paths: paths.into_boxed_slice(),
|
||||
},
|
||||
Some(CONFIRM_CONTEXT_ACTION_BUTTON_ID.clone()),
|
||||
);
|
||||
}
|
||||
context_action::run(&self.config.context_actions, action, &paths);
|
||||
} else {
|
||||
log::warn!("invalid context action index `{action}`");
|
||||
}
|
||||
}
|
||||
}
|
||||
NavMenuAction::OpenInNewTab(entity) => {
|
||||
let open_task = match self.nav_model.data::<Location>(entity) {
|
||||
Some(Location::Network(uri, display_name, path)) => self.open_tab(
|
||||
|
|
@ -5789,6 +5870,26 @@ impl Application for App {
|
|||
.spacing(space_xxs),
|
||||
)
|
||||
}
|
||||
DialogPage::RunContextAction { action, paths } => {
|
||||
let name = self
|
||||
.config
|
||||
.context_actions
|
||||
.get(*action)
|
||||
.map_or_else(|| fl!("context-action"), |preset| preset.name.clone());
|
||||
|
||||
widget::dialog()
|
||||
.title(fl!("context-action-confirm-title", name = name))
|
||||
.body(fl!("context-action-confirm-warning", items = paths.len()))
|
||||
.icon(icon::from_name("dialog-error").size(64))
|
||||
.primary_action(
|
||||
widget::button::suggested(fl!("run"))
|
||||
.on_press(Message::DialogComplete)
|
||||
.id(CONFIRM_CONTEXT_ACTION_BUTTON_ID.clone()),
|
||||
)
|
||||
.secondary_action(
|
||||
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
||||
)
|
||||
}
|
||||
DialogPage::OpenWith {
|
||||
path,
|
||||
mime,
|
||||
|
|
@ -6335,6 +6436,7 @@ impl Application for App {
|
|||
&self.key_binds,
|
||||
&self.modifiers,
|
||||
self.clipboard_has_content(),
|
||||
&self.config.context_actions,
|
||||
)
|
||||
.map(move |message| Message::TabMessage(Some(entity), message));
|
||||
tab_column = tab_column.push(tab_view);
|
||||
|
|
@ -6363,6 +6465,7 @@ impl Application for App {
|
|||
&self.key_binds,
|
||||
&window.modifiers,
|
||||
self.clipboard_has_content(),
|
||||
&self.config.context_actions,
|
||||
)
|
||||
.map(|x| Message::TabMessage(Some(*entity), x)),
|
||||
id.clone(),
|
||||
|
|
@ -6380,6 +6483,7 @@ impl Application for App {
|
|||
&self.key_binds,
|
||||
&window.modifiers,
|
||||
self.clipboard_has_content(),
|
||||
&self.config.context_actions,
|
||||
)
|
||||
.map(move |message| Message::TabMessage(Some(*entity), message)),
|
||||
None => widget::space::vertical().into(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue