Implement dialog for replacing files

This commit is contained in:
Jeremy Soller 2024-02-26 15:15:49 -07:00
parent ab3b5f40d5
commit 5778d64e8c
5 changed files with 265 additions and 220 deletions

395
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,6 @@ rust-embed = "8"
git = "https://github.com/pop-os/libcosmic.git" git = "https://github.com/pop-os/libcosmic.git"
default-features = false default-features = false
features = ["multi-window", "tokio", "winit"] features = ["multi-window", "tokio", "winit"]
#path = "../libcosmic"
[dependencies.smol_str] [dependencies.smol_str]
version = "0.2.1" version = "0.2.1"

View file

@ -11,6 +11,7 @@ open-file = Open file
open-folder = Open folder open-folder = Open folder
open-multiple-files = Open multiple files open-multiple-files = Open multiple files
open-multiple-folders = Open multiple folders open-multiple-folders = Open multiple folders
replace = Replace file
save = Save save = Save
save-file = Save file save-file = Save file

View file

@ -962,7 +962,7 @@ impl Application for App {
if self.tab_model.iter().count() > 1 { if self.tab_model.iter().count() > 1 {
tab_column = tab_column.push( tab_column = tab_column.push(
widget::container( widget::container(
widget::view_switcher::horizontal(&self.tab_model) widget::tab_bar::horizontal(&self.tab_model)
.button_height(32) .button_height(32)
.button_spacing(space_xxs) .button_spacing(space_xxs)
.on_activate(Message::TabActivate) .on_activate(Message::TabActivate)

View file

@ -175,7 +175,7 @@ enum Message {
NotifyEvent(notify::Event), NotifyEvent(notify::Event),
NotifyWatcher(WatcherWrapper), NotifyWatcher(WatcherWrapper),
Open, Open,
Save, Save(bool),
TabMessage(tab::Message), TabMessage(tab::Message),
TabRescan(Vec<tab::Item>), TabRescan(Vec<tab::Item>),
} }
@ -205,6 +205,7 @@ struct App {
modifiers: Modifiers, modifiers: Modifiers,
nav_model: segmented_button::SingleSelectModel, nav_model: segmented_button::SingleSelectModel,
result_opt: Option<DialogResult>, result_opt: Option<DialogResult>,
replace_dialog: bool,
tab: Tab, tab: Tab,
watcher_opt: Option<(notify::RecommendedWatcher, HashSet<PathBuf>)>, watcher_opt: Option<(notify::RecommendedWatcher, HashSet<PathBuf>)>,
} }
@ -350,6 +351,7 @@ impl Application for App {
modifiers: Modifiers::empty(), modifiers: Modifiers::empty(),
nav_model: nav_model.build(), nav_model: nav_model.build(),
result_opt: None, result_opt: None,
replace_dialog: false,
tab, tab,
watcher_opt: None, watcher_opt: None,
}; };
@ -405,8 +407,12 @@ impl Application for App {
fn update(&mut self, message: Message) -> Command<Message> { fn update(&mut self, message: Message) -> Command<Message> {
match message { match message {
Message::Cancel => { Message::Cancel => {
self.result_opt = Some(DialogResult::Cancel); if self.replace_dialog {
return window::close(self.main_window_id()); self.replace_dialog = false;
} else {
self.result_opt = Some(DialogResult::Cancel);
return window::close(self.main_window_id());
}
} }
Message::Filename(new_filename) => { Message::Filename(new_filename) => {
if let DialogKind::SaveFile { filename } = &mut self.flags.kind { if let DialogKind::SaveFile { filename } = &mut self.flags.kind {
@ -494,17 +500,23 @@ impl Application for App {
} }
} }
} }
Message::Save => { Message::Save(replace) => {
if let DialogKind::SaveFile { filename } = &self.flags.kind { if let DialogKind::SaveFile { filename } = &self.flags.kind {
if !filename.is_empty() { if !filename.is_empty() {
if let Location::Path(tab_path) = &self.tab.location { if let Location::Path(tab_path) = &self.tab.location {
let path = tab_path.join(&filename); let path = tab_path.join(&filename);
if path.exists() { if path.is_dir() {
//TODO: dialog or something? // cd to directory
log::warn!("{:?} exists", path); let message = Message::TabMessage(tab::Message::Location(
Location::Path(path.clone()),
));
return self.update(message);
} else if !replace && path.exists() {
self.replace_dialog = true;
} else {
self.result_opt = Some(DialogResult::Open(vec![path]));
return window::close(self.main_window_id());
} }
self.result_opt = Some(DialogResult::Open(vec![path]));
return window::close(self.main_window_id());
} }
} }
} }
@ -522,7 +534,7 @@ impl Application for App {
if let Some(click_i) = click_i_opt { if let Some(click_i) = click_i_opt {
if let Some(items) = &self.tab.items_opt { if let Some(items) = &self.tab.items_opt {
if let Some(item) = items.get(click_i) { if let Some(item) = items.get(click_i) {
if item.selected { if item.selected && !item.path.is_dir() {
*filename = item.name.clone(); *filename = item.name.clone();
} }
} }
@ -541,7 +553,11 @@ impl Application for App {
.push(Command::batch([self.update_watcher(), self.rescan_tab()])); .push(Command::batch([self.update_watcher(), self.rescan_tab()]));
} }
tab::Command::OpenFile(_item_path) => { tab::Command::OpenFile(_item_path) => {
commands.push(self.update(Message::Open)); if self.flags.kind.save() {
commands.push(self.update(Message::Save(false)));
} else {
commands.push(self.update(Message::Open));
}
} }
} }
} }
@ -567,10 +583,14 @@ impl Application for App {
/// Creates a view after each update. /// Creates a view after each update.
fn view(&self) -> Element<Message> { fn view(&self) -> Element<Message> {
let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing; let cosmic_theme::Spacing {
space_m,
space_s,
space_xxs,
..
} = self.core().system_theme().cosmic().spacing;
let mut tab_column = widget::column::with_capacity(2); let mut tab_column = widget::column::with_capacity(2);
tab_column = tab_column.push( tab_column = tab_column.push(
self.tab self.tab
.view(self.core()) .view(self.core())
@ -583,7 +603,7 @@ impl Application for App {
widget::text_input("", filename) widget::text_input("", filename)
.id(self.filename_id.clone()) .id(self.filename_id.clone())
.on_input(Message::Filename) .on_input(Message::Filename)
.on_submit(Message::Save) .on_submit(Message::Save(false))
.into() .into()
} else { } else {
widget::horizontal_space(Length::Fill).into() widget::horizontal_space(Length::Fill).into()
@ -592,7 +612,7 @@ impl Application for App {
.on_press(Message::Cancel) .on_press(Message::Cancel)
.into(), .into(),
if self.flags.kind.save() { if self.flags.kind.save() {
widget::button::standard(fl!("save")).on_press(Message::Save) widget::button::standard(fl!("save")).on_press(Message::Save(false))
} else { } else {
widget::button::standard(fl!("open")).on_press(Message::Open) widget::button::standard(fl!("open")).on_press(Message::Open)
} }
@ -602,7 +622,41 @@ impl Application for App {
.spacing(space_xxs), .spacing(space_xxs),
); );
let content: Element<_> = tab_column.into(); //TODO: what is the best empty widget?
let mut overlay: Element<_> = widget::horizontal_space(Length::Shrink).into();
let mut show_popup = false;
if self.replace_dialog {
if let DialogKind::SaveFile { filename } = &self.flags.kind {
overlay = widget::cosmic_container::container(
widget::column::with_children(vec![
widget::text::title3(fl!("replace")).into(),
//TODO: translate
widget::text(format!("Do you want to replace \"{}\"?", filename)).into(),
widget::row::with_children(vec![
widget::horizontal_space(Length::Fill).into(),
widget::button::standard(fl!("cancel"))
.on_press(Message::Cancel)
.into(),
widget::button::destructive(fl!("replace"))
.on_press(Message::Save(true))
.into(),
])
.spacing(space_xxs)
.into(),
])
.spacing(space_s),
)
.layer(cosmic_theme::Layer::Primary)
.padding(space_m)
.width(Length::Fixed(480.0))
.into();
show_popup = true;
}
}
let content: Element<_> = widget::popover(tab_column, overlay)
.show_popup(show_popup)
.into();
// Uncomment to debug layout: // Uncomment to debug layout:
//content.explain(cosmic::iced::Color::WHITE) //content.explain(cosmic::iced::Color::WHITE)