Skip to content

Commit 2b4a14d

Browse files
committed
Show parent folder in details, part of pop-os#541
1 parent a5dfffc commit 2b4a14d

File tree

3 files changed

+115
-64
lines changed

3 files changed

+115
-64
lines changed

src/app.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,13 @@ pub enum Message {
314314
TabConfig(TabConfig),
315315
TabMessage(Option<Entity>, tab::Message),
316316
TabNew,
317-
TabRescan(Entity, Location, Vec<tab::Item>, Option<PathBuf>),
317+
TabRescan(
318+
Entity,
319+
Location,
320+
Option<tab::Item>,
321+
Vec<tab::Item>,
322+
Option<PathBuf>,
323+
),
318324
TabView(Option<Entity>, tab::View),
319325
ToggleContextPage(ContextPage),
320326
ToggleFoldersFirst,
@@ -587,9 +593,13 @@ impl App {
587593
async move {
588594
let location2 = location.clone();
589595
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
590-
Ok(items) => {
591-
message::app(Message::TabRescan(entity, location, items, selection_path))
592-
}
596+
Ok((parent_item_opt, items)) => message::app(Message::TabRescan(
597+
entity,
598+
location,
599+
parent_item_opt,
600+
items,
601+
selection_path,
602+
)),
593603
Err(err) => {
594604
log::warn!("failed to rescan: {}", err);
595605
message::none()
@@ -1148,6 +1158,12 @@ impl App {
11481158
break;
11491159
}
11501160
}
1161+
if children.is_empty() {
1162+
if let Some(item) = &tab.parent_item_opt {
1163+
children
1164+
.push(item.preview_view(tab.config.icon_sizes, context_drawer));
1165+
}
1166+
}
11511167
}
11521168
}
11531169
}
@@ -2609,10 +2625,11 @@ impl Application for App {
26092625
};
26102626
return self.open_tab(location, true, None);
26112627
}
2612-
Message::TabRescan(entity, location, items, selection_path) => {
2628+
Message::TabRescan(entity, location, parent_item_opt, items, selection_path) => {
26132629
match self.tab_model.data_mut::<Tab>(entity) {
26142630
Some(tab) => {
26152631
if location == tab.location {
2632+
tab.parent_item_opt = parent_item_opt;
26162633
tab.set_items(items);
26172634
if let Some(selection_path) = selection_path {
26182635
tab.select_path(selection_path);
@@ -2654,7 +2671,7 @@ impl Application for App {
26542671
match tokio::task::spawn_blocking(move || Location::Trash.scan(icon_sizes))
26552672
.await
26562673
{
2657-
Ok(items) => {
2674+
Ok((_parent_item_opt, items)) => {
26582675
for path in &*recently_trashed {
26592676
for item in &items {
26602677
if let ItemMetadata::Trash { ref entry, .. } = item.metadata {
@@ -4243,8 +4260,9 @@ pub(crate) mod test_utils {
42434260

42444261
// New tab with items
42454262
let location = Location::Path(path.to_owned());
4246-
let items = location.scan(IconSizes::default());
4263+
let (parent_item_opt, items) = location.scan(IconSizes::default());
42474264
let mut tab = Tab::new(location, TabConfig::default());
4265+
tab.parent_item_opt = parent_item_opt;
42484266
tab.set_items(items);
42494267

42504268
// Ensure correct number of directories as a sanity check

src/dialog.rs

Lines changed: 73 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ enum Message {
325325
SearchClear,
326326
SearchInput(String),
327327
TabMessage(tab::Message),
328-
TabRescan(Vec<tab::Item>),
328+
TabRescan(Location, Option<tab::Item>, Vec<tab::Item>),
329329
TabView(tab::View),
330330
ToggleFoldersFirst,
331331
ZoomDefault,
@@ -494,6 +494,11 @@ impl App {
494494
break;
495495
}
496496
}
497+
if children.is_empty() {
498+
if let Some(item) = &self.tab.parent_item_opt {
499+
children.push(item.preview_view(self.tab.config.icon_sizes, true));
500+
}
501+
}
497502
}
498503
}
499504
}
@@ -505,8 +510,11 @@ impl App {
505510
let icon_sizes = self.tab.config.icon_sizes;
506511
Command::perform(
507512
async move {
508-
match tokio::task::spawn_blocking(move || location.scan(icon_sizes)).await {
509-
Ok(items) => message::app(Message::TabRescan(items)),
513+
let location2 = location.clone();
514+
match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await {
515+
Ok((parent_item_opt, items)) => {
516+
message::app(Message::TabRescan(location, parent_item_opt, items))
517+
}
510518
Err(err) => {
511519
log::warn!("failed to rescan: {}", err);
512520
message::none()
@@ -1408,74 +1416,85 @@ impl Application for App {
14081416
}
14091417
return Command::batch(commands);
14101418
}
1411-
Message::TabRescan(mut items) => {
1412-
// Filter
1413-
if let Some(filter_i) = self.filter_selected {
1414-
if let Some(filter) = self.filters.get(filter_i) {
1415-
// Parse filters
1416-
let mut parsed_globs = Vec::new();
1417-
let mut parsed_mimes = Vec::new();
1418-
for pattern in filter.patterns.iter() {
1419-
match pattern {
1420-
DialogFilterPattern::Glob(value) => {
1421-
match glob::Pattern::new(value) {
1422-
Ok(glob) => parsed_globs.push(glob),
1423-
Err(err) => {
1424-
log::warn!("failed to parse glob {:?}: {}", value, err);
1419+
Message::TabRescan(location, parent_item_opt, mut items) => {
1420+
if location == self.tab.location {
1421+
// Filter
1422+
if let Some(filter_i) = self.filter_selected {
1423+
if let Some(filter) = self.filters.get(filter_i) {
1424+
// Parse filters
1425+
let mut parsed_globs = Vec::new();
1426+
let mut parsed_mimes = Vec::new();
1427+
for pattern in filter.patterns.iter() {
1428+
match pattern {
1429+
DialogFilterPattern::Glob(value) => {
1430+
match glob::Pattern::new(value) {
1431+
Ok(glob) => parsed_globs.push(glob),
1432+
Err(err) => {
1433+
log::warn!(
1434+
"failed to parse glob {:?}: {}",
1435+
value,
1436+
err
1437+
);
1438+
}
14251439
}
14261440
}
1427-
}
1428-
DialogFilterPattern::Mime(value) => {
1429-
match mime_guess::Mime::from_str(value) {
1430-
Ok(mime) => parsed_mimes.push(mime),
1431-
Err(err) => {
1432-
log::warn!("failed to parse mime {:?}: {}", value, err);
1441+
DialogFilterPattern::Mime(value) => {
1442+
match mime_guess::Mime::from_str(value) {
1443+
Ok(mime) => parsed_mimes.push(mime),
1444+
Err(err) => {
1445+
log::warn!(
1446+
"failed to parse mime {:?}: {}",
1447+
value,
1448+
err
1449+
);
1450+
}
14331451
}
14341452
}
14351453
}
14361454
}
1437-
}
1438-
1439-
items.retain(|item| {
1440-
if item.metadata.is_dir() {
1441-
// Directories are always shown
1442-
return true;
1443-
}
14441455

1445-
// Check for mime type match (first because it is faster)
1446-
for mime in parsed_mimes.iter() {
1447-
if mime == &item.mime {
1456+
items.retain(|item| {
1457+
if item.metadata.is_dir() {
1458+
// Directories are always shown
14481459
return true;
14491460
}
1450-
}
14511461

1452-
// Check for glob match (last because it is slower)
1453-
for glob in parsed_globs.iter() {
1454-
if glob.matches(&item.name) {
1455-
return true;
1462+
// Check for mime type match (first because it is faster)
1463+
for mime in parsed_mimes.iter() {
1464+
if mime == &item.mime {
1465+
return true;
1466+
}
1467+
}
1468+
1469+
// Check for glob match (last because it is slower)
1470+
for glob in parsed_globs.iter() {
1471+
if glob.matches(&item.name) {
1472+
return true;
1473+
}
14561474
}
1457-
}
14581475

1459-
// No filters matched
1460-
false
1461-
});
1476+
// No filters matched
1477+
false
1478+
});
1479+
}
14621480
}
1463-
}
14641481

1465-
// Select based on filename
1466-
if let DialogKind::SaveFile { filename } = &self.flags.kind {
1467-
for item in items.iter_mut() {
1468-
item.selected = &item.name == filename;
1482+
// Select based on filename
1483+
if let DialogKind::SaveFile { filename } = &self.flags.kind {
1484+
for item in items.iter_mut() {
1485+
item.selected = &item.name == filename;
1486+
}
14691487
}
1470-
}
14711488

1472-
self.tab.set_items(items);
1489+
self.tab.parent_item_opt = parent_item_opt;
1490+
self.tab.set_items(items);
14731491

1474-
// Reset focus on location change
1475-
if self.search_get().is_some() {
1476-
return widget::text_input::focus(self.search_id.clone());
1477-
} else {
1478-
return widget::text_input::focus(self.filename_id.clone());
1492+
// Reset focus on location change
1493+
if self.search_get().is_some() {
1494+
return widget::text_input::focus(self.search_id.clone());
1495+
} else {
1496+
return widget::text_input::focus(self.filename_id.clone());
1497+
}
14791498
}
14801499
}
14811500
Message::TabView(view) => {

src/tab.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,8 @@ impl Location {
909909
}
910910
}
911911

912-
pub fn scan(&self, sizes: IconSizes) -> Vec<Item> {
913-
match self {
912+
pub fn scan(&self, sizes: IconSizes) -> (Option<Item>, Vec<Item>) {
913+
let items = match self {
914914
Self::Desktop(path, display, desktop_config) => {
915915
scan_desktop(path, display, *desktop_config, sizes)
916916
}
@@ -922,7 +922,19 @@ impl Location {
922922
Self::Trash => scan_trash(sizes),
923923
Self::Recents => scan_recents(sizes),
924924
Self::Network(uri, _) => scan_network(uri, sizes),
925-
}
925+
};
926+
let parent_item_opt = match self.path_opt() {
927+
Some(path) => match item_from_path(path, sizes) {
928+
Ok(item) => Some(item),
929+
Err(err) => {
930+
log::warn!("failed to get item for {:?}: {}", path, err);
931+
None
932+
}
933+
},
934+
//TODO: support other locations?
935+
None => None,
936+
};
937+
(parent_item_opt, items)
926938
}
927939
}
928940

@@ -1535,6 +1547,7 @@ pub struct Tab {
15351547
pub sort_name: HeadingOptions,
15361548
pub sort_direction: bool,
15371549
pub gallery: bool,
1550+
pub(crate) parent_item_opt: Option<Item>,
15381551
pub(crate) items_opt: Option<Vec<Item>>,
15391552
pub dnd_hovered: Option<(Location, Instant)>,
15401553
scrollable_id: widget::Id,
@@ -1607,6 +1620,7 @@ impl Tab {
16071620
sort_name: HeadingOptions::Name,
16081621
sort_direction: true,
16091622
gallery: false,
1623+
parent_item_opt: None,
16101624
items_opt: None,
16111625
scrollable_id: widget::Id::unique(),
16121626
select_focus: None,

0 commit comments

Comments
 (0)