Merge pull request #295 from pop-os/undo-toaster
Implement undo toaster for trash operations
This commit is contained in:
commit
1820433da4
4 changed files with 81 additions and 48 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
|
@ -1112,7 +1112,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config"
|
name = "cosmic-config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomicwrites",
|
"atomicwrites",
|
||||||
"cosmic-config-derive",
|
"cosmic-config-derive",
|
||||||
|
|
@ -1131,7 +1131,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config-derive"
|
name = "cosmic-config-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
|
@ -1198,7 +1198,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-text"
|
name = "cosmic-text"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/cosmic-text.git#0e2d050a8d87c2e97e94ae205c9beda5858123b6"
|
source = "git+https://github.com/pop-os/cosmic-text.git#4f316658050536c4254fb70639f4b5203c31dbce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"fontdb",
|
"fontdb",
|
||||||
|
|
@ -1220,7 +1220,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-theme"
|
name = "cosmic-theme"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"almost",
|
"almost",
|
||||||
"cosmic-config",
|
"cosmic-config",
|
||||||
|
|
@ -2624,7 +2624,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dnd",
|
"dnd",
|
||||||
"iced_accessibility",
|
"iced_accessibility",
|
||||||
|
|
@ -2643,7 +2643,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_accessibility"
|
name = "iced_accessibility"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_unix",
|
"accesskit_unix",
|
||||||
|
|
@ -2653,7 +2653,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"dnd",
|
"dnd",
|
||||||
|
|
@ -2675,7 +2675,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_futures"
|
name = "iced_futures"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
|
|
@ -2688,7 +2688,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -2712,7 +2712,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_renderer"
|
name = "iced_renderer"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_tiny_skia",
|
"iced_tiny_skia",
|
||||||
|
|
@ -2724,7 +2724,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_runtime"
|
name = "iced_runtime"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dnd",
|
"dnd",
|
||||||
"iced_accessibility",
|
"iced_accessibility",
|
||||||
|
|
@ -2738,7 +2738,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_sctk"
|
name = "iced_sctk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum-repr",
|
"enum-repr",
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
|
|
@ -2765,7 +2765,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_style"
|
name = "iced_style"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -2775,7 +2775,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_tiny_skia"
|
name = "iced_tiny_skia"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
|
|
@ -2792,7 +2792,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
|
|
@ -2821,7 +2821,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_widget"
|
name = "iced_widget"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dnd",
|
"dnd",
|
||||||
"iced_accessibility",
|
"iced_accessibility",
|
||||||
|
|
@ -2839,7 +2839,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_winit"
|
name = "iced_winit"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dnd",
|
"dnd",
|
||||||
"iced_accessibility",
|
"iced_accessibility",
|
||||||
|
|
@ -3337,7 +3337,7 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcosmic"
|
name = "libcosmic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic.git#2dd55f2f20cc0a5bd09f834779dd6cf1dcb23bcf"
|
source = "git+https://github.com/pop-os/libcosmic.git#3d22fb8fe2ffe1eaf5047fa77cec2d8d63781601"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ empty-folder-hidden = Empty folder (has hidden items)
|
||||||
filesystem = Filesystem
|
filesystem = Filesystem
|
||||||
home = Home
|
home = Home
|
||||||
trash = Trash
|
trash = Trash
|
||||||
|
undo = Undo
|
||||||
|
|
||||||
# List view
|
# List view
|
||||||
name = Name
|
name = Name
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ replace-title = {$filename} 已存在於此位置。
|
||||||
replace-warning = 您想用您正在儲存的檔案替換它嗎?替換將會覆蓋其內容。
|
replace-warning = 您想用您正在儲存的檔案替換它嗎?替換將會覆蓋其內容。
|
||||||
replace-warning-operation = 您想要替換它嗎? 替換將會覆蓋其內容。
|
replace-warning-operation = 您想要替換它嗎? 替換將會覆蓋其內容。
|
||||||
original-file = 原始檔案
|
original-file = 原始檔案
|
||||||
#replace-with = Replace with # Can't translate due to word order
|
# replace-with = Replace with # Can't translate due to word order
|
||||||
apply-to-all = 全部套用
|
apply-to-all = 全部套用
|
||||||
keep-both = 保留兩者
|
keep-both = 保留兩者
|
||||||
skip = 跳過
|
skip = 跳過
|
||||||
|
|
|
||||||
90
src/app.rs
90
src/app.rs
|
|
@ -40,6 +40,7 @@ use std::{
|
||||||
time::{self, Instant},
|
time::{self, Instant},
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
use trash::TrashItem;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
||||||
|
|
@ -202,6 +203,7 @@ impl MenuAction for NavMenuAction {
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
AddToSidebar(Option<Entity>),
|
AddToSidebar(Option<Entity>),
|
||||||
AppTheme(AppTheme),
|
AppTheme(AppTheme),
|
||||||
|
CloseToast(usize),
|
||||||
Config(Config),
|
Config(Config),
|
||||||
Copy(Option<Entity>),
|
Copy(Option<Entity>),
|
||||||
Cut(Option<Entity>),
|
Cut(Option<Entity>),
|
||||||
|
|
@ -247,9 +249,10 @@ pub enum Message {
|
||||||
TabMessage(Option<Entity>, tab::Message),
|
TabMessage(Option<Entity>, tab::Message),
|
||||||
TabNew,
|
TabNew,
|
||||||
TabRescan(Entity, Location, Vec<tab::Item>),
|
TabRescan(Entity, Location, Vec<tab::Item>),
|
||||||
Toast(widget::toaster::ToastMessage),
|
|
||||||
ToggleContextPage(ContextPage),
|
ToggleContextPage(ContextPage),
|
||||||
Undo(u64),
|
Undo(usize),
|
||||||
|
UndoTrash(usize, Arc<[PathBuf]>),
|
||||||
|
UndoTrashStart(Vec<TrashItem>),
|
||||||
WindowClose,
|
WindowClose,
|
||||||
WindowNew,
|
WindowNew,
|
||||||
DndHoverLocTimeout(Location),
|
DndHoverLocTimeout(Location),
|
||||||
|
|
@ -262,12 +265,6 @@ pub enum Message {
|
||||||
DndDropNav(Entity, Option<ClipboardPaste>, DndAction),
|
DndDropNav(Entity, Option<ClipboardPaste>, DndAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<widget::toaster::ToastMessage> for Message {
|
|
||||||
fn from(toast_message: widget::toaster::ToastMessage) -> Self {
|
|
||||||
Self::Toast(toast_message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum ContextPage {
|
pub enum ContextPage {
|
||||||
About,
|
About,
|
||||||
|
|
@ -991,7 +988,7 @@ impl Application for App {
|
||||||
search_active: false,
|
search_active: false,
|
||||||
search_id: widget::Id::unique(),
|
search_id: widget::Id::unique(),
|
||||||
search_input: String::new(),
|
search_input: String::new(),
|
||||||
toasts: widget::toaster::Toasts::default(),
|
toasts: widget::toaster::Toasts::new(Message::CloseToast),
|
||||||
watcher_opt: None,
|
watcher_opt: None,
|
||||||
nav_dnd_hover: None,
|
nav_dnd_hover: None,
|
||||||
tab_dnd_hover: None,
|
tab_dnd_hover: None,
|
||||||
|
|
@ -1193,6 +1190,9 @@ impl Application for App {
|
||||||
let contents = ClipboardCopy::new(ClipboardKind::Cut, &paths);
|
let contents = ClipboardCopy::new(ClipboardKind::Cut, &paths);
|
||||||
return clipboard::write_data(contents);
|
return clipboard::write_data(contents);
|
||||||
}
|
}
|
||||||
|
Message::CloseToast(id) => {
|
||||||
|
self.toasts.remove(id);
|
||||||
|
}
|
||||||
Message::DialogCancel => {
|
Message::DialogCancel => {
|
||||||
self.dialog_pages.pop_front();
|
self.dialog_pages.pop_front();
|
||||||
}
|
}
|
||||||
|
|
@ -1542,23 +1542,26 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::PendingComplete(id) => {
|
Message::PendingComplete(id) => {
|
||||||
let mut commands = Vec::with_capacity(2);
|
let mut commands = Vec::new();
|
||||||
|
|
||||||
if let Some((op, _)) = self.pending_operations.remove(&id) {
|
if let Some((op, _)) = self.pending_operations.remove(&id) {
|
||||||
if let Some(description) = op.toast() {
|
if let Some(description) = op.toast() {
|
||||||
commands.push(
|
if let Operation::Delete { ref paths } = op {
|
||||||
self.toasts.push(
|
let paths: Arc<[PathBuf]> = Arc::from(paths.as_slice());
|
||||||
widget::toaster::Toast::new(description)
|
commands.push(
|
||||||
/*TODO
|
self.toasts
|
||||||
.action(widget::toaster::ToastAction {
|
.push(
|
||||||
description: fl!("undo"),
|
widget::toaster::Toast::new(description)
|
||||||
message: Message::Undo(id),
|
.action(fl!("undo"), move |tid| {
|
||||||
})
|
Message::UndoTrash(tid, paths.clone())
|
||||||
*/
|
}),
|
||||||
.duration(widget::toaster::ToastDuration::Long),
|
)
|
||||||
),
|
.map(cosmic::app::Message::App),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.complete_operations.insert(id, op);
|
||||||
}
|
}
|
||||||
self.complete_operations.insert(id, op);
|
|
||||||
}
|
}
|
||||||
// Manually rescan any trash tabs after any operation is completed
|
// Manually rescan any trash tabs after any operation is completed
|
||||||
commands.push(self.rescan_trash());
|
commands.push(self.rescan_trash());
|
||||||
|
|
@ -1896,10 +1899,6 @@ impl Application for App {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: TABRELOAD
|
|
||||||
Message::Toast(toast_message) => {
|
|
||||||
self.toasts.handle_message(&toast_message);
|
|
||||||
}
|
|
||||||
Message::ToggleContextPage(context_page) => {
|
Message::ToggleContextPage(context_page) => {
|
||||||
//TODO: ensure context menus are closed
|
//TODO: ensure context menus are closed
|
||||||
if self.context_page == context_page {
|
if self.context_page == context_page {
|
||||||
|
|
@ -1911,7 +1910,40 @@ impl Application for App {
|
||||||
self.set_context_title(context_page.title());
|
self.set_context_title(context_page.title());
|
||||||
}
|
}
|
||||||
Message::Undo(id) => {
|
Message::Undo(id) => {
|
||||||
log::error!("TODO: Undo {id}");
|
// TODO;
|
||||||
|
}
|
||||||
|
Message::UndoTrash(id, recently_trashed) => {
|
||||||
|
self.toasts.remove(id);
|
||||||
|
|
||||||
|
let mut paths = Vec::with_capacity(recently_trashed.len());
|
||||||
|
let icon_sizes = self.config.tab.icon_sizes;
|
||||||
|
|
||||||
|
return cosmic::command::future(async move {
|
||||||
|
match tokio::task::spawn_blocking(move || Location::Trash.scan(icon_sizes))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(items) => {
|
||||||
|
for path in &*recently_trashed {
|
||||||
|
for item in &items {
|
||||||
|
if let ItemMetadata::Trash { ref entry, .. } = item.metadata {
|
||||||
|
let original_path = entry.original_path();
|
||||||
|
if &original_path == path {
|
||||||
|
paths.push(entry.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to rescan: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::UndoTrashStart(paths)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Message::UndoTrashStart(paths) => {
|
||||||
|
self.operation(Operation::Restore { paths });
|
||||||
}
|
}
|
||||||
Message::WindowClose => {
|
Message::WindowClose => {
|
||||||
return window::close(window::Id::MAIN);
|
return window::close(window::Id::MAIN);
|
||||||
|
|
@ -2429,7 +2461,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let content: Element<_> = widget::toaster::toaster(&self.toasts, tab_column).into();
|
let content: Element<_> = widget::toaster(&self.toasts, tab_column).into();
|
||||||
|
|
||||||
// Uncomment to debug layout:
|
// Uncomment to debug layout:
|
||||||
//content.explain(cosmic::iced::Color::WHITE)
|
//content.explain(cosmic::iced::Color::WHITE)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue