mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-03-13 06:01:21 +00:00
group request history by host names
This commit is contained in:
parent
c403039abc
commit
d10987ff4e
@ -1,14 +1,16 @@
|
||||
use super::{BrowserAction, Profile, WindowAction};
|
||||
use gtk::{
|
||||
gio::{self},
|
||||
glib::{GString, Uri},
|
||||
prelude::{ActionExt, EditableExt, ToVariant},
|
||||
Align, MenuButton,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
// Config options
|
||||
|
||||
const LABEL_MAX_LENGTH: usize = 32;
|
||||
const LABEL_MAX_LENGTH: usize = 28;
|
||||
pub struct Menu {
|
||||
pub menu_button: MenuButton,
|
||||
}
|
||||
@ -192,7 +194,7 @@ impl Menu {
|
||||
// Bookmarks
|
||||
main_bookmarks.remove_all();
|
||||
for request in profile.bookmark.memory.recent() {
|
||||
let menu_item = gio::MenuItem::new(Some(&label(&request, LABEL_MAX_LENGTH)), None);
|
||||
let menu_item = gio::MenuItem::new(Some(&ellipsize(&request, LABEL_MAX_LENGTH)), None);
|
||||
menu_item.set_action_and_target_value(Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id,
|
||||
@ -210,7 +212,7 @@ impl Menu {
|
||||
main_history_tab.remove_all();
|
||||
for item in profile.history.memory.tab.recent() {
|
||||
let item_request = item.page.navigation.request.widget.entry.text(); // @TODO restore entire `Item`
|
||||
let menu_item = gio::MenuItem::new(Some(&label(&item_request, LABEL_MAX_LENGTH)), None);
|
||||
let menu_item = gio::MenuItem::new(Some(&ellipsize(&item_request, LABEL_MAX_LENGTH)), None);
|
||||
menu_item.set_action_and_target_value(Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id,
|
||||
@ -221,16 +223,33 @@ impl Menu {
|
||||
}
|
||||
|
||||
// Recently visited history
|
||||
// * in first iteration, group records by it hostname
|
||||
// * in second iteration, collect uri path as the menu sub-item label
|
||||
main_history_request.remove_all();
|
||||
for request in profile.history.memory.request.recent() {
|
||||
let menu_item = gio::MenuItem::new(Some(&label(&request, LABEL_MAX_LENGTH)), None);
|
||||
menu_item.set_action_and_target_value(Some(&format!(
|
||||
|
||||
let mut list: IndexMap<GString, Vec<Uri>> = IndexMap::new();
|
||||
for uri in profile.history.memory.request.recent() {
|
||||
list.entry(match uri.host() {
|
||||
Some(host) => host,
|
||||
None => uri.to_str(),
|
||||
}).or_default().push(uri);
|
||||
}
|
||||
|
||||
for (group, items) in list {
|
||||
let list = gio::Menu::new();
|
||||
for uri in items {
|
||||
let item = gio::MenuItem::new(Some(&ellipsize(
|
||||
&uri_to_label(&uri),
|
||||
LABEL_MAX_LENGTH
|
||||
)), None);
|
||||
item.set_action_and_target_value(Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id,
|
||||
window_action.open.simple_action.name()
|
||||
)), Some(&request.to_variant()));
|
||||
|
||||
main_history_request.append_item(&menu_item);
|
||||
)), Some(&uri.to_string().to_variant()));
|
||||
list.append_item(&item);
|
||||
}
|
||||
main_history_request.append_submenu(Some(&group), &list);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -242,14 +261,9 @@ impl Menu {
|
||||
}
|
||||
}
|
||||
|
||||
/// Format dynamically generated strings for menu item labels
|
||||
/// * trim gemini scheme prefix
|
||||
/// * trim slash postfix
|
||||
/// Format dynamically generated strings for menu item label
|
||||
/// * crop resulting string at the middle position on new `value` longer than `limit`
|
||||
fn label(value: &str, limit: usize) -> String {
|
||||
let value = value.trim_start_matches("gemini://");
|
||||
let value = value.trim_end_matches('/');
|
||||
|
||||
fn ellipsize(value: &str, limit: usize) -> String {
|
||||
if value.len() <= limit {
|
||||
return value.to_string();
|
||||
}
|
||||
@ -258,3 +272,12 @@ fn label(value: &str, limit: usize) -> String {
|
||||
|
||||
format!("{}..{}", &value[..length], &value[value.len() - length..])
|
||||
}
|
||||
|
||||
fn uri_to_label(uri: &Uri) -> GString {
|
||||
let path = uri.path();
|
||||
if path == "/" {
|
||||
uri.host().unwrap_or(uri.to_str())
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use gtk::{
|
||||
gdk::Texture,
|
||||
gdk_pixbuf::Pixbuf,
|
||||
gio::SocketClientEvent,
|
||||
glib::{gformat, DateTime, GString, Priority, Uri, UriFlags, UriHideFlags},
|
||||
glib::{gformat, GString, Priority, Uri, UriFlags, UriHideFlags},
|
||||
prelude::{EditableExt, FileExt, SocketClientExt},
|
||||
};
|
||||
use sqlite::Transaction;
|
||||
@ -234,7 +234,7 @@ impl Page {
|
||||
scheme => {
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(&self.profile, &self.navigation);
|
||||
snap_history(&self.profile, &self.navigation, Some(uri));
|
||||
}
|
||||
|
||||
// Update widget
|
||||
@ -322,7 +322,7 @@ impl Page {
|
||||
self.navigation.restore(transaction, &record.id)?;
|
||||
// Make initial page history snap using `navigation` values restored
|
||||
// * just to have back/forward navigation ability
|
||||
snap_history(&self.profile, &self.navigation);
|
||||
snap_history(&self.profile, &self.navigation, None);
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
@ -478,7 +478,7 @@ impl Page {
|
||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-20
|
||||
response::meta::Status::Success => {
|
||||
if is_history {
|
||||
snap_history(&profile, &navigation);
|
||||
snap_history(&profile, &navigation, Some(&uri));
|
||||
}
|
||||
if is_download {
|
||||
// Init download widget
|
||||
@ -806,7 +806,7 @@ impl Page {
|
||||
response::meta::Status::CertificateInvalid => {
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(&profile, &navigation);
|
||||
snap_history(&profile, &navigation, Some(&uri));
|
||||
}
|
||||
|
||||
// Update widget
|
||||
@ -831,7 +831,7 @@ impl Page {
|
||||
_ => {
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(&profile, &navigation);
|
||||
snap_history(&profile, &navigation, Some(&uri));
|
||||
}
|
||||
|
||||
// Update widget
|
||||
@ -854,7 +854,7 @@ impl Page {
|
||||
Err(e) => {
|
||||
// Add history record
|
||||
if is_history {
|
||||
snap_history(&profile, &navigation);
|
||||
snap_history(&profile, &navigation, Some(&uri));
|
||||
}
|
||||
|
||||
// Update widget
|
||||
@ -921,15 +921,13 @@ fn is_external_uri(subject: &Uri, base: &Uri) -> bool {
|
||||
|
||||
/// Make new history record for given `navigation` object
|
||||
/// * applies on shared conditions match only
|
||||
fn snap_history(profile: &Profile, navigation: &Navigation) {
|
||||
fn snap_history(profile: &Profile, navigation: &Navigation, uri: Option<&Uri>) {
|
||||
let request = navigation.request.widget.entry.text();
|
||||
|
||||
// Add new record into the global memory index (used in global menu)
|
||||
profile
|
||||
.history
|
||||
.memory
|
||||
.request
|
||||
.set(request.clone(), DateTime::now_local().unwrap().to_unix());
|
||||
if let Some(uri) = uri {
|
||||
profile.history.memory.request.set(uri);
|
||||
}
|
||||
|
||||
// Add new record into the page navigation history
|
||||
if match navigation.history.current() {
|
||||
|
@ -1,9 +1,10 @@
|
||||
use gtk::glib::GString;
|
||||
use gtk::glib::{DateTime, GString, Uri};
|
||||
use itertools::Itertools;
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
pub struct Value {
|
||||
pub unix_timestamp: i64,
|
||||
pub uri: Uri,
|
||||
}
|
||||
|
||||
/// Recent request history
|
||||
@ -31,23 +32,27 @@ impl Request {
|
||||
|
||||
/// Add new record with `request` as key and `unix_timestamp` as value
|
||||
/// * replace with new value if `request` already exists
|
||||
pub fn set(&self, request: GString, unix_timestamp: i64) {
|
||||
self.index
|
||||
.borrow_mut()
|
||||
.insert(request, Value { unix_timestamp });
|
||||
pub fn set(&self, uri: &Uri) {
|
||||
self.index.borrow_mut().insert(
|
||||
uri.to_str(),
|
||||
Value {
|
||||
unix_timestamp: DateTime::now_local().unwrap().to_unix(),
|
||||
uri: uri.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Get recent requests vector
|
||||
/// Get recent records vector
|
||||
/// * sorted by `unix_timestamp` DESC
|
||||
pub fn recent(&self) -> Vec<GString> {
|
||||
let mut recent: Vec<GString> = Vec::new();
|
||||
for (request, _) in self
|
||||
pub fn recent(&self) -> Vec<Uri> {
|
||||
let mut recent: Vec<Uri> = Vec::new();
|
||||
for (_, value) in self
|
||||
.index
|
||||
.borrow()
|
||||
.iter()
|
||||
.sorted_by(|a, b| Ord::cmp(&b.1.unix_timestamp, &a.1.unix_timestamp))
|
||||
{
|
||||
recent.push(request.clone())
|
||||
recent.push(value.uri.clone())
|
||||
}
|
||||
recent
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user