fix: focus button for permanently delete dialog

This commit is contained in:
Ashley Wulber 2025-10-17 14:14:59 -04:00 committed by Ashley Wulber
parent 2aa7b6f063
commit 6615e0a2b7
2 changed files with 68 additions and 41 deletions

View file

@ -31,6 +31,7 @@ use cosmic::{
window::{self, Event as WindowEvent, Id as WindowId}, window::{self, Event as WindowEvent, Id as WindowId},
}, },
iced_runtime::clipboard, iced_runtime::clipboard,
iced_widget::button::focus,
style, surface, theme, style, surface, theme,
widget::{ widget::{
self, self,
@ -58,7 +59,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
pin::Pin, pin::Pin,
process, process,
sync::{Arc, Mutex}, sync::{Arc, LazyLock, Mutex},
time::{self, Duration, Instant}, time::{self, Duration, Instant},
}; };
use tokio::sync::mpsc; use tokio::sync::mpsc;
@ -91,6 +92,9 @@ use crate::{
}; };
use crate::{config::State, dialog::DialogSettings}; use crate::{config::State, dialog::DialogSettings};
static PERMANENT_DELETE_BUTTON_ID: LazyLock<widget::Id> =
LazyLock::new(|| widget::Id::new("permanent-delete-button"));
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Mode { pub enum Mode {
App, App,
@ -315,7 +319,7 @@ pub enum Message {
DialogComplete, DialogComplete,
Eject, Eject,
FileDialogMessage(DialogMessage), FileDialogMessage(DialogMessage),
DialogPush(DialogPage), DialogPush(DialogPage, Option<widget::Id>),
DialogUpdate(DialogPage), DialogUpdate(DialogPage),
DialogUpdateComplete(DialogPage), DialogUpdateComplete(DialogPage),
ExtractHere(Option<Entity>), ExtractHere(Option<Entity>),
@ -694,6 +698,15 @@ pub struct App {
} }
impl App { impl App {
fn push_dialog(&mut self, page: DialogPage, focus_id: Option<widget::Id>) -> Task<Message> {
let t = self.dialog_pages.push_back(page);
if let Some(focus_id) = focus_id {
Task::batch(vec![t, focus(focus_id)])
} else {
t
}
}
fn open_file(&mut self, paths: &[impl AsRef<Path>]) -> Task<Message> { fn open_file(&mut self, paths: &[impl AsRef<Path>]) -> Task<Message> {
let mut tasks = Vec::new(); let mut tasks = Vec::new();
@ -1091,9 +1104,12 @@ impl App {
let mut tasks = Vec::new(); let mut tasks = Vec::new();
if !dialog_paths.is_empty() { if !dialog_paths.is_empty() {
tasks.push(self.dialog_pages.push_back(DialogPage::PermanentlyDelete { tasks.push(self.update(Message::DialogPush(
paths: dialog_paths, DialogPage::PermanentlyDelete {
})); paths: dialog_paths,
},
Some(PERMANENT_DELETE_BUTTON_ID.clone()),
)));
} }
if !trash_paths.is_empty() { if !trash_paths.is_empty() {
tasks.push(self.operation(Operation::Delete { paths: trash_paths })); tasks.push(self.operation(Operation::Delete { paths: trash_paths }));
@ -2855,8 +2871,8 @@ impl Application for App {
return Task::batch(tasks); return Task::batch(tasks);
} }
} }
Message::DialogPush(dialog_page) => { Message::DialogPush(dialog_page, focused_id) => {
return self.dialog_pages.push_back(dialog_page); return self.push_dialog(dialog_page, focused_id);
} }
Message::DialogUpdate(dialog_page) => { Message::DialogUpdate(dialog_page) => {
self.dialog_pages.update_front(dialog_page); self.dialog_pages.update_front(dialog_page);
@ -3342,17 +3358,20 @@ impl Application for App {
let Some(path) = item.path_opt() else { let Some(path) = item.path_opt() else {
continue; continue;
}; };
return self.update(Message::DialogPush(DialogPage::OpenWith { return self.push_dialog(
path: path.to_path_buf(), DialogPage::OpenWith {
mime: item.mime.clone(), path: path.to_path_buf(),
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()
})); }),
},
None, // TODO which id to focus?
);
} }
} }
} }
@ -3530,9 +3549,10 @@ impl Application for App {
Message::PermanentlyDelete(entity_opt) => { Message::PermanentlyDelete(entity_opt) => {
let paths = self.selected_paths(entity_opt); let paths = self.selected_paths(entity_opt);
if !paths.is_empty() { if !paths.is_empty() {
return self return self.push_dialog(
.dialog_pages DialogPage::PermanentlyDelete { paths },
.push_back(DialogPage::PermanentlyDelete { paths }); Some(PERMANENT_DELETE_BUTTON_ID.clone()),
);
} }
} }
Message::Preview(entity_opt) => { Message::Preview(entity_opt) => {
@ -4404,17 +4424,20 @@ impl Application for App {
{ {
match tab::item_from_path(&path, IconSizes::default()) { match tab::item_from_path(&path, IconSizes::default()) {
Ok(item) => { Ok(item) => {
return self.update(Message::DialogPush(DialogPage::OpenWith { return self.push_dialog(
path: path.to_path_buf(), DialogPage::OpenWith {
mime: item.mime.clone(), path: path.to_path_buf(),
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()
})); }),
},
None,
);
} }
Err(err) => { Err(err) => {
log::warn!("failed to get item for path {:?}: {}", path, err); log::warn!("failed to get item for path {:?}: {}", path, err);
@ -5283,7 +5306,8 @@ impl Application for App {
.title(fl!("permanently-delete-question")) .title(fl!("permanently-delete-question"))
.primary_action( .primary_action(
widget::button::destructive(fl!("delete")) widget::button::destructive(fl!("delete"))
.on_press(Message::DialogComplete), .on_press(Message::DialogComplete)
.id(PERMANENT_DELETE_BUTTON_ID.clone()),
) )
.secondary_action( .secondary_action(
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),

View file

@ -53,13 +53,16 @@ async fn handle_replace(
let _ = msg_tx let _ = msg_tx
.lock() .lock()
.await .await
.send(Message::DialogPush(DialogPage::Replace { .send(Message::DialogPush(
from: item_from, DialogPage::Replace {
to: item_to, from: item_from,
multiple, to: item_to,
apply_to_all: false, multiple,
tx, apply_to_all: false,
})) tx,
},
None, // TODO which widget to focus?
))
.await; .await;
rx.recv().await.unwrap_or(ReplaceResult::Cancel) rx.recv().await.unwrap_or(ReplaceResult::Cancel)
} }
@ -1198,7 +1201,7 @@ mod tests {
let handle_messages = async move { let handle_messages = async move {
while let Some(msg) = rx.next().await { while let Some(msg) = rx.next().await {
match msg { match msg {
Message::DialogPush(DialogPage::Replace { tx, .. }) => { Message::DialogPush(DialogPage::Replace { tx, .. }, _id_to_focus) => {
debug!("[{id}] Replace request"); debug!("[{id}] Replace request");
tx.send(ReplaceResult::Cancel) tx.send(ReplaceResult::Cancel)
.await .await