diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index 453427bb..ac92d450 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -76,8 +76,8 @@ impl Tab { if let Some(item) = index.borrow_mut().remove(tab_page) { // keep removed `Item` reference in the memory (to reopen from the main menu) // * skip item with blank request - if !item.page.navigation.request().is_empty() { - profile.history.close(&item.page.navigation.request()); + if !item.page.navigation.request.is_empty() { + profile.history.close(&item.page.navigation.request.text()); } } // reassign global actions to active tab @@ -160,7 +160,7 @@ impl Tab { // Expect user input on tab appended has empty request entry // * this action initiated here because should be applied on tab appending event only if request.is_none() || request.is_some_and(|value| value.is_empty()) { - item.page.navigation.grab_focus(); + item.page.navigation.request.grab_focus(); } // Relate with GTK `TabPage` with app `Item` @@ -221,7 +221,7 @@ impl Tab { // Save page at given `position`, `None` to save selected page (if available) pub fn save_as(&self, page_position: Option) { if let Some(item) = self.item(page_position) { - item.page.navigation.to_download(); + item.page.navigation.request.to_download(); self.window_action.reload.activate(); } } @@ -229,7 +229,7 @@ impl Tab { // View source for page at given `position`, `None` to use selected page (if available) pub fn source(&self, page_position: Option) { if let Some(item) = self.item(page_position) { - item.page.navigation.to_source(); + item.page.navigation.request.to_source(); self.window_action.reload.activate(); } } @@ -273,7 +273,7 @@ impl Tab { pub fn reload(&self, page_position: Option) { if let Some(item) = self.item(page_position) { item.client - .handle(&item.page.navigation.request(), true, false); + .handle(&item.page.navigation.request.text(), true, false); } } @@ -414,7 +414,7 @@ fn update_actions( window_action .save_as .simple_action - .set_enabled(!item.page.navigation.is_file()); + .set_enabled(!item.page.navigation.request.is_file()); window_action.change_state(Some(tab_view.page_position(tab_page))); return; diff --git a/src/app/browser/window/tab/item.rs b/src/app/browser/window/tab/item.rs index 2d8daff7..ebf43651 100644 --- a/src/app/browser/window/tab/item.rs +++ b/src/app/browser/window/tab/item.rs @@ -83,9 +83,9 @@ impl Item { let page = page.clone(); move |this, _| { this.set_enabled(false); - if let Some(uri) = page.navigation.home() { + if let Some(uri) = page.navigation.request.home() { let request = uri.to_string(); - page.navigation.set_request(&request); + page.navigation.request.set_text(&request); client.handle(&request, true, false); } } @@ -96,7 +96,7 @@ impl Item { let client = client.clone(); move |request, is_snap_history, is_redirect| { if let Some(request) = request { - page.navigation.set_request(&request); + page.navigation.request.set_text(&request); client.handle(&request, is_snap_history, is_redirect); } } @@ -110,7 +110,7 @@ impl Item { action.reload.connect_activate({ let page = page.clone(); let client = client.clone(); - move |_, _| client.handle(&page.navigation.request(), true, false) + move |_, _| client.handle(&page.navigation.request.text(), true, false) }); action.reload.connect_enabled_notify({ @@ -145,7 +145,7 @@ impl Item { // Handle immediately on request if let Some(request) = request { - page.navigation.set_request(request); + page.navigation.request.set_text(request); if is_load { client.handle(request, true, false) } 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 f421485b..3300ef4b 100644 --- a/src/app/browser/window/tab/item/client/driver/gemini.rs +++ b/src/app/browser/window/tab/item/client/driver/gemini.rs @@ -569,7 +569,7 @@ fn handle( } else { let t = target.to_string(); if matches!(redirect, Redirect::Permanent { .. }) { - page.navigation.set_request(&t); + page.navigation.request.set_text(&t); } redirects.replace(total); { diff --git a/src/app/browser/window/tab/item/client/driver/nex.rs b/src/app/browser/window/tab/item/client/driver/nex.rs index 6517fafa..2e130cdb 100644 --- a/src/app/browser/window/tab/item/client/driver/nex.rs +++ b/src/app/browser/window/tab/item/client/driver/nex.rs @@ -59,7 +59,7 @@ impl Nex { .request .info .replace(i.into_permanent_redirect()); - self.page.navigation.set_request(&r); + self.page.navigation.request.set_text(&r); self.page.item_action.load.activate(Some(&r), false, true); return; // prevents operation cancelled message on redirect } diff --git a/src/app/browser/window/tab/item/page.rs b/src/app/browser/window/tab/item/page.rs index 35b0aafc..cd923040 100644 --- a/src/app/browser/window/tab/item/page.rs +++ b/src/app/browser/window/tab/item/page.rs @@ -98,10 +98,10 @@ impl Page { pub fn snap_history(&self) { self.item_action .history - .add(self.navigation.request(), true); + .add(self.navigation.request.text(), true); self.profile .history - .open(self.navigation.request(), Some(self.title())) + .open(self.navigation.request.text(), Some(self.title())) } /// Cleanup session for `Self` @@ -136,7 +136,7 @@ impl Page { // Make initial page history snap self.profile .history - .open(self.navigation.request(), Some(self.title())); + .open(self.navigation.request.text(), Some(self.title())); } Ok(()) } @@ -176,7 +176,9 @@ impl Page { } pub fn set_progress(&self, progress_fraction: f64) { - self.navigation.set_progress_fraction(progress_fraction); + self.navigation + .request + .set_progress_fraction(progress_fraction); self.tab_page.set_loading(progress_fraction > 0.0) } diff --git a/src/app/browser/window/tab/item/page/navigation.rs b/src/app/browser/window/tab/item/page/navigation.rs index 1ff26907..2e06f519 100644 --- a/src/app/browser/window/tab/item/page/navigation.rs +++ b/src/app/browser/window/tab/item/page/navigation.rs @@ -8,11 +8,7 @@ mod request; use super::{ItemAction, Profile, TabAction, WindowAction}; use anyhow::Result; use bookmark::Bookmark; -use gtk::{ - Box, Button, Orientation, - glib::{GString, Uri}, - prelude::{BoxExt, EditableExt, EntryExt, WidgetExt}, -}; +use gtk::{Box, Button, Orientation, prelude::BoxExt}; use history::History; use home::Home; use reload::Reload; @@ -43,7 +39,7 @@ impl Navigation { let request = Rc::new(Request::build(item_action, profile)); let reload = Button::reload((window_action, tab_action, item_action), &request); let home = Button::home((window_action, tab_action, item_action), &request); - let bookmark = Rc::new(Bookmark::build(window_action, profile, &request.entry)); + let bookmark = Rc::new(Bookmark::build(window_action, profile, &request)); // Init main widget let g_box = Box::builder() @@ -57,7 +53,7 @@ impl Navigation { g_box.append(&home); g_box.append(&history); g_box.append(&reload); - g_box.append(&request.entry); + request.append_to(&g_box); // private member g_box.append(&bookmark.button); Self { @@ -114,45 +110,9 @@ impl Navigation { Ok(()) } - pub fn grab_focus(&self) -> bool { - self.request.entry.grab_focus() - } - pub fn show_identity_dialog(&self) { self.request.show_identity_dialog() } - - // Setters - - pub fn set_request(&self, value: &str) { - self.request.entry.set_text(value); - } - - pub fn set_progress_fraction(&self, value: f64) { - self.request.entry.set_progress_fraction(value); - } - - pub fn to_download(&self) { - self.request.to_download(); - } - - pub fn to_source(&self) { - self.request.to_source(); - } - - // Getters - - pub fn request(&self) -> GString { - self.request.entry.text() - } - - pub fn home(&self) -> Option { - self.request.home() - } - - pub fn is_file(&self) -> bool { - self.request.is_file() - } } // Tools diff --git a/src/app/browser/window/tab/item/page/navigation/bookmark.rs b/src/app/browser/window/tab/item/page/navigation/bookmark.rs index 04be9f7f..6e47ee91 100644 --- a/src/app/browser/window/tab/item/page/navigation/bookmark.rs +++ b/src/app/browser/window/tab/item/page/navigation/bookmark.rs @@ -1,7 +1,7 @@ -use super::{Profile, WindowAction}; +use super::{Profile, Request, WindowAction}; use gtk::{ - Button, Entry, - prelude::{ActionExt, ButtonExt, EditableExt, WidgetExt}, + Button, + prelude::{ActionExt, ButtonExt, WidgetExt}, }; use std::rc::Rc; @@ -10,12 +10,12 @@ const TOOLTIP_TEXT: (&str, &str) = ("Add Bookmark", "Remove Bookmark"); pub struct Bookmark { profile: Rc, - request: Entry, + request: Rc, pub button: Button, } impl Bookmark { - pub fn build(action: &Rc, profile: &Rc, request: &Entry) -> Self { + pub fn build(action: &Rc, profile: &Rc, request: &Rc) -> Self { let button = Button::builder() .action_name(format!( "{}.{}", @@ -23,11 +23,12 @@ impl Bookmark { action.bookmark.simple_action.name() )) .build(); - update(profile, &button, request.text()); - request.connect_changed({ - let profile = profile.clone(); - let button = button.clone(); - move |entry| update(&profile, &button, entry.text()) + update(profile, &button, &request.text()); + request.on_change({ + let b = button.clone(); + let p = profile.clone(); + let r = request.clone(); + move || update(&p, &b, &r.text()) }); Self { profile: profile.clone(), @@ -65,14 +66,10 @@ fn icon_name(has_bookmark: bool) -> &'static str { } } -fn update(profile: &Rc, button: &Button, request: gtk::glib::GString) { - let profile = profile.clone(); - let button = button.clone(); - gtk::glib::spawn_future_local(async move { - button.set_sensitive(false); // lock - let has_bookmark = profile.bookmark.is_match_request(&request); - button.set_icon_name(icon_name(has_bookmark)); - button.set_tooltip_text(Some(tooltip_text(has_bookmark))); - button.set_sensitive(true); - }); // may take a while +fn update(profile: &Profile, button: &Button, request: &str) { + button.set_sensitive(false); // lock + let has_bookmark = profile.bookmark.is_match_request(request); + button.set_icon_name(icon_name(has_bookmark)); + button.set_tooltip_text(Some(tooltip_text(has_bookmark))); + button.set_sensitive(true); } diff --git a/src/app/browser/window/tab/item/page/navigation/request.rs b/src/app/browser/window/tab/item/page/navigation/request.rs index a18de080..c6b34ce9 100644 --- a/src/app/browser/window/tab/item/page/navigation/request.rs +++ b/src/app/browser/window/tab/item/page/navigation/request.rs @@ -27,7 +27,8 @@ const PREFIX_DOWNLOAD: &str = "download:"; const PREFIX_SOURCE: &str = "source:"; pub struct Request { - pub entry: Entry, + /// * keep it private to properly update some local dependencies on change (e.g. proxy resolver) + entry: Entry, pub info: Rc>, profile: Rc, proxy_resolver: Rc>>, @@ -290,6 +291,27 @@ impl Request { self.entry.text().starts_with("file://") } + pub fn is_empty(&self) -> bool { + self.entry.text_length() > 0 + } + + pub fn grab_focus(&self) -> bool { + self.entry.grab_focus() + } + + pub fn set_progress_fraction(&self, value: f64) { + self.entry.set_progress_fraction(value); + } + + pub fn set_text(&self, value: &str) { + self.entry.set_text(value); + self.refresh() + } + + pub fn text(&self) -> GString { + self.entry.text() + } + /// Get [ProxyResolver](https://docs.gtk.org/gio/iface.ProxyResolver.html) /// which is constructed for every `Request` entry change /// * useful on build new [SocketClient](https://docs.gtk.org/gio/class.SocketClient.html) @@ -298,6 +320,15 @@ impl Request { self.proxy_resolver.borrow().clone() } + pub fn append_to(&self, parent: >k::Box) { + use gtk::prelude::BoxExt; + parent.append(&self.entry) + } + + pub fn on_change(&self, callback: impl Fn() + 'static) { + self.entry.connect_changed(move |_| callback()); + } + // Tools /// Get request value with formatted `download` prefix @@ -474,34 +505,30 @@ fn update_blocked( } /// Indicate proxy connections @TODO cancel previous operation on update +/// * note: it's important to use sync lookup method by the current impl fn refresh_proxy_resolver( entry: &Entry, - profile: &Rc, - resolver: &Rc>>, + profile: &Profile, + resolver: &RefCell>, ) { const NONE: &[&str] = &[]; let t = entry.text(); // allocate once match profile.proxy.matches(&t) { - Some(m) => m.clone().lookup_async(&t, Cancellable::NONE, { - let e = entry.clone(); - let p = profile.clone(); - let r = resolver.clone(); - move |l| { - let (css_classes, tooltip_text) = match l { - Ok(h) => (&["accent"], format!("Proxy over {}", h.join(","))), - Err(i) => (&["error"], i.to_string()), - }; - e.set_css_classes(if p.proxy.misc.is_highlight_request_entry() { - css_classes - } else { - NONE - }); - e.set_tooltip_text(Some(&tooltip_text)); - r.replace(Some(m)); - } - }), + Some(m) => { + let (css_classes, tooltip_text) = match m.lookup(&t, Cancellable::NONE) { + Ok(h) => (&["accent"], format!("Proxy over {}", h.join(","))), + Err(i) => (&["error"], i.to_string()), + }; + entry.set_css_classes(if profile.proxy.misc.is_highlight_request_entry() { + css_classes + } else { + NONE + }); + entry.set_tooltip_text(Some(&tooltip_text)); + resolver.replace(Some(m)); + } None => { entry.set_css_classes(NONE); entry.set_tooltip_text(None);