mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
implement Redirect struct as the redirection wrapper with additional API features
This commit is contained in:
parent
0a5e837140
commit
a832936054
5 changed files with 111 additions and 18 deletions
|
|
@ -566,7 +566,10 @@ fn handle(
|
||||||
.set_size(None)
|
.set_size(None)
|
||||||
.commit();
|
.commit();
|
||||||
|
|
||||||
page.navigation.request.info.replace(i.into_redirect());
|
page.navigation.request.info.replace(match redirect {
|
||||||
|
Redirect::Permanent { .. } => i.into_permanent_redirect(),
|
||||||
|
Redirect::Temporary { .. } => i.into_temporary_redirect(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
page.item_action.load.activate(Some(&t), false);
|
page.item_action.load.activate(Some(&t), false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
mod dialog;
|
mod dialog;
|
||||||
mod event;
|
mod event;
|
||||||
|
mod redirect;
|
||||||
mod socket;
|
mod socket;
|
||||||
|
|
||||||
use super::Profile;
|
use super::Profile;
|
||||||
use dialog::Dialog;
|
use dialog::Dialog;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use gtk::{gio::SocketAddress, prelude::IsA};
|
use gtk::{gio::SocketAddress, prelude::IsA};
|
||||||
|
use redirect::Redirect;
|
||||||
use socket::Socket;
|
use socket::Socket;
|
||||||
|
|
||||||
/// Common, shared `Page` information holder
|
/// Common, shared `Page` information holder
|
||||||
|
|
@ -24,7 +26,7 @@ pub struct Info {
|
||||||
mime: Option<String>,
|
mime: Option<String>,
|
||||||
/// Hold redirections chain with handled details
|
/// Hold redirections chain with handled details
|
||||||
/// * the `referrer` member name is reserved for other protocols
|
/// * the `referrer` member name is reserved for other protocols
|
||||||
redirect: Option<Box<Self>>,
|
redirect: Option<Box<Redirect>>,
|
||||||
/// Key to relate data collected with the specific request
|
/// Key to relate data collected with the specific request
|
||||||
request: Option<String>,
|
request: Option<String>,
|
||||||
/// Hold size info
|
/// Hold size info
|
||||||
|
|
@ -74,13 +76,20 @@ impl Info {
|
||||||
|
|
||||||
/// Take `Self`, convert it into the redirect member,
|
/// Take `Self`, convert it into the redirect member,
|
||||||
/// then, return new `Self` back
|
/// then, return new `Self` back
|
||||||
/// * tip: use on driver redirection events
|
pub fn into_redirect(self, method: redirect::Method) -> Self {
|
||||||
pub fn into_redirect(self) -> Self {
|
|
||||||
let mut this = Self::new();
|
let mut this = Self::new();
|
||||||
this.redirect = Some(Box::new(self));
|
this.redirect = Some(Box::new(Redirect { info: self, method }));
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_permanent_redirect(self) -> Self {
|
||||||
|
self.into_redirect(redirect::Method::Permanent)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_temporary_redirect(self) -> Self {
|
||||||
|
self.into_redirect(redirect::Method::Temporary)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_event(&mut self, name: String) -> &mut Self {
|
pub fn add_event(&mut self, name: String) -> &mut Self {
|
||||||
self.event.push(Event::now(name));
|
self.event.push(Event::now(name));
|
||||||
self
|
self
|
||||||
|
|
|
||||||
|
|
@ -185,36 +185,60 @@ impl Dialog for PreferencesDialog {
|
||||||
.icon_name("insert-link-symbolic")
|
.icon_name("insert-link-symbolic")
|
||||||
.build();
|
.build();
|
||||||
p.add(&{
|
p.add(&{
|
||||||
// Collect redirections into the buffer,
|
use gtk::Button;
|
||||||
// to reverse chain before add its members to widget
|
/// Common suffix widget pattern
|
||||||
// * capacity optimized for Gemini protocol (as default)
|
fn suffix(
|
||||||
let mut b = Vec::with_capacity(5);
|
icon_name: impl Into<GString>,
|
||||||
|
tooltip_text: impl Into<GString>,
|
||||||
|
) -> Button {
|
||||||
|
Button::builder()
|
||||||
|
.css_classes(["flat"])
|
||||||
|
.icon_name(icon_name)
|
||||||
|
.tooltip_text(tooltip_text)
|
||||||
|
.sensitive(false)
|
||||||
|
.valign(Align::Center)
|
||||||
|
.halign(Align::Center)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
/// Recursively collect redirection members into the given vector
|
/// Recursively collect redirection members into the given vector
|
||||||
fn chain<'a>(b: &mut Vec<&'a Info>, i: &'a Info) {
|
fn chain<'a>(b: &mut Vec<&'a Info>, i: &'a Info) {
|
||||||
b.push(i);
|
b.push(i);
|
||||||
if let Some(ref r) = i.redirect {
|
if let Some(ref r) = i.redirect {
|
||||||
chain(b, r)
|
chain(b, &r.info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Collect redirections into the buffer,
|
||||||
|
// to reverse chain before add its members to widget
|
||||||
|
// * capacity optimized for Gemini protocol (as default)
|
||||||
|
let mut b = Vec::with_capacity(5);
|
||||||
chain(&mut b, info);
|
chain(&mut b, info);
|
||||||
b.reverse();
|
b.reverse();
|
||||||
let l = b.len(); // calculate once
|
let l = b.len(); // calculate once
|
||||||
let t = b[0].event[0].time(); // first event time to count from
|
let t = b[0].event[0].time(); // first event time to count from
|
||||||
for (i, r) in b.iter().enumerate() {
|
for (i, r) in b.iter().enumerate() {
|
||||||
g.add(&{
|
g.add(&{
|
||||||
|
let is_external = r
|
||||||
|
.redirect
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|this| this.is_external(r).is_some_and(|v| v));
|
||||||
let a = ActionRow::builder()
|
let a = ActionRow::builder()
|
||||||
.css_classes(["property"])
|
.css_classes(["property"])
|
||||||
.subtitle_selectable(true)
|
.subtitle_selectable(true)
|
||||||
.title_selectable(true)
|
.title_selectable(true)
|
||||||
.title(r.request().unwrap())
|
.title(r.request().unwrap())
|
||||||
.build();
|
.build();
|
||||||
// show redirections counter
|
|
||||||
a.add_prefix(&{
|
a.add_prefix(&{
|
||||||
let c = i + 1;
|
let c = i + 1;
|
||||||
gtk::Button::builder()
|
Button::builder()
|
||||||
.css_classes([
|
.css_classes([
|
||||||
"circular",
|
"circular",
|
||||||
if c == l { "success" } else { "accent" },
|
if is_external {
|
||||||
|
"warning"
|
||||||
|
} else if c == l {
|
||||||
|
"success"
|
||||||
|
} else {
|
||||||
|
"accent"
|
||||||
|
},
|
||||||
])
|
])
|
||||||
.label(c.to_string())
|
.label(c.to_string())
|
||||||
.sensitive(false)
|
.sensitive(false)
|
||||||
|
|
@ -222,6 +246,15 @@ impl Dialog for PreferencesDialog {
|
||||||
.halign(Align::Center)
|
.halign(Align::Center)
|
||||||
.build()
|
.build()
|
||||||
});
|
});
|
||||||
|
if let Some(ref redirect) = r.redirect {
|
||||||
|
a.add_suffix(&suffix(
|
||||||
|
redirect.method.icon_name(),
|
||||||
|
redirect.method.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if is_external {
|
||||||
|
a.add_suffix(&suffix("application-exit-symbolic", "External")) // @TODO links contain ⇖ text label indication
|
||||||
|
}
|
||||||
// show total redirection time in ms
|
// show total redirection time in ms
|
||||||
a.set_subtitle(&if i == 0 {
|
a.set_subtitle(&if i == 0 {
|
||||||
t.format_iso8601().unwrap()
|
t.format_iso8601().unwrap()
|
||||||
|
|
@ -237,7 +270,7 @@ impl Dialog for PreferencesDialog {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
a
|
a
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
g
|
g
|
||||||
});
|
});
|
||||||
|
|
@ -266,10 +299,7 @@ impl Dialog for PreferencesDialog {
|
||||||
);
|
);
|
||||||
a.add_suffix(
|
a.add_suffix(
|
||||||
&Label::builder()
|
&Label::builder()
|
||||||
.css_classes([
|
.css_classes([if c == 0 { "success" } else { "warning" }])
|
||||||
"flat",
|
|
||||||
if c == 0 { "success" } else { "warning" },
|
|
||||||
])
|
|
||||||
.halign(Align::End)
|
.halign(Align::End)
|
||||||
.label(if c > 0 {
|
.label(if c > 0 {
|
||||||
format!("+{c} ms")
|
format!("+{c} ms")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
pub mod method;
|
||||||
|
pub use method::Method;
|
||||||
|
|
||||||
|
use super::Info;
|
||||||
|
|
||||||
|
/// Unified redirection info wrapper for the application page
|
||||||
|
pub struct Redirect {
|
||||||
|
pub info: Info,
|
||||||
|
pub method: Method,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Redirect {
|
||||||
|
// Getters
|
||||||
|
|
||||||
|
/// Check redirection has external target
|
||||||
|
/// * return `None` when at least one request value could not be parsed to
|
||||||
|
/// the valid [Uri](https://docs.gtk.org/glib/struct.Uri.html) host
|
||||||
|
pub fn is_external(&self, cmp: &Info) -> Option<bool> {
|
||||||
|
fn parse(info: &Info) -> Option<gtk::glib::GString> {
|
||||||
|
gtk::glib::Uri::parse(info.request.as_ref()?, gtk::glib::UriFlags::NONE)
|
||||||
|
.ok()?
|
||||||
|
.host()
|
||||||
|
}
|
||||||
|
Some(parse(&self.info)? != parse(cmp)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/// Common redirection type enumeration for different protocol drivers
|
||||||
|
pub enum Method {
|
||||||
|
Permanent,
|
||||||
|
Temporary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Method {
|
||||||
|
pub fn icon_name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Permanent => "network-transmit-symbolic",
|
||||||
|
Self::Temporary => "network-transmit-receive-symbolic",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Method {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Permanent => write!(f, "Permanent"),
|
||||||
|
Self::Temporary => {
|
||||||
|
write!(f, "Temporary")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue