diff --git a/src/app/browser/window.rs b/src/app/browser/window.rs index 821e8582..ecedac68 100644 --- a/src/app/browser/window.rs +++ b/src/app/browser/window.rs @@ -93,16 +93,12 @@ impl Window { action.history_back.connect_activate({ let tab = tab.clone(); - move |position| { - tab.history_back(position); - } + move |position| tab.history_back(position) }); action.history_forward.connect_activate({ let tab = tab.clone(); - move |position| { - tab.history_forward(position); - } + move |position| tab.history_forward(position) }); action.load.on_activate({ @@ -114,9 +110,7 @@ impl Window { action.open.on_activate({ let tab = tab.clone(); - move |position, request| { - tab.open(position, request, true); - } + move |position, request| tab.open(position, request) }); // Init struct diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index c753651c..f685b9f8 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -284,13 +284,13 @@ impl Tab { /// Reload page at `i32` position or selected page on `None` given pub fn reload(&self, page_position: Option) { if let Some(item) = self.item(page_position) { - item.client.handle(&item.page.navigation.request(), true); + item.client.handle(&item.page.navigation.request()); } } - pub fn open(&self, page_position: Option, request: &str, is_snap_history: bool) { + pub fn open(&self, page_position: Option, request: &str) { if let Some(item) = self.item(page_position) { - item.action.load.activate(Some(request), is_snap_history); + item.action.load.activate(Some(request)); } } diff --git a/src/app/browser/window/tab/item.rs b/src/app/browser/window/tab/item.rs index 5f376d09..f4b915b5 100644 --- a/src/app/browser/window/tab/item.rs +++ b/src/app/browser/window/tab/item.rs @@ -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, true); + client.handle(&request); } } }); @@ -98,10 +98,10 @@ impl Item { action.load.connect_activate({ let page = page.clone(); let client = client.clone(); - move |request, is_history| { - if let Some(text) = request { - page.navigation.set_request(&text); - client.handle(&text, is_history); + move |request| { + if let Some(request) = request { + page.navigation.set_request(&request); + client.handle(&request); } } }); @@ -114,9 +114,7 @@ impl Item { action.reload.connect_activate({ let page = page.clone(); let client = client.clone(); - move |_, _| { - client.handle(&page.navigation.request(), true); - } + move |_, _| client.handle(&page.navigation.request()) }); action.reload.connect_enabled_notify({ @@ -150,10 +148,10 @@ impl Item { }); // Handle immediately on request - if let Some(text) = request { - page.navigation.set_request(text); + if let Some(request) = request { + page.navigation.set_request(request); if is_load { - client.handle(text, true); + client.handle(request) } } diff --git a/src/app/browser/window/tab/item/action.rs b/src/app/browser/window/tab/item/action.rs index 24bea278..b829dcaa 100644 --- a/src/app/browser/window/tab/item/action.rs +++ b/src/app/browser/window/tab/item/action.rs @@ -40,7 +40,7 @@ impl Action { let history = Rc::new(History::build({ let load = load.clone(); - move |request| load.activate(Some(&request), false) + move |request| load.activate(Some(&request)) })); Self { diff --git a/src/app/browser/window/tab/item/action/load.rs b/src/app/browser/window/tab/item/action/load.rs index e11da482..677f444b 100644 --- a/src/app/browser/window/tab/item/action/load.rs +++ b/src/app/browser/window/tab/item/action/load.rs @@ -32,30 +32,25 @@ 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>, is_history: bool) { - self.simple_action.activate(Some( - &(request.unwrap_or_default(), is_history).to_variant(), - )); + pub fn activate(&self, request: Option<&str>) { + self.simple_action + .activate(Some(&(request.unwrap_or_default()).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, bool) + 'static) { + pub fn connect_activate(&self, callback: impl Fn(Option) + 'static) { self.simple_action.connect_activate(move |_, this| { - 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, - ) + let request = this + .expect("Expected `request` variant") + .get::() + .expect("Parameter type does not match `String`"); + callback(match request.is_empty() { + true => None, + false => Some(request.into()), + }) }); } } diff --git a/src/app/browser/window/tab/item/client.rs b/src/app/browser/window/tab/item/client.rs index f6ea16dc..5cb2abe8 100644 --- a/src/app/browser/window/tab/item/client.rs +++ b/src/app/browser/window/tab/item/client.rs @@ -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, is_snap_history: bool) { + pub fn handle(&self, request: &str) { // Move focus out from navigation entry @TODO self.page.browser_action.escape.activate(None); @@ -61,18 +61,8 @@ impl Client { match result { // route by scheme Ok(uri) => match uri.scheme().as_str() { - "file" => { - if is_snap_history { - snap_history(&page); - } - driver.file.handle(uri, feature, cancellable) - } - "gemini" | "titan" => { - if is_snap_history { - snap_history(&page); - } - driver.gemini.handle(uri, feature, cancellable) - } + "file" => driver.file.handle(uri, feature, cancellable), + "gemini" | "titan" => driver.gemini.handle(uri, feature, cancellable), scheme => { // no scheme match driver, complete with failure message let status = page.content.to_status_failure(); @@ -84,10 +74,7 @@ impl Client { } }, // begin redirection to new address suggested - Err(query) => page - .item_action - .load - .activate(Some(&query), is_snap_history), + Err(query) => page.item_action.load.activate(Some(&query)), } } }) @@ -199,13 +186,3 @@ fn search(profile: &Profile, query: &str) -> Uri { ) .unwrap() // @TODO handle or skip extra URI parse by String return } - -/// Make new history record in related components -fn snap_history(page: &Page) { - page.item_action - .history - .add(page.navigation.request(), true); - page.profile - .history - .open(page.navigation.request(), Some(page.title())) -} diff --git a/src/app/browser/window/tab/item/client/driver/file/directory.rs b/src/app/browser/window/tab/item/client/driver/file/directory.rs index e86d7c18..b031164f 100644 --- a/src/app/browser/window/tab/item/client/driver/file/directory.rs +++ b/src/app/browser/window/tab/item/client/driver/file/directory.rs @@ -20,18 +20,16 @@ impl Directory { { let page = page.clone(); move |file| { - page.item_action.load.activate( - Some(&format!( - "file://{}", - file.path().unwrap().to_str().unwrap() - )), - true, - ) + page.item_action.load.activate(Some(&format!( + "file://{}", + file.path().unwrap().to_str().unwrap() + ))) } }, ), ); page.set_title(&self.file.parse_name()); + page.snap_history(); page.window_action.find.simple_action.set_enabled(false); page.window_action.save_as.simple_action.set_enabled(false); } diff --git a/src/app/browser/window/tab/item/client/driver/file/image.rs b/src/app/browser/window/tab/item/client/driver/file/image.rs index e05a11e8..5a5d3840 100644 --- a/src/app/browser/window/tab/item/client/driver/file/image.rs +++ b/src/app/browser/window/tab/item/client/driver/file/image.rs @@ -15,6 +15,7 @@ impl Image { }; page.set_title(&crate::tool::uri_to_title(uri)); page.set_progress(0.0); + page.snap_history(); page.window_action.find.simple_action.set_enabled(false); } } diff --git a/src/app/browser/window/tab/item/client/driver/file/status.rs b/src/app/browser/window/tab/item/client/driver/file/status.rs index 706b381b..31183541 100644 --- a/src/app/browser/window/tab/item/client/driver/file/status.rs +++ b/src/app/browser/window/tab/item/client/driver/file/status.rs @@ -10,6 +10,7 @@ impl Status { widget.set_description(Some(message)); page.set_title(&widget.title()); page.set_progress(0.0); + page.snap_history(); page.window_action.find.simple_action.set_enabled(false); } } diff --git a/src/app/browser/window/tab/item/client/driver/file/text.rs b/src/app/browser/window/tab/item/client/driver/file/text.rs index 407ec8fb..0f7a10eb 100644 --- a/src/app/browser/window/tab/item/client/driver/file/text.rs +++ b/src/app/browser/window/tab/item/client/driver/file/text.rs @@ -19,6 +19,7 @@ impl Text { None => crate::tool::uri_to_title(uri), }); page.set_progress(0.0); + page.snap_history(); page.window_action.find.simple_action.set_enabled(true); } } diff --git a/src/app/browser/window/tab/item/client/driver/gemini.rs b/src/app/browser/window/tab/item/client/driver/gemini.rs index 15237450..9ca839fb 100644 --- a/src/app/browser/window/tab/item/client/driver/gemini.rs +++ b/src/app/browser/window/tab/item/client/driver/gemini.rs @@ -102,6 +102,7 @@ impl Gemini { }); self.page.set_title("Titan input"); self.page.set_progress(0.0); + //self.page.snap_history(); } _ => panic!(), // unexpected } @@ -145,6 +146,7 @@ fn handle( let title = input.to_string(); page.set_progress(0.0); page.set_title(&title); + page.snap_history(); redirects.replace(0); // reset match input { // https://geminiprotocol.net/docs/protocol-specification.gmi#status-10 @@ -174,62 +176,61 @@ fn handle( { let cancellable = cancellable.clone(); let stream = connection.stream(); - move |file, action| { - match file.replace( - None, - false, - gtk::gio::FileCreateFlags::NONE, - Some(&cancellable), - ) { - Ok(file_output_stream) => { - use crate::tool::Format; - // Asynchronously read [IOStream](https://docs.gtk.org/gio/class.IOStream.html) - // to local [MemoryInputStream](https://docs.gtk.org/gio/class.MemoryInputStream.html) - // show bytes count in loading widget, validate max size for incoming data - // * no dependency of Gemini library here, feel free to use any other `IOStream` processor - file_output_stream::from_stream_async( - stream.clone(), - file_output_stream, - cancellable.clone(), - Priority::DEFAULT, - ( - 0x100000, // 1M bytes per chunk - None, // unlimited - 0, // initial totals - ), - ( - // on chunk - { - let action = action.clone(); - move |_, total| action.update.activate(&format!( - "Received {}...", - total.bytes() - )) - }, - // on complete - { - let action = action.clone(); - move |result| match result { - Ok((_, total)) => { - action.complete.activate(&format!( - "Saved to {} ({} total)", - file.parse_name(), - total.bytes() - )) - } - Err(e) => action.cancel.activate(&e.to_string()) + move |file, action| match file.replace( + None, + false, + gtk::gio::FileCreateFlags::NONE, + Some(&cancellable), + ) { + Ok(file_output_stream) => { + use crate::tool::Format; + // Asynchronously read [IOStream](https://docs.gtk.org/gio/class.IOStream.html) + // to local [MemoryInputStream](https://docs.gtk.org/gio/class.MemoryInputStream.html) + // show bytes count in loading widget, validate max size for incoming data + // * no dependency of Gemini library here, feel free to use any other `IOStream` processor + file_output_stream::from_stream_async( + stream.clone(), + file_output_stream, + cancellable.clone(), + Priority::DEFAULT, + ( + 0x100000, // 1M bytes per chunk + None, // unlimited + 0, // initial totals + ), + ( + // on chunk + { + let action = action.clone(); + move |_, total| action.update.activate(&format!( + "Received {}...", + total.bytes() + )) + }, + // on complete + { + let action = action.clone(); + move |result| match result { + Ok((_, total)) => { + action.complete.activate(&format!( + "Saved to {} ({} total)", + file.parse_name(), + total.bytes() + )) } - }, - ), - ) - } - Err(e) => action.cancel.activate(&e.to_string()), + Err(e) => action.cancel.activate(&e.to_string()) + } + }, + ), + ) } + Err(e) => action.cancel.activate(&e.to_string()), } }, ); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset }, _ => match success.mime() { @@ -270,6 +271,7 @@ fn handle( .find .simple_action .set_enabled(true); + page.snap_history(); redirects.replace(0); // reset }, Err(e) => { @@ -277,6 +279,7 @@ fn handle( status.set_description(Some(&e.to_string())); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset }, }, @@ -285,6 +288,7 @@ fn handle( status.set_description(Some(&e.to_string())); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset } } @@ -294,6 +298,7 @@ fn handle( status.set_description(Some(&e.to_string())); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset }, } @@ -320,7 +325,6 @@ fn handle( ( move |_, total| status.set_description(Some(&format!("Download: {total} bytes"))), { - //let page = page.clone(); move | result | match result { Ok((memory_input_stream, _)) => { Pixbuf::from_stream_async( @@ -339,6 +343,7 @@ fn handle( } } page.set_progress(0.0); + page.snap_history(); redirects.replace(0); // reset }, ) @@ -348,6 +353,7 @@ fn handle( status.set_description(Some(&e.to_string())); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset } } @@ -362,6 +368,7 @@ 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(); redirects.replace(0); // reset }, } @@ -397,7 +404,7 @@ fn handle( page.navigation.set_request(&target.to_string()); } redirects.replace(total); - page.item_action.load.activate(Some(&target.to_string()), false); + page.item_action.load.activate(Some(&target.to_string())); } } Err(e) => { @@ -419,6 +426,7 @@ 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(); redirects.replace(0); // reset } } @@ -433,6 +441,7 @@ 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(); redirects.replace(0); // reset if let Some(callback) = on_failure { callback() @@ -449,6 +458,7 @@ 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(); redirects.replace(0); // reset if let Some(callback) = on_failure { callback() @@ -462,6 +472,7 @@ fn handle( status.set_description(Some(&e.to_string())); page.set_progress(0.0); page.set_title(&status.title()); + page.snap_history(); redirects.replace(0); // reset } } diff --git a/src/app/browser/window/tab/item/page.rs b/src/app/browser/window/tab/item/page.rs index d4c2db97..bf4dc36d 100644 --- a/src/app/browser/window/tab/item/page.rs +++ b/src/app/browser/window/tab/item/page.rs @@ -93,6 +93,16 @@ impl Page { self.search.show() } + /// Make new history record in related components + pub fn snap_history(&self) { + self.item_action + .history + .add(self.navigation.request(), true); + self.profile + .history + .open(self.navigation.request(), Some(self.title())) + } + /// Cleanup session for `Self` pub fn clean( &self, diff --git a/src/app/browser/window/tab/item/page/content/status/mime.rs b/src/app/browser/window/tab/item/page/content/status/mime.rs index dd127854..fffcfda9 100644 --- a/src/app/browser/window/tab/item/page/content/status/mime.rs +++ b/src/app/browser/window/tab/item/page/content/status/mime.rs @@ -24,9 +24,7 @@ pub fn build(mime: &str, download: Option<(&Rc, &Uri)>) -> StatusPag let action = action.clone(); let request = request.clone(); move |_| { - action - .load - .activate(Some(&format!("download:{}", request)), true); + action.load.activate(Some(&format!("download:{}", request))); } }); diff --git a/src/app/browser/window/tab/item/page/content/text/gemini.rs b/src/app/browser/window/tab/item/page/content/text/gemini.rs index 852182d8..a04be284 100644 --- a/src/app/browser/window/tab/item/page/content/text/gemini.rs +++ b/src/app/browser/window/tab/item/page/content/text/gemini.rs @@ -388,8 +388,7 @@ impl Gemini { // Select link handler by scheme return match uri.scheme().as_str() { "gemini" | "titan" => { - // Open new page in browser - item_action.load.activate(Some(&uri.to_str()), true); + item_action.load.activate(Some(&uri.to_str())) } // Scheme not supported, delegate _ => UriLauncher::new(&uri.to_str()).launch( diff --git a/src/app/browser/window/tab/item/page/input/response.rs b/src/app/browser/window/tab/item/page/input/response.rs index f6a4dedd..b8338e32 100644 --- a/src/app/browser/window/tab/item/page/input/response.rs +++ b/src/app/browser/window/tab/item/page/input/response.rs @@ -81,14 +81,11 @@ 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), - )), - false, // prevent re-send on history navigation - ); + item_action.load.activate(Some(&format!( + "{}?{}", + base.to_string_partial(UriHideFlags::QUERY), + Uri::escape_string(&form.text(), None, false), + ))) } }); diff --git a/src/app/browser/window/tab/item/page/input/sensitive.rs b/src/app/browser/window/tab/item/page/input/sensitive.rs index 419f6590..d5ea9e9a 100644 --- a/src/app/browser/window/tab/item/page/input/sensitive.rs +++ b/src/app/browser/window/tab/item/page/input/sensitive.rs @@ -59,14 +59,11 @@ 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), - )), - false, // prevent re-send on history navigation - ); + item_action.load.activate(Some(&format!( + "{}?{}", + base.to_string_partial(UriHideFlags::QUERY), + Uri::escape_string(&form.password_entry_row.text(), None, false), + ))) } });