Enable preview in dialog
This commit is contained in:
parent
333d4e58ca
commit
73ed4cfa5a
2 changed files with 97 additions and 20 deletions
|
|
@ -342,7 +342,7 @@ pub enum ContextPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextPage {
|
impl ContextPage {
|
||||||
fn title(&self) -> String {
|
pub fn title(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::About => String::new(),
|
Self::About => String::new(),
|
||||||
Self::EditHistory => fl!("edit-history"),
|
Self::EditHistory => fl!("edit-history"),
|
||||||
|
|
|
||||||
115
src/dialog.rs
115
src/dialog.rs
|
|
@ -39,8 +39,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{Action, Message as AppMessage},
|
app::{Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind},
|
||||||
config::{Config, Favorite, TabConfig},
|
config::{Config, Favorite, IconSizes, TabConfig},
|
||||||
fl, home_dir,
|
fl, home_dir,
|
||||||
localize::LANGUAGE_SORTER,
|
localize::LANGUAGE_SORTER,
|
||||||
menu,
|
menu,
|
||||||
|
|
@ -315,6 +315,7 @@ enum Message {
|
||||||
NotifyEvents(Vec<DebouncedEvent>),
|
NotifyEvents(Vec<DebouncedEvent>),
|
||||||
NotifyWatcher(WatcherWrapper),
|
NotifyWatcher(WatcherWrapper),
|
||||||
Open,
|
Open,
|
||||||
|
Preview(PreviewKind, time::Duration),
|
||||||
Save(bool),
|
Save(bool),
|
||||||
SearchActivate,
|
SearchActivate,
|
||||||
SearchClear,
|
SearchClear,
|
||||||
|
|
@ -324,6 +325,18 @@ enum Message {
|
||||||
TabRescan(Vec<tab::Item>),
|
TabRescan(Vec<tab::Item>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<AppMessage> for Message {
|
||||||
|
fn from(app_message: AppMessage) -> Message {
|
||||||
|
match app_message {
|
||||||
|
AppMessage::TabMessage(_entity_opt, tab_message) => Message::TabMessage(tab_message),
|
||||||
|
unsupported => {
|
||||||
|
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||||
|
Message::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MounterData(MounterKey, MounterItem);
|
pub struct MounterData(MounterKey, MounterItem);
|
||||||
|
|
||||||
struct WatcherWrapper {
|
struct WatcherWrapper {
|
||||||
|
|
@ -355,6 +368,7 @@ struct App {
|
||||||
title: String,
|
title: String,
|
||||||
accept_label: String,
|
accept_label: String,
|
||||||
choices: Vec<DialogChoice>,
|
choices: Vec<DialogChoice>,
|
||||||
|
context_page: ContextPage,
|
||||||
dialog_pages: VecDeque<DialogPage>,
|
dialog_pages: VecDeque<DialogPage>,
|
||||||
dialog_text_input: widget::Id,
|
dialog_text_input: widget::Id,
|
||||||
filters: Vec<DialogFilter>,
|
filters: Vec<DialogFilter>,
|
||||||
|
|
@ -364,6 +378,7 @@ struct App {
|
||||||
mounters: Mounters,
|
mounters: Mounters,
|
||||||
mounter_items: HashMap<MounterKey, MounterItems>,
|
mounter_items: HashMap<MounterKey, MounterItems>,
|
||||||
nav_model: segmented_button::SingleSelectModel,
|
nav_model: segmented_button::SingleSelectModel,
|
||||||
|
preview_opt: Option<(PreviewKind, time::Instant)>,
|
||||||
result_opt: Option<DialogResult>,
|
result_opt: Option<DialogResult>,
|
||||||
search_active: bool,
|
search_active: bool,
|
||||||
search_id: widget::Id,
|
search_id: widget::Id,
|
||||||
|
|
@ -374,6 +389,40 @@ struct App {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
fn preview(&self, kind: &PreviewKind) -> Element<AppMessage> {
|
||||||
|
let mut children = Vec::with_capacity(1);
|
||||||
|
match kind {
|
||||||
|
PreviewKind::Custom(PreviewItem(item)) => {
|
||||||
|
children.push(item.property_view(IconSizes::default()));
|
||||||
|
}
|
||||||
|
PreviewKind::Location(location) => {
|
||||||
|
if let Some(items) = self.tab.items_opt() {
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.location_opt.as_ref() == Some(location) {
|
||||||
|
children.push(item.property_view(self.tab.config.icon_sizes));
|
||||||
|
// Only show one property view to avoid issues like hangs when generating
|
||||||
|
// preview images on thousands of files
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PreviewKind::Selected => {
|
||||||
|
if let Some(items) = self.tab.items_opt() {
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.selected {
|
||||||
|
children.push(item.property_view(self.tab.config.icon_sizes));
|
||||||
|
// Only show one property view to avoid issues like hangs when generating
|
||||||
|
// preview images on thousands of files
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
widget::settings::view_column(children).into()
|
||||||
|
}
|
||||||
|
|
||||||
fn rescan_tab(&self) -> Command<Message> {
|
fn rescan_tab(&self) -> Command<Message> {
|
||||||
let location = self.tab.location.clone();
|
let location = self.tab.location.clone();
|
||||||
let mounters = self.mounters.clone();
|
let mounters = self.mounters.clone();
|
||||||
|
|
@ -606,6 +655,7 @@ impl Application for App {
|
||||||
title,
|
title,
|
||||||
accept_label,
|
accept_label,
|
||||||
choices: Vec::new(),
|
choices: Vec::new(),
|
||||||
|
context_page: ContextPage::Settings,
|
||||||
dialog_pages: VecDeque::new(),
|
dialog_pages: VecDeque::new(),
|
||||||
dialog_text_input: widget::Id::unique(),
|
dialog_text_input: widget::Id::unique(),
|
||||||
filters: Vec::new(),
|
filters: Vec::new(),
|
||||||
|
|
@ -615,6 +665,7 @@ impl Application for App {
|
||||||
mounters: mounters(),
|
mounters: mounters(),
|
||||||
mounter_items: HashMap::new(),
|
mounter_items: HashMap::new(),
|
||||||
nav_model: segmented_button::ModelBuilder::default().build(),
|
nav_model: segmented_button::ModelBuilder::default().build(),
|
||||||
|
preview_opt: None,
|
||||||
result_opt: None,
|
result_opt: None,
|
||||||
search_active: false,
|
search_active: false,
|
||||||
search_id: widget::Id::unique(),
|
search_id: widget::Id::unique(),
|
||||||
|
|
@ -638,6 +689,17 @@ impl Application for App {
|
||||||
self.flags.window_id
|
self.flags.window_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn context_drawer(&self) -> Option<Element<Message>> {
|
||||||
|
if !self.core.window.show_context {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.context_page {
|
||||||
|
ContextPage::Preview(_, kind) => Some(self.preview(kind).map(Message::from)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dialog(&self) -> Option<Element<Message>> {
|
fn dialog(&self) -> Option<Element<Message>> {
|
||||||
let dialog_page = match self.dialog_pages.front() {
|
let dialog_page = match self.dialog_pages.front() {
|
||||||
Some(some) => some,
|
Some(some) => some,
|
||||||
|
|
@ -752,15 +814,7 @@ impl Application for App {
|
||||||
|
|
||||||
elements.push(
|
elements.push(
|
||||||
menu::dialog_menu(&self.tab, &self.key_binds)
|
menu::dialog_menu(&self.tab, &self.key_binds)
|
||||||
.map(|message| match message {
|
.map(Message::from)
|
||||||
AppMessage::TabMessage(_entity_opt, tab_message) => {
|
|
||||||
Message::TabMessage(tab_message)
|
|
||||||
}
|
|
||||||
unsupported => {
|
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
|
||||||
Message::None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1100,6 +1154,17 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::Preview(kind, timeout) => {
|
||||||
|
if self
|
||||||
|
.preview_opt
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|(k, i)| *k == kind && i.elapsed() > timeout)
|
||||||
|
{
|
||||||
|
self.context_page = ContextPage::Preview(None, kind);
|
||||||
|
self.set_show_context(true);
|
||||||
|
self.set_context_title(self.context_page.title());
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::Save(replace) => {
|
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() {
|
||||||
|
|
@ -1176,14 +1241,9 @@ impl Application for App {
|
||||||
let mut commands = Vec::new();
|
let mut commands = Vec::new();
|
||||||
for tab_command in tab_commands {
|
for tab_command in tab_commands {
|
||||||
match tab_command {
|
match tab_command {
|
||||||
tab::Command::Action(action) => match action.message() {
|
tab::Command::Action(action) => {
|
||||||
AppMessage::TabMessage(_entity_opt, tab_message) => {
|
commands.push(self.update(Message::from(action.message())));
|
||||||
commands.push(self.update(Message::TabMessage(tab_message)));
|
}
|
||||||
}
|
|
||||||
unsupported => {
|
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tab::Command::ChangeLocation(_tab_title, _tab_path, _selection_path) => {
|
tab::Command::ChangeLocation(_tab_title, _tab_path, _selection_path) => {
|
||||||
commands
|
commands
|
||||||
.push(Command::batch([self.update_watcher(), self.rescan_tab()]));
|
.push(Command::batch([self.update_watcher(), self.rescan_tab()]));
|
||||||
|
|
@ -1202,6 +1262,23 @@ impl Application for App {
|
||||||
commands.push(self.update(Message::Open));
|
commands.push(self.update(Message::Open));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tab::Command::Preview(kind, mut timeout) => {
|
||||||
|
self.preview_opt = Some((kind.clone(), time::Instant::now()));
|
||||||
|
if self.core.window.show_context {
|
||||||
|
// If the context window is already open, immediately show the preview
|
||||||
|
timeout = time::Duration::new(0, 0)
|
||||||
|
};
|
||||||
|
commands.push(Command::perform(
|
||||||
|
async move {
|
||||||
|
tokio::time::sleep(timeout).await;
|
||||||
|
message::app(Message::Preview(kind, timeout))
|
||||||
|
},
|
||||||
|
|x| x,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
tab::Command::PreviewCancel => {
|
||||||
|
self.preview_opt = None;
|
||||||
|
}
|
||||||
unsupported => {
|
unsupported => {
|
||||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue