Add Rename
This commit is contained in:
parent
8fed9dd216
commit
1dc9b9c1b1
4 changed files with 145 additions and 1 deletions
|
|
@ -26,6 +26,10 @@ open-multiple-folders = Open multiple folders
|
|||
save = Save
|
||||
save-file = Save file
|
||||
|
||||
# Rename Dialog
|
||||
rename-file = Rename file
|
||||
rename-folder = Rename folder
|
||||
|
||||
# Replace Dialog
|
||||
replace = Replace
|
||||
replace-title = {$filename} already exists in this location.
|
||||
|
|
@ -78,6 +82,7 @@ restore-from-trash = Restore from trash
|
|||
file = File
|
||||
new-tab = New tab
|
||||
new-window = New window
|
||||
rename = Rename
|
||||
close-tab = Close tab
|
||||
quit = Quit
|
||||
|
||||
|
|
|
|||
122
src/app.rs
122
src/app.rs
|
|
@ -53,6 +53,7 @@ pub enum Action {
|
|||
Operations,
|
||||
Paste,
|
||||
Properties,
|
||||
Rename,
|
||||
RestoreFromTrash,
|
||||
SelectAll,
|
||||
Settings,
|
||||
|
|
@ -82,6 +83,7 @@ impl Action {
|
|||
Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
|
||||
Action::Paste => Message::Paste(entity_opt),
|
||||
Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
|
||||
Action::Rename => Message::Rename(entity_opt),
|
||||
Action::RestoreFromTrash => Message::RestoreFromTrash(entity_opt),
|
||||
Action::SelectAll => Message::SelectAll(entity_opt),
|
||||
Action::Settings => Message::ToggleContextPage(ContextPage::Settings),
|
||||
|
|
@ -123,6 +125,7 @@ pub enum Message {
|
|||
PendingComplete(u64),
|
||||
PendingError(u64, String),
|
||||
PendingProgress(u64, f32),
|
||||
Rename(Option<segmented_button::Entity>),
|
||||
RestoreFromTrash(Option<segmented_button::Entity>),
|
||||
SelectAll(Option<segmented_button::Entity>),
|
||||
SystemThemeModeChange(cosmic_theme::ThemeMode),
|
||||
|
|
@ -166,6 +169,12 @@ pub enum DialogPage {
|
|||
name: String,
|
||||
dir: bool,
|
||||
},
|
||||
RenameItem {
|
||||
from: PathBuf,
|
||||
parent: PathBuf,
|
||||
name: String,
|
||||
dir: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -717,6 +726,12 @@ impl Application for App {
|
|||
Operation::NewFile { path }
|
||||
});
|
||||
}
|
||||
DialogPage::RenameItem {
|
||||
from, parent, name, ..
|
||||
} => {
|
||||
let to = parent.join(name);
|
||||
self.operation(Operation::Rename { from, to });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -831,6 +846,38 @@ impl Application for App {
|
|||
*progress = new_progress;
|
||||
}
|
||||
}
|
||||
Message::Rename(entity_opt) => {
|
||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||
if let Location::Path(parent) = &tab.location {
|
||||
if let Some(items) = &tab.items_opt {
|
||||
let mut selected = Vec::new();
|
||||
for item in items.iter() {
|
||||
if item.selected {
|
||||
selected.push(item.path.clone());
|
||||
}
|
||||
}
|
||||
if !selected.is_empty() {
|
||||
//TODO: batch rename
|
||||
for path in selected {
|
||||
let name = match path.file_name().and_then(|x| x.to_str()) {
|
||||
Some(some) => some.to_string(),
|
||||
None => continue,
|
||||
};
|
||||
let dir = path.is_dir();
|
||||
self.dialog_pages.push_back(DialogPage::RenameItem {
|
||||
from: path,
|
||||
parent: parent.clone(),
|
||||
name,
|
||||
dir,
|
||||
});
|
||||
}
|
||||
return widget::text_input::focus(self.dialog_text_input.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::RestoreFromTrash(entity_opt) => {
|
||||
let mut paths = Vec::new();
|
||||
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
|
||||
|
|
@ -1136,6 +1183,81 @@ impl Application for App {
|
|||
.spacing(space_xxs),
|
||||
)
|
||||
}
|
||||
DialogPage::RenameItem {
|
||||
from,
|
||||
parent,
|
||||
name,
|
||||
dir,
|
||||
} => {
|
||||
//TODO: combine logic with NewItem
|
||||
let mut dialog = widget::dialog(if *dir {
|
||||
fl!("rename-folder")
|
||||
} else {
|
||||
fl!("rename-file")
|
||||
});
|
||||
|
||||
let complete_maybe = if name.is_empty() {
|
||||
None
|
||||
} else if name == "." || name == ".." {
|
||||
dialog = dialog.tertiary_action(widget::text::body(fl!(
|
||||
"name-invalid",
|
||||
filename = name.as_str()
|
||||
)));
|
||||
None
|
||||
} else if name.contains('/') {
|
||||
dialog = dialog.tertiary_action(widget::text::body(fl!("name-no-slashes")));
|
||||
None
|
||||
} else {
|
||||
let path = parent.join(name);
|
||||
if path.exists() {
|
||||
if path.is_dir() {
|
||||
dialog = dialog
|
||||
.tertiary_action(widget::text::body(fl!("folder-already-exists")));
|
||||
} else {
|
||||
dialog = dialog
|
||||
.tertiary_action(widget::text::body(fl!("file-already-exists")));
|
||||
}
|
||||
None
|
||||
} else {
|
||||
if name.starts_with('.') {
|
||||
dialog = dialog.tertiary_action(widget::text::body(fl!("name-hidden")));
|
||||
}
|
||||
Some(Message::DialogComplete)
|
||||
}
|
||||
};
|
||||
|
||||
dialog
|
||||
.primary_action(
|
||||
widget::button::suggested(fl!("rename"))
|
||||
.on_press_maybe(complete_maybe.clone()),
|
||||
)
|
||||
.secondary_action(
|
||||
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
|
||||
)
|
||||
.control(
|
||||
widget::column::with_children(vec![
|
||||
widget::text::body(if *dir {
|
||||
fl!("folder-name")
|
||||
} else {
|
||||
fl!("file-name")
|
||||
})
|
||||
.into(),
|
||||
widget::text_input("", name.as_str())
|
||||
.id(self.dialog_text_input.clone())
|
||||
.on_input(move |name| {
|
||||
Message::DialogUpdate(DialogPage::RenameItem {
|
||||
from: from.clone(),
|
||||
parent: parent.clone(),
|
||||
name,
|
||||
dir: *dir,
|
||||
})
|
||||
})
|
||||
.on_submit_maybe(complete_maybe)
|
||||
.into(),
|
||||
])
|
||||
.spacing(space_xxs),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
Some(dialog.into())
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ pub fn context_menu<'a>(tab: &Tab) -> Element<'a, tab::Message> {
|
|||
children.push(menu_action(fl!("new-folder"), Action::NewFolder).into());
|
||||
children.push(horizontal_rule(1).into());
|
||||
if selected > 0 {
|
||||
children.push(menu_action(fl!("rename"), Action::Rename).into());
|
||||
children.push(menu_action(fl!("cut"), Action::Cut).into());
|
||||
children.push(menu_action(fl!("copy"), Action::Copy).into());
|
||||
children.push(menu_action(fl!("paste"), Action::Paste).into());
|
||||
|
|
@ -133,9 +134,14 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
|||
menu_item(fl!("new-window"), Action::WindowNew),
|
||||
menu_item(fl!("new-file"), Action::NewFile),
|
||||
menu_item(fl!("new-folder"), Action::NewFolder),
|
||||
//TODO: open
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("rename"), Action::Rename),
|
||||
//TOOD: add to sidebar, then divider
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("move-to-trash"), Action::MoveToTrash),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("close-tab"), Action::TabClose),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("quit"), Action::WindowClose),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ pub enum Operation {
|
|||
NewFolder {
|
||||
path: PathBuf,
|
||||
},
|
||||
Rename {
|
||||
from: PathBuf,
|
||||
to: PathBuf,
|
||||
},
|
||||
/// Restore a path from the trash
|
||||
Restore {
|
||||
paths: Vec<trash::TrashItem>,
|
||||
|
|
@ -74,6 +78,13 @@ impl Operation {
|
|||
.map_err(err_str)?;
|
||||
let _ = msg_tx.send(Message::PendingProgress(id, 100.0)).await;
|
||||
}
|
||||
Self::Rename { from, to } => {
|
||||
tokio::task::spawn_blocking(|| fs::rename(from, to))
|
||||
.await
|
||||
.map_err(err_str)?
|
||||
.map_err(err_str)?;
|
||||
let _ = msg_tx.send(Message::PendingProgress(id, 100.0)).await;
|
||||
}
|
||||
Self::Restore { paths } => {
|
||||
let total = paths.len();
|
||||
let mut count = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue