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
pub fn reload(&self, page_position: Option<i32>) {
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) {
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() {
let request = uri.to_string();
page.navigation.set_request(&request);
client.handle(&request);
client.handle(&request, true);
}
}
});
@ -98,10 +98,10 @@ impl Item {
action.load.connect_activate({
let page = page.clone();
let client = client.clone();
move |request| {
move |request, is_snap_history| {
if let Some(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({
let page = page.clone();
let client = client.clone();
move |_, _| client.handle(&page.navigation.request())
move |_, _| client.handle(&page.navigation.request(), true)
});
action.reload.connect_enabled_notify({
@ -151,7 +151,7 @@ impl Item {
if let Some(request) = request {
page.navigation.set_request(request);
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 load = load.clone();
move |request| load.activate(Some(&request))
move |request| load.activate(Some(&request), false)
}));
Self {

View File

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

View File

@ -36,7 +36,7 @@ impl Client {
/// Route tab item `request` to protocol driver
/// * 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
self.page.browser_action.escape.activate(None);
@ -61,8 +61,14 @@ impl Client {
match result {
// route by scheme
Ok(uri) => match uri.scheme().as_str() {
"file" => driver.file.handle(uri, feature, cancellable),
"gemini" | "titan" => driver.gemini.handle(uri, feature, cancellable),
"file" => driver
.file
.handle(uri, feature, cancellable, is_snap_history),
"gemini" | "titan" => {
driver
.gemini
.handle(uri, feature, cancellable, is_snap_history)
}
scheme => {
// no scheme match driver, complete with failure message
let status = page.content.to_status_failure();
@ -74,7 +80,10 @@ impl Client {
}
},
// 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
}
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 gtk::{
gio::{File, FileQueryInfoFlags, FileType},
@ -36,7 +42,7 @@ impl File {
let page = self.page.clone();
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(
"standard::content-type",
FileQueryInfoFlags::NONE,

View File

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

View File

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

View File

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

View File

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