add new tab item action group, delegate history handle to action implementation

This commit is contained in:
yggverse 2025-01-25 17:28:05 +02:00
parent 5145a53bfa
commit 913030a955
29 changed files with 409 additions and 232 deletions

View file

@ -5,7 +5,7 @@ mod text;
use image::Image;
use text::Text;
use super::{TabAction, WindowAction};
use super::{ItemAction, WindowAction};
use adw::StatusPage;
use gtk::{
gdk::Paintable,
@ -18,7 +18,7 @@ use std::{rc::Rc, time::Duration};
pub struct Content {
window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>,
item_action: Rc<ItemAction>,
pub g_box: Box,
}
@ -26,11 +26,11 @@ impl Content {
// Construct
/// Create new container for different components
pub fn build((window_action, tab_action): (&Rc<WindowAction>, &Rc<TabAction>)) -> Self {
pub fn build((window_action, item_action): (&Rc<WindowAction>, &Rc<ItemAction>)) -> Self {
Self {
g_box: Box::builder().orientation(Orientation::Vertical).build(),
window_action: window_action.clone(),
tab_action: tab_action.clone(),
item_action: item_action.clone(),
}
}
@ -77,7 +77,7 @@ impl Content {
pub fn to_status_mime(
&self,
mime: &str,
download: Option<(&Rc<TabAction>, &Uri)>,
download: Option<(&Rc<ItemAction>, &Uri)>,
) -> StatusPage {
self.clean();
let status = status::mime::build(mime, download);
@ -90,7 +90,7 @@ impl Content {
/// * action removes previous children component from `Self`
pub fn to_status_identity(&self) -> StatusPage {
self.clean();
let status = status::identity::build(self.tab_action.clone());
let status = status::identity::build(self.item_action.clone());
self.g_box.append(&status);
status
}
@ -122,7 +122,7 @@ impl Content {
/// * could be useful to extract document title parsed from Gemtext
pub fn to_text_gemini(&self, base: &Uri, data: &str) -> Text {
self.clean();
let text = Text::new_gemini(data, base, (&self.window_action, &self.tab_action));
let text = Text::new_gemini(data, base, (&self.window_action, &self.item_action));
self.g_box.append(&text.g_box);
text
}

View file

@ -4,4 +4,4 @@ pub mod identity;
pub mod loading;
pub mod mime;
use super::TabAction;
use super::ItemAction;

View file

@ -1,11 +1,11 @@
use super::TabAction;
use super::ItemAction;
use adw::StatusPage;
use gtk::{glib::Uri, prelude::ButtonExt, Align, Button};
use std::rc::Rc;
/// Create new default `GObject` preset for mime issue
/// [StatusPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.StatusPage.html)
pub fn build(mime: &str, download: Option<(&Rc<TabAction>, &Uri)>) -> StatusPage {
pub fn build(mime: &str, download: Option<(&Rc<ItemAction>, &Uri)>) -> StatusPage {
let status_page = StatusPage::builder()
.description(format!("Content type `{mime}` not supported!"))
.icon_name("dialog-question-symbolic")

View file

@ -4,7 +4,7 @@ mod source;
use gemini::Gemini;
use source::Source;
use super::{TabAction, WindowAction};
use super::{ItemAction, WindowAction};
use gtk::{
glib::Uri,
prelude::{BoxExt, Cast},
@ -28,10 +28,10 @@ impl Text {
pub fn new_gemini(
gemtext: &str,
base: &Uri,
(window_action, tab_action): (&Rc<WindowAction>, &Rc<TabAction>),
(window_action, item_action): (&Rc<WindowAction>, &Rc<ItemAction>),
) -> Self {
// Init components
let gemini = Gemini::new(gemtext, base, (window_action, tab_action));
let gemini = Gemini::new(gemtext, base, (window_action, item_action));
// Init main widget
let g_box = Box::builder().orientation(Orientation::Vertical).build();

View file

@ -4,7 +4,7 @@ mod widget;
use reader::Reader;
use widget::Widget;
use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
use crate::app::browser::window::{tab::item::Action as ItemAction, Action as WindowAction};
use gtk::glib::Uri;
use std::rc::Rc;
@ -18,11 +18,11 @@ impl Gemini {
pub fn new(
gemtext: &str,
base: &Uri,
(window_action, tab_action): (&Rc<WindowAction>, &Rc<TabAction>),
(window_action, item_action): (&Rc<WindowAction>, &Rc<ItemAction>),
) -> Self {
// Init components
let reader = Rc::new(
Reader::new(gemtext, base, (window_action.clone(), tab_action.clone())).unwrap(),
Reader::new(gemtext, base, (window_action.clone(), item_action.clone())).unwrap(),
); // @TODO handle errors
let widget = Rc::new(Widget::new(&reader.widget.text_view));

View file

@ -9,7 +9,7 @@ use syntax::Syntax;
use tag::Tag;
use widget::Widget;
use super::{TabAction, WindowAction};
use super::{ItemAction, WindowAction};
use crate::app::browser::window::action::Position;
use ggemtext::line::{
code::{Inline, Multiline},
@ -43,7 +43,7 @@ impl Reader {
pub fn new(
gemtext: &str,
base: &Uri,
(window_action, tab_action): (Rc<WindowAction>, Rc<TabAction>),
(window_action, item_action): (Rc<WindowAction>, Rc<ItemAction>),
) -> Result<Self, Error> {
// Init default values
let mut title = None;
@ -332,7 +332,7 @@ impl Reader {
return match uri.scheme().as_str() {
"gemini" | "titan" => {
// Open new page in browser
tab_action.load.activate(Some(&uri.to_str()), true);
item_action.load.activate(Some(&uri.to_str()), true);
}
// Scheme not supported, delegate
_ => UriLauncher::new(&uri.to_str()).launch(

View file

@ -2,7 +2,7 @@ mod response;
mod sensitive;
mod titan;
use super::TabAction;
use super::ItemAction;
use adw::Clamp;
use gtk::{glib::Uri, prelude::WidgetExt, Box, Label};
use response::Response;
@ -52,7 +52,7 @@ impl Input {
// Setters
pub fn set_new_response(
&self,
action: Rc<TabAction>,
action: Rc<ItemAction>,
base: Uri,
title: Option<&str>,
size_limit: Option<usize>,
@ -64,7 +64,7 @@ impl Input {
pub fn set_new_sensitive(
&self,
action: Rc<TabAction>,
action: Rc<ItemAction>,
base: Uri,
title: Option<&str>,
max_length: Option<i32>,

View file

@ -6,7 +6,7 @@ use control::Control;
use form::Form;
use title::Title;
use super::TabAction;
use super::ItemAction;
use gtk::{
gio::SimpleAction,
glib::{uuid_string_random, Uri, UriHideFlags},
@ -28,7 +28,7 @@ impl Response {
/// Build new `Self`
pub fn build(
tab_action: Rc<TabAction>,
item_action: Rc<ItemAction>,
base: Uri,
title: Option<&str>,
size_limit: Option<usize>,
@ -77,7 +77,7 @@ impl Response {
action_send.connect_activate({
let form = form.clone();
move |_, _| {
tab_action.load.activate(
item_action.load.activate(
Some(&format!(
"{}?{}",
base.to_string_partial(UriHideFlags::QUERY),

View file

@ -1,6 +1,6 @@
mod form;
use super::TabAction;
use super::ItemAction;
use form::Form;
use gtk::{
gio::SimpleAction,
@ -22,7 +22,7 @@ impl Sensitive {
/// Build new `Self`
pub fn build(
tab_action: Rc<TabAction>,
item_action: Rc<ItemAction>,
base: Uri,
title: Option<&str>,
max_length: Option<i32>,
@ -54,7 +54,7 @@ impl Sensitive {
action_send.connect_activate({
let form = form.clone();
move |_, _| {
tab_action.load.activate(
item_action.load.activate(
Some(&format!(
"{}?{}",
base.to_string_partial(UriHideFlags::QUERY),

View file

@ -6,20 +6,18 @@ mod reload;
mod request;
mod widget;
use super::{BrowserAction, ItemAction, Profile, WindowAction};
use bookmark::Bookmark;
use gtk::Button;
use gtk::{Box, Button};
use history::History;
use home::Home;
use reload::Reload;
use request::Request;
use widget::Widget;
use super::{BrowserAction, Profile, TabAction, WindowAction};
use sqlite::Transaction;
use std::rc::Rc;
use widget::Widget;
pub struct Navigation {
pub history: Rc<History>,
pub profile: Rc<Profile>,
pub request: Rc<Request>,
pub widget: Rc<Widget>,
@ -28,21 +26,21 @@ pub struct Navigation {
impl Navigation {
pub fn build(
profile: &Rc<Profile>,
(browser_action, window_action, tab_action): (
(browser_action, window_action, item_action): (
&Rc<BrowserAction>,
&Rc<WindowAction>,
&Rc<TabAction>,
&Rc<ItemAction>,
),
(back_action_name, forward_action_name): (&str, &str),
) -> Self {
// init children components
let history = Rc::new(History::build(window_action));
let request = Rc::new(Request::build((browser_action, tab_action)));
let request = Rc::new(Request::build((browser_action, item_action)));
// init main widget
let widget = Rc::new(Widget::build(
&Button::home(window_action),
&history.widget.g_box, // @TODO
&Box::history(back_action_name, forward_action_name),
&Button::reload(window_action),
&request.widget.entry, // @TODO
&Button::bookmark(window_action),
@ -50,7 +48,6 @@ impl Navigation {
// done
Self {
history,
profile: profile.clone(),
request,
widget,

View file

@ -1,107 +1,26 @@
mod back;
mod forward;
mod widget;
pub mod back;
pub mod forward;
use back::Back;
use forward::Forward;
use widget::Widget;
pub use back::Back;
pub use forward::Forward;
use super::WindowAction;
use gtk::{glib::GString, Button};
use std::{cell::RefCell, rc::Rc};
use gtk::{prelude::BoxExt, Box, Button, Orientation};
struct Memory {
request: GString,
// time: SystemTime,
pub trait History {
fn history(back_action_name: &str, forward_action_name: &str) -> Self;
}
pub struct History {
// Extras
memory: RefCell<Vec<Memory>>,
index: RefCell<Option<usize>>,
// GTK
pub widget: Rc<Widget>,
}
impl History for Box {
fn history(back_action_name: &str, forward_action_name: &str) -> Self {
let g_box = Box::builder()
.orientation(Orientation::Horizontal)
.css_classes([
"linked", // merge childs
])
.build();
impl History {
// Constructors
/// Build new `Self`
pub fn build(action: &Rc<WindowAction>) -> Self {
// Init widget
let widget = Rc::new(Widget::build(
&Button::back(action),
&Button::forward(action),
));
// Init memory
let memory = RefCell::new(Vec::new());
// Init index
let index = RefCell::new(None);
Self {
memory,
index,
widget,
}
}
// Actions
pub fn add(&self, request: GString, follow_to_index: bool) {
// Append new Memory record
self.memory.borrow_mut().push(Memory {
request: request.clone(),
//time: SystemTime::now(),
});
if follow_to_index {
// Even push action make positive len value, make sure twice
if !self.memory.borrow().is_empty() {
// Navigate to the last record appended
self.index.replace(Some(self.memory.borrow().len() - 1));
} else {
self.index.replace(None);
}
}
}
pub fn back(&self, follow_to_index: bool) -> Option<GString> {
let index = *self.index.borrow();
if let Some(usize) = index {
// Make sure value positive to prevent panic
if usize > 0 {
if let Some(memory) = self.memory.borrow().get(usize - 1) {
if follow_to_index {
self.index.replace(Some(usize - 1));
}
return Some(memory.request.clone());
}
}
}
None
}
pub fn current(&self) -> Option<GString> {
let index = *self.index.borrow();
if let Some(usize) = index {
if let Some(memory) = self.memory.borrow().get(usize) {
return Some(memory.request.clone());
}
}
None
}
pub fn forward(&self, follow_to_index: bool) -> Option<GString> {
let index = *self.index.borrow();
if let Some(usize) = index {
if let Some(memory) = self.memory.borrow().get(usize + 1) {
if follow_to_index {
self.index.replace(Some(usize + 1));
}
return Some(memory.request.clone());
}
}
None
g_box.append(&Button::back(back_action_name));
g_box.append(&Button::forward(forward_action_name));
g_box
}
}

View file

@ -1,19 +1,13 @@
use super::WindowAction;
use gtk::{prelude::ActionExt, Button};
use std::rc::Rc;
use gtk::Button;
pub trait Back {
fn back(action: &Rc<WindowAction>) -> Self;
fn back(action_name: &str) -> Self;
}
impl Back for Button {
fn back(action: &Rc<WindowAction>) -> Self {
fn back(action_name: &str) -> Self {
Button::builder()
.action_name(format!(
"{}.{}",
action.id,
action.history_back.simple_action.name()
)) // @TODO
.action_name(action_name)
.icon_name("go-previous-symbolic")
.tooltip_text("Back")
.build()

View file

@ -1,19 +1,13 @@
use super::WindowAction;
use gtk::{prelude::ActionExt, Button};
use std::rc::Rc;
use gtk::Button;
pub trait Forward {
fn forward(action: &Rc<WindowAction>) -> Self;
fn forward(action_name: &str) -> Self;
}
impl Forward for Button {
fn forward(action: &Rc<WindowAction>) -> Self {
fn forward(action_name: &str) -> Self {
Button::builder()
.action_name(format!(
"{}.{}",
action.id,
action.history_back.simple_action.name()
)) // @TODO
.action_name(action_name)
.icon_name("go-next-symbolic")
.tooltip_text("Forward")
.build()

View file

@ -1,27 +0,0 @@
use gtk::{
prelude::{BoxExt, IsA},
Box, Orientation,
};
pub struct Widget {
pub g_box: Box,
}
impl Widget {
// Constructors
/// Build new `Self`
pub fn build(back: &impl IsA<gtk::Widget>, forward: &impl IsA<gtk::Widget>) -> Self {
let g_box = Box::builder()
.orientation(Orientation::Horizontal)
.css_classes([
"linked", // merge childs
])
.build();
g_box.append(back);
g_box.append(forward);
Self { g_box }
}
}

View file

@ -4,7 +4,7 @@ mod widget;
use widget::Widget;
use crate::app::browser::{window::tab::item::Action as TabAction, Action as BrowserAction};
use crate::app::browser::{window::tab::item::Action as ItemAction, Action as BrowserAction};
use gtk::{
glib::{gformat, GString, Uri, UriFlags},
prelude::EditableExt,
@ -21,9 +21,9 @@ impl Request {
// Constructors
/// Build new `Self`
pub fn build((browser_action, tab_action): (&Rc<BrowserAction>, &Rc<TabAction>)) -> Self {
pub fn build((browser_action, item_action): (&Rc<BrowserAction>, &Rc<ItemAction>)) -> Self {
Self {
widget: Rc::new(Widget::build((browser_action, tab_action))),
widget: Rc::new(Widget::build((browser_action, item_action))),
}
}

View file

@ -3,7 +3,7 @@ mod primary_icon;
use primary_icon::PrimaryIcon;
use super::{BrowserAction, TabAction};
use super::{BrowserAction, ItemAction};
use gtk::{
glib::{timeout_add_local, ControlFlow, SourceId},
prelude::{EditableExt, EntryExt, WidgetExt},
@ -36,7 +36,7 @@ impl Widget {
// Constructors
/// Build new `Self`
pub fn build((browser_action, tab_action): (&Rc<BrowserAction>, &Rc<TabAction>)) -> Self {
pub fn build((browser_action, item_action): (&Rc<BrowserAction>, &Rc<ItemAction>)) -> Self {
// Init animated progress bar state
let progress = Rc::new(Progress {
fraction: RefCell::new(0.0),
@ -52,10 +52,10 @@ impl Widget {
// Connect events
entry.connect_icon_release({
let tab_action = tab_action.clone();
let item_action = item_action.clone();
move |this, position| match position {
EntryIconPosition::Primary => tab_action.ident.activate(), // @TODO PrimaryIcon impl
EntryIconPosition::Secondary => tab_action.load.activate(Some(&this.text()), true),
EntryIconPosition::Primary => item_action.ident.activate(), // @TODO PrimaryIcon impl
EntryIconPosition::Secondary => item_action.load.activate(Some(&this.text()), true),
_ => todo!(), // unexpected
}
});
@ -77,9 +77,9 @@ impl Widget {
});
entry.connect_activate({
let tab_action = tab_action.clone();
let item_action = item_action.clone();
move |entry| {
tab_action.load.activate(Some(&entry.text()), true);
item_action.load.activate(Some(&entry.text()), true);
}
});