recent section
This commit is contained in:
parent
aebc652006
commit
056724268e
6 changed files with 167 additions and 16 deletions
34
Cargo.lock
generated
34
Cargo.lock
generated
|
|
@ -1166,6 +1166,7 @@ dependencies = [
|
|||
"open",
|
||||
"paste",
|
||||
"rayon",
|
||||
"recently-used-xbel",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
|
|
@ -1446,6 +1447,15 @@ dependencies = [
|
|||
"dirs-sys 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
|
|
@ -4598,6 +4608,18 @@ dependencies = [
|
|||
"font-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "recently-used-xbel"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9533c371523034735c8c68da31004561dd011df9d45d0e5886c141858a7d17"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"serde",
|
||||
"serde-xml-rs",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
|
|
@ -4948,6 +4970,18 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-xml-rs"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ i18n-embed = { version = "0.14", features = [
|
|||
i18n-embed-fl = "0.7"
|
||||
rust-embed = "8"
|
||||
slotmap = "1.0.7"
|
||||
recently-used-xbel = "1.0.0"
|
||||
|
||||
[dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic.git"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ filesystem = Filesystem
|
|||
home = Home
|
||||
notification-in-progress = File operations are in progress.
|
||||
trash = Trash
|
||||
recents = Recents
|
||||
undo = Undo
|
||||
|
||||
# List view
|
||||
|
|
|
|||
13
src/app.rs
13
src/app.rs
|
|
@ -107,6 +107,7 @@ pub enum Action {
|
|||
ZoomDefault,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
Recents
|
||||
}
|
||||
|
||||
impl Action {
|
||||
|
|
@ -164,6 +165,7 @@ impl Action {
|
|||
Action::ZoomDefault => Message::TabMessage(entity_opt, tab::Message::ZoomDefault),
|
||||
Action::ZoomIn => Message::TabMessage(entity_opt, tab::Message::ZoomIn),
|
||||
Action::ZoomOut => Message::TabMessage(entity_opt, tab::Message::ZoomOut),
|
||||
Action::Recents => Message::Recents
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,6 +269,7 @@ pub enum Message {
|
|||
DndExitTab,
|
||||
DndDropTab(Entity, Option<ClipboardPaste>, DndAction),
|
||||
DndDropNav(Entity, Option<ClipboardPaste>, DndAction),
|
||||
Recents
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
|
|
@ -509,6 +512,13 @@ impl App {
|
|||
|
||||
fn update_nav_model(&mut self) {
|
||||
let mut nav_model = segmented_button::ModelBuilder::default();
|
||||
|
||||
nav_model = nav_model.insert(|b| {
|
||||
b.text(fl!("recents"))
|
||||
.icon(widget::icon::from_name("user-bookmarks-symbolic")) //TODO change icon with a watch icon like gnome recents
|
||||
.data(Location::Recents)
|
||||
});
|
||||
|
||||
for (favorite_i, favorite) in self.config.favorites.iter().enumerate() {
|
||||
if let Some(path) = favorite.path_opt() {
|
||||
let name = if matches!(favorite, Favorite::Home) {
|
||||
|
|
@ -2233,6 +2243,9 @@ impl Application for App {
|
|||
self.dialog_pages.push_front(DialogPage::EmptyTrash);
|
||||
}
|
||||
},
|
||||
Message::Recents => {
|
||||
return self.open_tab(Location::Recents);
|
||||
}
|
||||
}
|
||||
|
||||
Command::none()
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ pub fn context_menu<'a>(
|
|||
|
||||
let mut children: Vec<Element<_>> = Vec::new();
|
||||
match tab.location {
|
||||
Location::Path(_) | Location::Search(_, _) => {
|
||||
Location::Path(_) | Location::Search(_, _) | Location::Recents => {
|
||||
if selected > 0 {
|
||||
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
|
||||
children.push(menu_item(fl!("open"), Action::Open).into());
|
||||
|
|
|
|||
132
src/tab.rs
132
src/tab.rs
|
|
@ -33,21 +33,6 @@ use cosmic::{
|
|||
Element,
|
||||
};
|
||||
|
||||
use mime_guess::{mime, Mime};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
fs::{self, Metadata},
|
||||
num::NonZeroU16,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{self, Action},
|
||||
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
||||
|
|
@ -60,6 +45,24 @@ use crate::{
|
|||
mime_icon::{mime_for_path, mime_icon},
|
||||
mouse_area,
|
||||
};
|
||||
use chrono::{DateTime, ParseError, Utc};
|
||||
use mime_guess::{mime, Mime};
|
||||
use once_cell::sync::Lazy;
|
||||
use recently_used_xbel::{Error, RecentlyUsed};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Reverse;
|
||||
use std::iter::from_fn;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
fs::{self, Metadata},
|
||||
num::NonZeroU16,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub const DOUBLE_CLICK_DURATION: Duration = Duration::from_millis(500);
|
||||
pub const HOVER_DURATION: Duration = Duration::from_millis(1600);
|
||||
|
|
@ -543,11 +546,85 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
|
|||
items
|
||||
}
|
||||
|
||||
fn uri_to_path(uri: String) -> Option<PathBuf> {
|
||||
//TODO support for external drive or cloud?
|
||||
if uri.starts_with("file://") {
|
||||
let path_str = &uri[7..];
|
||||
Some(PathBuf::from(path_str))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan_recents(sizes: IconSizes) -> Vec<Item> {
|
||||
let mut recent_files = recently_used_xbel::parse_file();
|
||||
|
||||
let mut recents = Vec::new();
|
||||
|
||||
match recent_files {
|
||||
Ok(recent_files) => {
|
||||
for bookmark in recent_files.bookmarks {
|
||||
let uri = bookmark.href;
|
||||
let path = match uri_to_path(uri) {
|
||||
None => continue,
|
||||
Some(path) => path,
|
||||
};
|
||||
let last_edit = match bookmark.modified.parse::<DateTime<Utc>>() {
|
||||
Ok(last_edit) => last_edit,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let last_visit = match bookmark.visited.parse::<DateTime<Utc>>() {
|
||||
Ok(last_visit) => last_visit,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let path_buf = PathBuf::from(path);
|
||||
let path_exist = path_buf.exists();
|
||||
|
||||
if path_exist {
|
||||
let file_name = path_buf.file_name();
|
||||
|
||||
if let Some(name) = file_name {
|
||||
let name = name.to_string_lossy().to_string();
|
||||
|
||||
let metadata = match path_buf.metadata() {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
"failed to read metadata for entry at {:?}: {}",
|
||||
path_buf.clone(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let item = item_from_entry(path_buf, name, metadata, sizes);
|
||||
recents.push((item, if last_edit.le(&last_visit) { last_edit } else { last_visit }))
|
||||
}
|
||||
} else {
|
||||
log::warn!("recent file path not exist: {:?}", path_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Error reading recent files: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
recents.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
|
||||
let recent_items: Vec<Item> = recents.into_iter().take(50).map(|(item, _)| item).collect();
|
||||
|
||||
log::info!("items: {}", recent_items.len());
|
||||
|
||||
recent_items
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Location {
|
||||
Path(PathBuf),
|
||||
Search(PathBuf, String),
|
||||
Trash,
|
||||
Recents,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Location {
|
||||
|
|
@ -556,6 +633,7 @@ impl std::fmt::Display for Location {
|
|||
Self::Path(path) => write!(f, "{}", path.display()),
|
||||
Self::Search(path, term) => write!(f, "search {} for {}", path.display(), term),
|
||||
Self::Trash => write!(f, "trash"),
|
||||
Self::Recents => write!(f, "recents"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -566,6 +644,7 @@ impl Location {
|
|||
Self::Path(path) => scan_path(path, sizes),
|
||||
Self::Search(path, term) => scan_search(path, term, sizes),
|
||||
Self::Trash => scan_trash(sizes),
|
||||
Self::Recents => scan_recents(sizes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -979,6 +1058,9 @@ impl Tab {
|
|||
Location::Trash => {
|
||||
fl!("trash")
|
||||
}
|
||||
Location::Recents => {
|
||||
fl!("recents")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1648,6 +1730,7 @@ impl Tab {
|
|||
Location::Trash => {
|
||||
cd = Some(location);
|
||||
}
|
||||
Location::Recents => cd = Some(location),
|
||||
}
|
||||
}
|
||||
Message::LocationUp => {
|
||||
|
|
@ -1789,6 +1872,9 @@ impl Tab {
|
|||
Location::Trash => {
|
||||
log::warn!("Copy to trash is not supported.");
|
||||
}
|
||||
Location::Recents => {
|
||||
log::warn!("Copy to recents is not supported.");
|
||||
}
|
||||
};
|
||||
}
|
||||
Message::Drop(None) => {
|
||||
|
|
@ -1861,6 +1947,7 @@ impl Tab {
|
|||
Location::Path(path) => path.is_dir(),
|
||||
Location::Search(path, _term) => path.is_dir(),
|
||||
Location::Trash => true,
|
||||
Location::Recents => true,
|
||||
} {
|
||||
self.change_location(&location, history_i_opt);
|
||||
commands.push(Command::ChangeLocation(self.title(), location));
|
||||
|
|
@ -2254,6 +2341,21 @@ impl Tab {
|
|||
.into(),
|
||||
);
|
||||
}
|
||||
Location::Recents => {
|
||||
let mut row = widget::row::with_capacity(2)
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(space_xxxs);
|
||||
row = row.push(widget::icon::from_name("user-bookmarks-symbolic").size(16)); //TODO change with recent icon
|
||||
row = row.push(widget::text::heading(fl!("recents")));
|
||||
|
||||
children.push(
|
||||
widget::button(row)
|
||||
.padding(space_xxxs)
|
||||
.on_press(Message::Location(Location::Recents))
|
||||
.style(theme::Button::Text)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for child in children {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue