restore optional history snaps

This commit is contained in:
yggverse 2025-03-12 11:52:05 +02:00
parent 0dbc8def65
commit 7803aa1c44
12 changed files with 141 additions and 72 deletions

View file

@ -284,13 +284,13 @@ impl Tab {
/// Reload page at `i32` position or selected page on `None` given /// Reload page at `i32` position or selected page on `None` given
pub fn reload(&self, page_position: Option<i32>) { pub fn reload(&self, page_position: Option<i32>) {
if let Some(item) = self.item(page_position) { if let Some(item) = self.item(page_position) {
item.client.handle(&item.page.navigation.request()); item.client.handle(&item.page.navigation.request(), true);
} }
} }
pub fn open(&self, page_position: Option<i32>, request: &str) { pub fn open(&self, page_position: Option<i32>, request: &str) {
if let Some(item) = self.item(page_position) { if let Some(item) = self.item(page_position) {
item.action.load.activate(Some(request)); item.action.load.activate(Some(request), true);
} }
} }

View file

@ -90,7 +90,7 @@ impl Item {
if let Some(uri) = page.navigation.home() { if let Some(uri) = page.navigation.home() {
let request = uri.to_string(); let request = uri.to_string();
page.navigation.set_request(&request); page.navigation.set_request(&request);
client.handle(&request); client.handle(&request, true);
} }
} }
}); });
@ -98,10 +98,10 @@ impl Item {
action.load.connect_activate({ action.load.connect_activate({
let page = page.clone(); let page = page.clone();
let client = client.clone(); let client = client.clone();
move |request| { move |request, is_snap_history| {
if let Some(request) = request { if let Some(request) = request {
page.navigation.set_request(&request); page.navigation.set_request(&request);
client.handle(&request); client.handle(&request, is_snap_history);
} }
} }
}); });
@ -114,7 +114,7 @@ impl Item {
action.reload.connect_activate({ action.reload.connect_activate({
let page = page.clone(); let page = page.clone();
let client = client.clone(); let client = client.clone();
move |_, _| client.handle(&page.navigation.request()) move |_, _| client.handle(&page.navigation.request(), true)
}); });
action.reload.connect_enabled_notify({ action.reload.connect_enabled_notify({
@ -151,7 +151,7 @@ impl Item {
if let Some(request) = request { if let Some(request) = request {
page.navigation.set_request(request); page.navigation.set_request(request);
if is_load { if is_load {
client.handle(request) client.handle(request, true)
} }
} }

View file

@ -40,7 +40,7 @@ impl Action {
let history = Rc::new(History::build({ let history = Rc::new(History::build({
let load = load.clone(); let load = load.clone();
move |request| load.activate(Some(&request)) move |request| load.activate(Some(&request), false)
})); }));
Self { Self {

View file

@ -23,7 +23,7 @@ impl Load {
Self { Self {
simple_action: SimpleAction::new( simple_action: SimpleAction::new(
&uuid_string_random(), &uuid_string_random(),
Some(&<String>::static_variant_type()), Some(&<(String, bool)>::static_variant_type()),
), ),
} }
} }
@ -32,25 +32,30 @@ impl Load {
/// Emit [activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal /// Emit [activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
/// with formatted for this action [Variant](https://docs.gtk.org/glib/struct.Variant.html) value /// with formatted for this action [Variant](https://docs.gtk.org/glib/struct.Variant.html) value
pub fn activate(&self, request: Option<&str>) { pub fn activate(&self, request: Option<&str>, is_history: bool) {
self.simple_action self.simple_action.activate(Some(
.activate(Some(&(request.unwrap_or_default()).to_variant())); &(request.unwrap_or_default(), is_history).to_variant(),
));
} }
// Events // Events
/// Define callback function for /// Define callback function for
/// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal /// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
pub fn connect_activate(&self, callback: impl Fn(Option<GString>) + 'static) { pub fn connect_activate(&self, callback: impl Fn(Option<GString>, bool) + 'static) {
self.simple_action.connect_activate(move |_, this| { self.simple_action.connect_activate(move |_, this| {
let request = this let (request, is_history) = this
.expect("Expected `request` variant") .expect("Expected (`request`,`is_history`) variant")
.get::<String>() .get::<(String, bool)>()
.expect("Parameter type does not match `String`"); .expect("Parameter type does not match (`String`,`bool`) tuple");
callback(match request.is_empty() {
callback(
match request.is_empty() {
true => None, true => None,
false => Some(request.into()), false => Some(request.into()),
}) },
is_history,
)
}); });
} }
} }

View file

@ -36,7 +36,7 @@ impl Client {
/// Route tab item `request` to protocol driver /// Route tab item `request` to protocol driver
/// * or `navigation` entry if the value not provided /// * or `navigation` entry if the value not provided
pub fn handle(&self, request: &str) { pub fn handle(&self, request: &str, is_snap_history: bool) {
// Move focus out from navigation entry @TODO // Move focus out from navigation entry @TODO
self.page.browser_action.escape.activate(None); self.page.browser_action.escape.activate(None);
@ -61,8 +61,14 @@ impl Client {
match result { match result {
// route by scheme // route by scheme
Ok(uri) => match uri.scheme().as_str() { Ok(uri) => match uri.scheme().as_str() {
"file" => driver.file.handle(uri, feature, cancellable), "file" => driver
"gemini" | "titan" => driver.gemini.handle(uri, feature, cancellable), .file
.handle(uri, feature, cancellable, is_snap_history),
"gemini" | "titan" => {
driver
.gemini
.handle(uri, feature, cancellable, is_snap_history)
}
scheme => { scheme => {
// no scheme match driver, complete with failure message // no scheme match driver, complete with failure message
let status = page.content.to_status_failure(); let status = page.content.to_status_failure();
@ -74,7 +80,10 @@ impl Client {
} }
}, },
// begin redirection to new address suggested // begin redirection to new address suggested
Err(query) => page.item_action.load.activate(Some(&query)), Err(query) => page
.item_action
.load
.activate(Some(&query), is_snap_history),
} }
} }
}) })

View file

@ -20,7 +20,13 @@ impl File {
Self { page: page.clone() } // @TODO Self { page: page.clone() } // @TODO
} }
pub fn handle(&self, uri: Uri, feature: Rc<Feature>, cancellable: Cancellable) { pub fn handle(
&self,
uri: Uri,
feature: Rc<Feature>,
cancellable: Cancellable,
is_snap_history: bool,
) {
use directory::Directory; use directory::Directory;
use gtk::{ use gtk::{
gio::{File, FileQueryInfoFlags, FileType}, gio::{File, FileQueryInfoFlags, FileType},
@ -36,7 +42,7 @@ impl File {
let page = self.page.clone(); let page = self.page.clone();
match file.query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) { match file.query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) {
FileType::Directory => Directory { file }.handle(&page), FileType::Directory => Directory { file }.handle(&page, is_snap_history),
_ => file.clone().query_info_async( _ => file.clone().query_info_async(
"standard::content-type", "standard::content-type",
FileQueryInfoFlags::NONE, FileQueryInfoFlags::NONE,

View file

@ -6,7 +6,7 @@ pub struct Directory {
} }
impl Directory { impl Directory {
pub fn handle(&self, page: &Rc<super::Page>) { pub fn handle(&self, page: &Rc<super::Page>, is_snap_history: bool) {
page.set_progress(1.0); page.set_progress(1.0);
page.content.to_directory( page.content.to_directory(
&self.file, &self.file,
@ -20,16 +20,21 @@ impl Directory {
{ {
let page = page.clone(); let page = page.clone();
move |file| { move |file| {
page.item_action.load.activate(Some(&format!( page.item_action.load.activate(
Some(&format!(
"file://{}", "file://{}",
file.path().unwrap().to_str().unwrap() file.path().unwrap().to_str().unwrap()
))) )),
is_snap_history,
)
} }
}, },
), ),
); );
page.set_title(&self.file.parse_name()); page.set_title(&self.file.parse_name());
if is_snap_history {
page.snap_history(); page.snap_history();
}
page.window_action.find.simple_action.set_enabled(false); page.window_action.find.simple_action.set_enabled(false);
page.window_action.save_as.simple_action.set_enabled(false); page.window_action.save_as.simple_action.set_enabled(false);
} }

View file

@ -65,18 +65,27 @@ impl Gemini {
// Actions // Actions
pub fn handle(&self, uri: Uri, feature: Rc<Feature>, cancellable: Cancellable) { pub fn handle(
&self,
uri: Uri,
feature: Rc<Feature>,
cancellable: Cancellable,
is_snap_history: bool,
) {
use ggemini::client::connection::Request; use ggemini::client::connection::Request;
match uri.scheme().as_str() { match uri.scheme().as_str() {
"gemini" => handle( "gemini" => handle(
Request::Gemini { uri }, Request::Gemini { uri },
(
self.client.clone(), self.client.clone(),
self.page.clone(), self.page.clone(),
self.redirects.clone(), self.redirects.clone(),
feature, feature,
),
cancellable, cancellable,
None, None,
is_snap_history,
), ),
"titan" => { "titan" => {
self.page.input.set_new_titan({ self.page.input.set_new_titan({
@ -91,12 +100,15 @@ impl Gemini {
mime: header.mime.map(|mime| mime.into()), mime: header.mime.map(|mime| mime.into()),
token: header.token.map(|token| token.into()), token: header.token.map(|token| token.into()),
}, },
(
client.clone(), client.clone(),
page.clone(), page.clone(),
redirects.clone(), redirects.clone(),
feature.clone(), feature.clone(),
),
cancellable.clone(), cancellable.clone(),
Some(on_failure), Some(on_failure),
is_snap_history,
) )
} }
}); });
@ -111,12 +123,10 @@ impl Gemini {
fn handle( fn handle(
request: Request, request: Request,
client: Rc<Client>, (client, page, redirects, feature): (Rc<Client>, Rc<Page>, Rc<Cell<usize>>, Rc<Feature>),
page: Rc<Page>,
redirects: Rc<Cell<usize>>,
feature: Rc<Feature>,
cancellable: Cancellable, cancellable: Cancellable,
on_failure: Option<Box<dyn Fn()>>, on_failure: Option<Box<dyn Fn()>>,
is_snap_history: bool,
) { ) {
let uri = request.uri().clone(); let uri = request.uri().clone();
client.request_async( client.request_async(
@ -146,7 +156,9 @@ fn handle(
let title = input.to_string(); let title = input.to_string();
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&title); page.set_title(&title);
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
match input { match input {
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-10 // https://geminiprotocol.net/docs/protocol-specification.gmi#status-10
@ -230,7 +242,9 @@ fn handle(
); );
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
_ => match success.mime() { _ => match success.mime() {
@ -271,7 +285,9 @@ fn handle(
.find .find
.simple_action .simple_action
.set_enabled(true); .set_enabled(true);
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
Err(e) => { Err(e) => {
@ -279,7 +295,9 @@ fn handle(
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
}, },
@ -288,7 +306,9 @@ fn handle(
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
} }
} }
@ -298,7 +318,9 @@ fn handle(
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
} }
@ -343,7 +365,9 @@ fn handle(
} }
} }
page.set_progress(0.0); page.set_progress(0.0);
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
) )
@ -353,7 +377,9 @@ fn handle(
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
} }
} }
@ -368,7 +394,9 @@ fn handle(
status.set_description(Some(&format!("Content type `{mime}` yet not supported"))); status.set_description(Some(&format!("Content type `{mime}` yet not supported")));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
} }
@ -404,7 +432,7 @@ fn handle(
page.navigation.set_request(&target.to_string()); page.navigation.set_request(&target.to_string());
} }
redirects.replace(total); redirects.replace(total);
page.item_action.load.activate(Some(&target.to_string())); page.item_action.load.activate(Some(&target.to_string()), false);
} }
} }
Err(e) => { Err(e) => {
@ -426,7 +454,9 @@ fn handle(
status.set_description(Some(message.as_ref().unwrap_or(&certificate.to_string()))); status.set_description(Some(message.as_ref().unwrap_or(&certificate.to_string())));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
} }
} }
@ -441,7 +471,9 @@ fn handle(
status.set_description(Some(message.as_ref().unwrap_or(&temporary.to_string()))); status.set_description(Some(message.as_ref().unwrap_or(&temporary.to_string())));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
if let Some(callback) = on_failure { if let Some(callback) = on_failure {
callback() callback()
@ -458,7 +490,9 @@ fn handle(
status.set_description(Some(message.as_ref().unwrap_or(&permanent.to_string()))); status.set_description(Some(message.as_ref().unwrap_or(&permanent.to_string())));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
if let Some(callback) = on_failure { if let Some(callback) = on_failure {
callback() callback()
@ -472,7 +506,9 @@ fn handle(
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
page.set_progress(0.0); page.set_progress(0.0);
page.set_title(&status.title()); page.set_title(&status.title());
if is_snap_history {
page.snap_history(); page.snap_history();
}
redirects.replace(0); // reset redirects.replace(0); // reset
} }
} }

View file

@ -24,7 +24,9 @@ pub fn build(mime: &str, download: Option<(&Rc<ItemAction>, &Uri)>) -> StatusPag
let action = action.clone(); let action = action.clone();
let request = request.clone(); let request = request.clone();
move |_| { move |_| {
action.load.activate(Some(&format!("download:{}", request))); action
.load
.activate(Some(&format!("download:{}", request)), true)
} }
}); });

View file

@ -388,7 +388,7 @@ impl Gemini {
// Select link handler by scheme // Select link handler by scheme
return match uri.scheme().as_str() { return match uri.scheme().as_str() {
"gemini" | "titan" => { "gemini" | "titan" => {
item_action.load.activate(Some(&uri.to_str())) item_action.load.activate(Some(&uri.to_str()), true)
} }
// Scheme not supported, delegate // Scheme not supported, delegate
_ => UriLauncher::new(&uri.to_str()).launch( _ => UriLauncher::new(&uri.to_str()).launch(

View file

@ -81,11 +81,14 @@ impl Response for Box {
action_send.connect_activate({ action_send.connect_activate({
let form = form.clone(); let form = form.clone();
move |_, _| { move |_, _| {
item_action.load.activate(Some(&format!( item_action.load.activate(
Some(&format!(
"{}?{}", "{}?{}",
base.to_string_partial(UriHideFlags::QUERY), base.to_string_partial(UriHideFlags::QUERY),
Uri::escape_string(&form.text(), None, false), Uri::escape_string(&form.text(), None, false),
))) )),
false,
)
} }
}); });

View file

@ -59,11 +59,14 @@ impl Sensitive for Box {
action_send.connect_activate({ action_send.connect_activate({
let form = form.clone(); let form = form.clone();
move |_, _| { move |_, _| {
item_action.load.activate(Some(&format!( item_action.load.activate(
Some(&format!(
"{}?{}", "{}?{}",
base.to_string_partial(UriHideFlags::QUERY), base.to_string_partial(UriHideFlags::QUERY),
Uri::escape_string(&form.password_entry_row.text(), None, false), Uri::escape_string(&form.password_entry_row.text(), None, false),
))) )),
false,
)
} }
}); });