Enable preview in dialog

This commit is contained in:
Jeremy Soller 2024-09-20 19:36:50 -06:00
parent 333d4e58ca
commit 73ed4cfa5a
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
2 changed files with 97 additions and 20 deletions

View file

@ -342,7 +342,7 @@ pub enum ContextPage {
}
impl ContextPage {
fn title(&self) -> String {
pub fn title(&self) -> String {
match self {
Self::About => String::new(),
Self::EditHistory => fl!("edit-history"),

View file

@ -39,8 +39,8 @@ use std::{
};
use crate::{
app::{Action, Message as AppMessage},
config::{Config, Favorite, TabConfig},
app::{Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind},
config::{Config, Favorite, IconSizes, TabConfig},
fl, home_dir,
localize::LANGUAGE_SORTER,
menu,
@ -315,6 +315,7 @@ enum Message {
NotifyEvents(Vec<DebouncedEvent>),
NotifyWatcher(WatcherWrapper),
Open,
Preview(PreviewKind, time::Duration),
Save(bool),
SearchActivate,
SearchClear,
@ -324,6 +325,18 @@ enum Message {
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);
struct WatcherWrapper {
@ -355,6 +368,7 @@ struct App {
title: String,
accept_label: String,
choices: Vec<DialogChoice>,
context_page: ContextPage,
dialog_pages: VecDeque<DialogPage>,
dialog_text_input: widget::Id,
filters: Vec<DialogFilter>,
@ -364,6 +378,7 @@ struct App {
mounters: Mounters,
mounter_items: HashMap<MounterKey, MounterItems>,
nav_model: segmented_button::SingleSelectModel,
preview_opt: Option<(PreviewKind, time::Instant)>,
result_opt: Option<DialogResult>,
search_active: bool,
search_id: widget::Id,
@ -374,6 +389,40 @@ struct 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> {
let location = self.tab.location.clone();
let mounters = self.mounters.clone();
@ -606,6 +655,7 @@ impl Application for App {
title,
accept_label,
choices: Vec::new(),
context_page: ContextPage::Settings,
dialog_pages: VecDeque::new(),
dialog_text_input: widget::Id::unique(),
filters: Vec::new(),
@ -615,6 +665,7 @@ impl Application for App {
mounters: mounters(),
mounter_items: HashMap::new(),
nav_model: segmented_button::ModelBuilder::default().build(),
preview_opt: None,
result_opt: None,
search_active: false,
search_id: widget::Id::unique(),
@ -638,6 +689,17 @@ impl Application for App {
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>> {
let dialog_page = match self.dialog_pages.front() {
Some(some) => some,
@ -752,15 +814,7 @@ impl Application for App {
elements.push(
menu::dialog_menu(&self.tab, &self.key_binds)
.map(|message| match message {
AppMessage::TabMessage(_entity_opt, tab_message) => {
Message::TabMessage(tab_message)
}
unsupported => {
log::warn!("{unsupported:?} not supported in dialog mode");
Message::None
}
})
.map(Message::from)
.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) => {
if let DialogKind::SaveFile { filename } = &self.flags.kind {
if !filename.is_empty() {
@ -1176,14 +1241,9 @@ impl Application for App {
let mut commands = Vec::new();
for tab_command in tab_commands {
match tab_command {
tab::Command::Action(action) => match action.message() {
AppMessage::TabMessage(_entity_opt, tab_message) => {
commands.push(self.update(Message::TabMessage(tab_message)));
}
unsupported => {
log::warn!("{unsupported:?} not supported in dialog mode");
}
},
tab::Command::Action(action) => {
commands.push(self.update(Message::from(action.message())));
}
tab::Command::ChangeLocation(_tab_title, _tab_path, _selection_path) => {
commands
.push(Command::batch([self.update_watcher(), self.rescan_tab()]));
@ -1202,6 +1262,23 @@ impl Application for App {
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 => {
log::warn!("{unsupported:?} not supported in dialog mode");
}