implement request as trait

This commit is contained in:
yggverse 2025-01-27 16:30:27 +02:00
parent 6db928afee
commit 3d1a07213c
11 changed files with 141 additions and 95 deletions

View file

@ -210,7 +210,7 @@ impl Menu for MenuButton {
// Recently closed history // Recently closed history
main_history_tab.remove_all(); main_history_tab.remove_all();
for item in profile.history.memory.tab.recent() { for item in profile.history.memory.tab.recent() {
let item_request = item.page.navigation.request.entry.text(); // @TODO restore entire `Item` let item_request = item.page.navigation.request.text(); // @TODO restore entire `Item`
let menu_item = gio::MenuItem::new(Some(&ellipsize(&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!( menu_item.set_action_and_target_value(Some(&format!(
"{}.{}", "{}.{}",

View file

@ -12,7 +12,7 @@ use error::Error;
use gtk::{ use gtk::{
gio::Icon, gio::Icon,
glib::{DateTime, Propagation}, glib::{DateTime, Propagation},
prelude::{ActionExt, EditableExt, WidgetExt}, prelude::{ActionExt, EditableExt},
}; };
pub use item::Item; pub use item::Item;
use menu::Menu; use menu::Menu;
@ -136,7 +136,7 @@ impl Tab {
// Expect user input on tab appended has empty request entry // Expect user input on tab appended has empty request entry
// * this action initiated here because should be applied on tab appending event only // * 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()) { if request.is_none() || request.is_some_and(|value| value.is_empty()) {
item.page.navigation.request.entry.grab_focus(); item.page.navigation.grab_focus();
} }
// Register dynamically created tab components in the HashMap index // Register dynamically created tab components in the HashMap index
@ -196,7 +196,7 @@ impl Tab {
// Save page at given `position`, `None` to save selected page (if available) // Save page at given `position`, `None` to save selected page (if available)
pub fn save_as(&self, tab_page_position: Option<i32>) { pub fn save_as(&self, tab_page_position: Option<i32>) {
if let Some(item) = self.item(tab_page_position) { if let Some(item) = self.item(tab_page_position) {
item.page.navigation.request.to_download(); item.page.navigation.to_download();
self.window_action.reload.activate(); self.window_action.reload.activate();
} }
} }
@ -204,7 +204,7 @@ impl Tab {
// View source for page at given `position`, `None` to use selected page (if available) // View source for page at given `position`, `None` to use selected page (if available)
pub fn source(&self, tab_page_position: Option<i32>) { pub fn source(&self, tab_page_position: Option<i32>) {
if let Some(item) = self.item(tab_page_position) { if let Some(item) = self.item(tab_page_position) {
item.page.navigation.request.to_source(); item.page.navigation.to_source();
self.window_action.reload.activate(); self.window_action.reload.activate();
} }
} }
@ -233,9 +233,9 @@ impl Tab {
pub fn page_home(&self, tab_page_position: Option<i32>) { pub fn page_home(&self, tab_page_position: Option<i32>) {
if let Some(item) = self.item(tab_page_position) { if let Some(item) = self.item(tab_page_position) {
if let Some(home) = item.page.navigation.request.home() { if let Some(home) = item.page.navigation.home() {
let home = home.to_string(); let home = home.to_string();
item.page.navigation.request.entry.set_text(&home); item.page.navigation.request.set_text(&home);
item.client.handle(&home, true); item.client.handle(&home, true);
} }
} }
@ -256,8 +256,7 @@ 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 page_reload(&self, tab_page_position: Option<i32>) { pub fn page_reload(&self, tab_page_position: Option<i32>) {
if let Some(item) = self.item(tab_page_position) { if let Some(item) = self.item(tab_page_position) {
item.client item.client.handle(&item.page.navigation.request(), true);
.handle(&item.page.navigation.request.entry.text(), true);
} }
} }

View file

@ -82,9 +82,9 @@ impl Item {
let page = page.clone(); let page = page.clone();
move |this, _| { move |this, _| {
this.set_enabled(false); this.set_enabled(false);
if let Some(uri) = page.navigation.request.home() { if let Some(uri) = page.navigation.home() {
let request = uri.to_string(); let request = uri.to_string();
page.navigation.request.entry.set_text(&request); page.navigation.request.set_text(&request);
client.handle(&request, true); client.handle(&request, true);
} }
} }
@ -96,7 +96,7 @@ impl Item {
let profile = profile.clone(); let profile = profile.clone();
let window_action = window_action.clone(); let window_action = window_action.clone();
move || { move || {
if let Some(uri) = page.navigation.request.uri() { if let Some(uri) = page.navigation.uri() {
let scheme = uri.scheme(); let scheme = uri.scheme();
if scheme == "gemini" || scheme == "titan" { if scheme == "gemini" || scheme == "titan" {
return identity::default(&window_action, &profile, &uri) return identity::default(&window_action, &profile, &uri)
@ -112,7 +112,7 @@ impl Item {
let client = client.clone(); let client = client.clone();
move |request, is_history| { move |request, is_history| {
if let Some(text) = request { if let Some(text) = request {
page.navigation.request.entry.set_text(&text); page.navigation.request.set_text(&text);
client.handle(&text, is_history); client.handle(&text, is_history);
} }
} }
@ -122,13 +122,13 @@ impl Item {
let page = page.clone(); let page = page.clone();
let client = client.clone(); let client = client.clone();
move |_, _| { move |_, _| {
client.handle(&page.navigation.request.entry.text(), false); client.handle(&page.navigation.request.text(), false);
} }
}); });
// Handle immediately on request // Handle immediately on request
if let Some(text) = request { if let Some(text) = request {
page.navigation.request.entry.set_text(text); page.navigation.request.set_text(text);
if is_load { if is_load {
client.handle(text, true); client.handle(text, true);
} }

View file

@ -9,7 +9,7 @@ use feature::Feature;
use gtk::{ use gtk::{
gio::Cancellable, gio::Cancellable,
glib::{Uri, UriFlags}, glib::{Uri, UriFlags},
prelude::{ActionExt, CancellableExt, EditableExt, EntryExt}, prelude::{ActionExt, CancellableExt, EntryExt},
}; };
use std::{cell::Cell, rc::Rc}; use std::{cell::Cell, rc::Rc};
use subject::Subject; use subject::Subject;
@ -62,7 +62,6 @@ impl Client {
.page .page
.navigation .navigation
.request .request
.entry
.set_progress_fraction(0.1); .set_progress_fraction(0.1);
self.subject.tab_page.set_loading(true); self.subject.tab_page.set_loading(true);
@ -87,12 +86,7 @@ impl Client {
"Scheme `{scheme}` yet not supported" "Scheme `{scheme}` yet not supported"
))); )));
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
subject subject.page.navigation.request.set_progress_fraction(0.0);
.page
.navigation
.request
.entry
.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
} }
}, },
@ -201,7 +195,7 @@ fn search(query: &str) -> Uri {
/// Make new history record in related components /// Make new history record in related components
/// * optional [Uri](https://docs.gtk.org/glib/struct.Uri.html) reference wanted only for performance reasons, to not parse it twice /// * optional [Uri](https://docs.gtk.org/glib/struct.Uri.html) reference wanted only for performance reasons, to not parse it twice
fn snap_history(subject: &Rc<Subject>, uri: Option<&Uri>) { fn snap_history(subject: &Rc<Subject>, uri: Option<&Uri>) {
let request = subject.page.navigation.request.entry.text(); let request = subject.page.navigation.request();
// Add new record into the global memory index (used in global menu) // Add new record into the global memory index (used in global menu)
// * if the `Uri` is `None`, try parse it from `request` // * if the `Uri` is `None`, try parse it from `request`
@ -210,7 +204,7 @@ fn snap_history(subject: &Rc<Subject>, uri: Option<&Uri>) {
None => { None => {
// this case especially useful for some routes that contain redirects // this case especially useful for some routes that contain redirects
// maybe some parental optimization wanted @TODO // maybe some parental optimization wanted @TODO
if let Some(uri) = subject.page.navigation.request.uri() { if let Some(uri) = subject.page.navigation.uri() {
subject.page.profile.history.memory.request.set(uri); subject.page.profile.history.memory.request.set(uri);
} }
} }

View file

@ -60,7 +60,6 @@ impl Gemini {
.page .page
.navigation .navigation
.request .request
.entry
.set_progress_fraction(progress_fraction); .set_progress_fraction(progress_fraction);
} }
}); });
@ -134,7 +133,6 @@ impl Gemini {
.page .page
.navigation .navigation
.request .request
.entry
.set_progress_fraction(0.0); .set_progress_fraction(0.0);
self.subject.tab_page.set_loading(false); self.subject.tab_page.set_loading(false);
} }
@ -203,7 +201,7 @@ fn handle(
Some(1024), Some(1024),
); );
} }
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&title); subject.tab_page.set_title(&title);
redirects.replace(0); // reset redirects.replace(0); // reset
@ -275,7 +273,7 @@ fn handle(
} }
}, },
); );
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -298,7 +296,7 @@ fn handle(
Some(title) => title.into(), // @TODO Some(title) => title.into(), // @TODO
None => uri_to_title(&uri), None => uri_to_title(&uri),
}); });
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.page.window_action subject.page.window_action
.find .find
@ -309,7 +307,7 @@ fn handle(
Err(e) => { Err(e) => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -353,7 +351,7 @@ fn handle(
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
} }
} }
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
redirects.replace(0); // reset redirects.replace(0); // reset
}, },
@ -362,7 +360,7 @@ fn handle(
Err(e) => { Err(e) => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -376,7 +374,7 @@ fn handle(
.content .content
.to_status_mime(mime, Some((&subject.page.item_action, &uri))); .to_status_mime(mime, Some((&subject.page.item_action, &uri)));
status.set_description(Some(&format!("Content type `{mime}` yet not supported"))); status.set_description(Some(&format!("Content type `{mime}` yet not supported")));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -385,7 +383,7 @@ fn handle(
None => { None => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some("MIME type not found")); status.set_description(Some("MIME type not found"));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -423,7 +421,7 @@ fn handle(
if total > 5 { if total > 5 {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some("Redirection limit reached")); status.set_description(Some("Redirection limit reached"));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -434,7 +432,7 @@ fn handle(
|| uri.host() != target.host() { || uri.host() != target.host() {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some("External redirects not allowed by protocol specification")); status.set_description(Some("External redirects not allowed by protocol specification"));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -443,7 +441,6 @@ fn handle(
if matches!(response.meta.status, Status::PermanentRedirect) { if matches!(response.meta.status, Status::PermanentRedirect) {
subject.page.navigation subject.page.navigation
.request .request
.entry
.set_text(&uri.to_string()); .set_text(&uri.to_string());
} }
redirects.replace(total); redirects.replace(total);
@ -453,7 +450,7 @@ fn handle(
Err(e) => { Err(e) => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -462,7 +459,7 @@ fn handle(
None => { None => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some("Redirection target not found")); status.set_description(Some("Redirection target not found"));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -481,7 +478,7 @@ fn handle(
None => response.meta.status.to_string(), None => response.meta.status.to_string(),
})); }));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -489,7 +486,7 @@ fn handle(
error => { error => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some(&error.to_string())); status.set_description(Some(&error.to_string()));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset
@ -499,7 +496,7 @@ fn handle(
Err(e) => { Err(e) => {
let status = subject.page.content.to_status_failure(); let status = subject.page.content.to_status_failure();
status.set_description(Some(&e.to_string())); status.set_description(Some(&e.to_string()));
subject.page.navigation.request.entry.set_progress_fraction(0.0); subject.page.navigation.request.set_progress_fraction(0.0);
subject.tab_page.set_loading(false); subject.tab_page.set_loading(false);
subject.tab_page.set_title(&status.title()); subject.tab_page.set_title(&status.title());
redirects.replace(0); // reset redirects.replace(0); // reset

View file

@ -6,18 +6,15 @@ mod navigation;
mod search; mod search;
mod widget; mod widget;
use super::{Action as ItemAction, BrowserAction, Profile, TabAction, WindowAction};
use content::Content; use content::Content;
use error::Error; use error::Error;
use input::Input; use input::Input;
use navigation::Navigation; use navigation::Navigation;
use search::Search; use search::Search;
use widget::Widget;
use super::{Action as ItemAction, BrowserAction, Profile, TabAction, WindowAction};
use gtk::prelude::EditableExt;
use sqlite::Transaction; use sqlite::Transaction;
use std::rc::Rc; use std::rc::Rc;
use widget::Widget;
pub struct Page { pub struct Page {
pub profile: Rc<Profile>, pub profile: Rc<Profile>,
@ -88,7 +85,7 @@ impl Page {
let result = match self let result = match self
.profile .profile
.bookmark .bookmark
.toggle(self.navigation.request.entry.text().as_str()) .toggle(self.navigation.request().as_str())
{ {
Ok(result) => Ok(result), Ok(result) => Ok(result),
Err(_) => Err(Error::Bookmark), // @TODO Err(_) => Err(Error::Bookmark), // @TODO
@ -144,7 +141,7 @@ impl Page {
self.navigation.restore(transaction, &record.id)?; self.navigation.restore(transaction, &record.id)?;
// Make initial page history snap using `navigation` values restored // Make initial page history snap using `navigation` values restored
// * just to have back/forward navigation ability // * just to have back/forward navigation ability
if let Some(uri) = self.navigation.request.uri() { if let Some(uri) = self.navigation.uri() {
self.profile.history.memory.request.set(uri); self.profile.history.memory.request.set(uri);
} }
} }

View file

@ -7,7 +7,11 @@ mod request;
use super::{ItemAction, Profile, TabAction, WindowAction}; use super::{ItemAction, Profile, TabAction, WindowAction};
use bookmark::Bookmark; use bookmark::Bookmark;
use gtk::{prelude::BoxExt, Box, Button, Orientation}; use gtk::{
glib::{GString, Uri},
prelude::{BoxExt, EditableExt, WidgetExt},
Box, Button, Entry, Orientation,
};
use history::History; use history::History;
use home::Home; use home::Home;
use reload::Reload; use reload::Reload;
@ -22,7 +26,7 @@ pub struct Navigation {
pub home: Button, pub home: Button,
pub reload: Button, pub reload: Button,
pub bookmark: Button, pub bookmark: Button,
pub request: Rc<Request>, pub request: Entry,
pub g_box: Box, pub g_box: Box,
} }
@ -35,14 +39,14 @@ impl Navigation {
&Rc<ItemAction>, &Rc<ItemAction>,
), ),
) -> Self { ) -> Self {
// init children components // Init children components
let history = Box::history((window_action, tab_action, item_action)); let history = Box::history((window_action, tab_action, item_action));
let request = Rc::new(Request::build(item_action, profile)); let request = Entry::request(item_action, profile);
let reload = Button::reload((window_action, tab_action, item_action), &request); let reload = Button::reload((window_action, tab_action, item_action), &request);
let home = Button::home((window_action, tab_action, item_action), &request); let home = Button::home((window_action, tab_action, item_action), &request);
let bookmark = Button::bookmark(window_action, profile, &request); let bookmark = Button::bookmark(window_action, profile, &request);
// Init main widget
let g_box = Box::builder() let g_box = Box::builder()
.orientation(Orientation::Horizontal) .orientation(Orientation::Horizontal)
.spacing(SPACING) .spacing(SPACING)
@ -54,7 +58,7 @@ impl Navigation {
g_box.append(&home); g_box.append(&home);
g_box.append(&history); g_box.append(&history);
g_box.append(&reload); g_box.append(&reload);
g_box.append(&request.entry); // @TODO g_box.append(&request);
g_box.append(&bookmark); g_box.append(&bookmark);
Self { Self {
@ -126,6 +130,32 @@ impl Navigation {
Ok(()) Ok(())
} }
pub fn grab_focus(&self) -> bool {
self.request.grab_focus()
}
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.text()
}
pub fn uri(&self) -> Option<Uri> {
self.request.uri()
}
pub fn home(&self) -> Option<Uri> {
self.request.home()
}
} }
// Tools // Tools

View file

@ -1,7 +1,7 @@
use super::{Profile, Request, WindowAction}; use super::{Profile, WindowAction};
use gtk::{ use gtk::{
prelude::{ActionExt, ButtonExt, EditableExt}, prelude::{ActionExt, ButtonExt, EditableExt},
Button, Button, Entry,
}; };
use std::rc::Rc; use std::rc::Rc;
@ -9,12 +9,12 @@ const ICON_YES: &str = "starred-symbolic";
const ICON_NON: &str = "non-starred-symbolic"; const ICON_NON: &str = "non-starred-symbolic";
pub trait Bookmark { pub trait Bookmark {
fn bookmark(action: &Rc<WindowAction>, profile: &Rc<Profile>, request: &Rc<Request>) -> Self; fn bookmark(action: &Rc<WindowAction>, profile: &Rc<Profile>, request: &Entry) -> Self;
} }
impl Bookmark for Button { impl Bookmark for Button {
fn bookmark(action: &Rc<WindowAction>, profile: &Rc<Profile>, request: &Rc<Request>) -> Self { fn bookmark(action: &Rc<WindowAction>, profile: &Rc<Profile>, request: &Entry) -> Self {
let has_bookmark = profile.bookmark.get(&request.entry.text()).is_ok(); let has_bookmark = profile.bookmark.get(&request.text()).is_ok();
let button = Button::builder() let button = Button::builder()
.action_name(format!( .action_name(format!(
@ -31,9 +31,7 @@ impl Bookmark for Button {
let profile = profile.clone(); let profile = profile.clone();
let request = request.clone(); let request = request.clone();
move |_, _| { move |_, _| {
button.set_icon_name(icon_name( button.set_icon_name(icon_name(profile.bookmark.get(&request.text()).is_ok()))
profile.bookmark.get(&request.entry.text()).is_ok(),
))
} }
}); // @TODO use local action }); // @TODO use local action

View file

@ -3,15 +3,12 @@ use crate::app::browser::window::action::Position;
use gtk::{ use gtk::{
gdk::BUTTON_MIDDLE, gdk::BUTTON_MIDDLE,
prelude::{ActionExt, WidgetExt}, prelude::{ActionExt, WidgetExt},
Button, GestureClick, Button, Entry, GestureClick,
}; };
use std::rc::Rc; use std::rc::Rc;
pub trait Home { pub trait Home {
fn home( fn home(action: (&Rc<WindowAction>, &Rc<TabAction>, &Rc<ItemAction>), request: &Entry) -> Self;
action: (&Rc<WindowAction>, &Rc<TabAction>, &Rc<ItemAction>),
request: &Rc<Request>,
) -> Self;
} }
impl Home for Button { impl Home for Button {
@ -21,7 +18,7 @@ impl Home for Button {
&Rc<TabAction>, &Rc<TabAction>,
&Rc<ItemAction>, &Rc<ItemAction>,
), ),
request: &Rc<Request>, request: &Entry,
) -> Self { ) -> Self {
let button = Button::builder() let button = Button::builder()
.action_name(format!("{}.{}", tab_action.id, item_action.home.name())) .action_name(format!("{}.{}", tab_action.id, item_action.home.name()))

View file

@ -3,14 +3,14 @@ use crate::app::browser::window::action::Position;
use gtk::{ use gtk::{
gdk::BUTTON_MIDDLE, gdk::BUTTON_MIDDLE,
prelude::{ActionExt, WidgetExt}, prelude::{ActionExt, WidgetExt},
Button, GestureClick, Button, Entry, GestureClick,
}; };
use std::rc::Rc; use std::rc::Rc;
pub trait Reload { pub trait Reload {
fn reload( fn reload(
action: (&Rc<WindowAction>, &Rc<TabAction>, &Rc<ItemAction>), action: (&Rc<WindowAction>, &Rc<TabAction>, &Rc<ItemAction>),
request: &Rc<Request>, request: &Entry,
) -> Self; ) -> Self;
} }
@ -21,7 +21,7 @@ impl Reload for Button {
&Rc<TabAction>, &Rc<TabAction>,
&Rc<ItemAction>, &Rc<ItemAction>,
), ),
request: &Rc<Request>, request: &Entry,
) -> Self { ) -> Self {
let button = Button::builder() let button = Button::builder()
.action_name(format!("{}.{}", tab_action.id, item_action.reload.name())) .action_name(format!("{}.{}", tab_action.id, item_action.reload.name()))

View file

@ -14,15 +14,50 @@ use std::{cell::Cell, rc::Rc};
const PLACEHOLDER_TEXT: &str = "URL or search term..."; const PLACEHOLDER_TEXT: &str = "URL or search term...";
pub struct Request { pub trait Request {
pub entry: Entry, // Constructors
fn request(item_action: &Rc<ItemAction>, profile: &Rc<Profile>) -> Self;
// Actions
fn clean(
&self,
transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64,
) -> Result<(), String>;
fn restore(
&self,
transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64,
) -> Result<(), String>;
fn save(
&self,
transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64,
) -> Result<(), String>;
// Setters
fn to_download(&self);
fn to_source(&self);
// Getters
fn strip_prefix(&self) -> GString;
fn download(&self) -> GString;
fn source(&self) -> GString;
fn uri(&self) -> Option<Uri>;
fn home(&self) -> Option<Uri>;
} }
impl Request { impl Request for Entry {
// Constructors // Constructors
/// Build new `Self` /// Build new `Self`
pub fn build(item_action: &Rc<ItemAction>, profile: &Rc<Profile>) -> Self { fn request(item_action: &Rc<ItemAction>, profile: &Rc<Profile>) -> Self {
// Init main widget // Init main widget
let entry = Entry::builder() let entry = Entry::builder()
.placeholder_text(PLACEHOLDER_TEXT) .placeholder_text(PLACEHOLDER_TEXT)
@ -122,12 +157,11 @@ impl Request {
} }
}); });
// Return activated `Self` entry
Self { entry }
} }
// Actions // Actions
pub fn clean( fn clean(
&self, &self,
transaction: &Transaction, transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64, app_browser_window_tab_item_page_navigation_id: &i64,
@ -150,7 +184,7 @@ impl Request {
Ok(()) Ok(())
} }
pub fn restore( fn restore(
&self, &self,
transaction: &Transaction, transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64, app_browser_window_tab_item_page_navigation_id: &i64,
@ -159,7 +193,7 @@ impl Request {
Ok(records) => { Ok(records) => {
for record in records { for record in records {
if let Some(text) = record.text { if let Some(text) = record.text {
self.entry.set_text(&text); self.set_text(&text);
} }
// Delegate restore action to the item childs // Delegate restore action to the item childs
@ -172,13 +206,13 @@ impl Request {
Ok(()) Ok(())
} }
pub fn save( fn save(
&self, &self,
transaction: &Transaction, transaction: &Transaction,
app_browser_window_tab_item_page_navigation_id: &i64, app_browser_window_tab_item_page_navigation_id: &i64,
) -> Result<(), String> { ) -> Result<(), String> {
// Keep value in memory until operation complete // Keep value in memory until operation complete
let text = self.entry.text(); let text = self.text();
match database::insert( match database::insert(
transaction, transaction,
@ -202,40 +236,40 @@ impl Request {
// Setters // Setters
pub fn to_download(&self) { fn to_download(&self) {
self.entry.set_text(&self.download()); self.set_text(&self.download());
} }
pub fn to_source(&self) { fn to_source(&self) {
self.entry.set_text(&self.source()); self.set_text(&self.source());
} }
// Getters // Getters
/// Get current request value without system prefix /// Get current request value without system prefix
/// * the `prefix` is not `scheme` /// * the `prefix` is not `scheme`
pub fn strip_prefix(&self) -> GString { fn strip_prefix(&self) -> GString {
strip_prefix(self.entry.text()) strip_prefix(self.text())
} }
/// Get request value in `download:` format /// Get request value in `download:` format
pub fn download(&self) -> GString { fn download(&self) -> GString {
gformat!("download:{}", self.strip_prefix()) gformat!("download:{}", self.strip_prefix())
} }
/// Get request value in `source:` format /// Get request value in `source:` format
pub fn source(&self) -> GString { fn source(&self) -> GString {
gformat!("source:{}", self.strip_prefix()) gformat!("source:{}", self.strip_prefix())
} }
/// Try get current request value as [Uri](https://docs.gtk.org/glib/struct.Uri.html) /// Try get current request value as [Uri](https://docs.gtk.org/glib/struct.Uri.html)
/// * `strip_prefix` on parse /// * `strip_prefix` on parse
pub fn uri(&self) -> Option<Uri> { fn uri(&self) -> Option<Uri> {
uri(&strip_prefix(self.entry.text())) uri(&strip_prefix(self.text()))
} }
/// Try build home [Uri](https://docs.gtk.org/glib/struct.Uri.html) for `Self` /// Try build home [Uri](https://docs.gtk.org/glib/struct.Uri.html) for `Self`
pub fn home(&self) -> Option<Uri> { fn home(&self) -> Option<Uri> {
home(self.uri()) home(self.uri())
} }
} }