mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-02-04 07:24:17 +00:00
add new tab item action group, delegate history handle to action implementation
This commit is contained in:
parent
5145a53bfa
commit
913030a955
@ -37,17 +37,22 @@ impl Browser {
|
||||
let widget = Rc::new(Widget::new(
|
||||
&window.widget.g_box,
|
||||
&[
|
||||
// Connect action groups (to apply accels)
|
||||
// action groups
|
||||
(
|
||||
// Browser
|
||||
// browser
|
||||
&action.id,
|
||||
action.simple_action_group.clone(),
|
||||
),
|
||||
(
|
||||
// Window
|
||||
// window
|
||||
&window.action.id,
|
||||
window.action.simple_action_group.clone(),
|
||||
),
|
||||
(
|
||||
// tab
|
||||
&window.tab.action.id,
|
||||
window.tab.action.simple_action_group.clone(),
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
mod action;
|
||||
mod database;
|
||||
mod error;
|
||||
mod item;
|
||||
mod menu;
|
||||
mod widget;
|
||||
|
||||
use action::Action;
|
||||
use error::Error;
|
||||
pub use item::Item;
|
||||
use menu::Menu;
|
||||
@ -27,6 +29,7 @@ pub struct Tab {
|
||||
window_action: Rc<WindowAction>,
|
||||
profile: Rc<Profile>,
|
||||
index: Rc<RefCell<HashMap<Rc<GString>, Rc<Item>>>>,
|
||||
pub action: Rc<Action>,
|
||||
pub widget: Rc<Widget>,
|
||||
}
|
||||
|
||||
@ -38,6 +41,8 @@ impl Tab {
|
||||
profile: &Rc<Profile>,
|
||||
(browser_action, window_action): (&Rc<BrowserAction>, &Rc<WindowAction>),
|
||||
) -> Self {
|
||||
let action = Rc::new(Action::new());
|
||||
|
||||
// Init empty HashMap index
|
||||
let index: Rc<RefCell<HashMap<Rc<GString>, Rc<Item>>>> =
|
||||
Rc::new(RefCell::new(HashMap::new()));
|
||||
@ -142,6 +147,7 @@ impl Tab {
|
||||
window_action: window_action.clone(),
|
||||
index,
|
||||
widget,
|
||||
action,
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +166,7 @@ impl Tab {
|
||||
&self.widget.tab_view,
|
||||
&self.profile,
|
||||
// Actions
|
||||
(&self.browser_action, &self.window_action),
|
||||
(&self.browser_action, &self.window_action, &self.action),
|
||||
// Options
|
||||
(
|
||||
position,
|
||||
@ -260,19 +266,13 @@ impl Tab {
|
||||
|
||||
pub fn page_history_back(&self, page_position: Option<i32>) {
|
||||
if let Some(item) = self.item(page_position) {
|
||||
if let Some(back) = item.page.navigation.history.back(true) {
|
||||
item.page.navigation.request.widget.entry.set_text(&back);
|
||||
item.client.handle(&back, false);
|
||||
}
|
||||
item.action.history.back(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn page_history_forward(&self, page_position: Option<i32>) {
|
||||
if let Some(item) = self.item(page_position) {
|
||||
if let Some(forward) = item.page.navigation.history.forward(true) {
|
||||
item.page.navigation.request.widget.entry.set_text(&forward);
|
||||
item.client.handle(&forward, false);
|
||||
}
|
||||
item.action.history.forward(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,7 +338,7 @@ impl Tab {
|
||||
transaction,
|
||||
record.id,
|
||||
&self.profile,
|
||||
(&self.browser_action, &self.window_action),
|
||||
(&self.browser_action, &self.window_action, &self.action),
|
||||
) {
|
||||
Ok(items) => {
|
||||
for item in items {
|
||||
|
25
src/app/browser/window/tab/action.rs
Normal file
25
src/app/browser/window/tab/action.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use gtk::{
|
||||
gio::SimpleActionGroup,
|
||||
glib::{uuid_string_random, GString},
|
||||
};
|
||||
|
||||
/// [SimpleActionGroup](https://docs.gtk.org/gio/class.SimpleActionGroup.html) wrapper for `Tab` actions
|
||||
pub struct Action {
|
||||
pub id: GString,
|
||||
pub simple_action_group: SimpleActionGroup,
|
||||
}
|
||||
|
||||
impl Default for Action {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Action {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
id: uuid_string_random(),
|
||||
simple_action_group: SimpleActionGroup::new(),
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ use adw::TabView;
|
||||
use client::Client;
|
||||
use gtk::{
|
||||
glib::{uuid_string_random, GString},
|
||||
prelude::{Cast, EditableExt},
|
||||
prelude::{ActionExt, ActionMapExt, Cast, EditableExt},
|
||||
};
|
||||
use page::Page;
|
||||
use sqlite::Transaction;
|
||||
@ -31,6 +31,7 @@ pub struct Item {
|
||||
// Components
|
||||
pub page: Rc<Page>,
|
||||
pub widget: Rc<Widget>,
|
||||
pub action: Rc<Action>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
@ -40,7 +41,11 @@ impl Item {
|
||||
pub fn build(
|
||||
tab_view: &TabView,
|
||||
profile: &Rc<Profile>,
|
||||
(browser_action, window_action): (&Rc<BrowserAction>, &Rc<WindowAction>),
|
||||
(browser_action, window_action, tab_action): (
|
||||
&Rc<BrowserAction>,
|
||||
&Rc<WindowAction>,
|
||||
&Rc<super::Action>,
|
||||
),
|
||||
(position, request, is_pinned, is_selected, is_attention, is_load): (
|
||||
Position,
|
||||
Option<String>,
|
||||
@ -57,10 +62,22 @@ impl Item {
|
||||
|
||||
let action = Rc::new(Action::new());
|
||||
|
||||
tab_action
|
||||
.simple_action_group
|
||||
.add_action(&action.history.back);
|
||||
|
||||
tab_action
|
||||
.simple_action_group
|
||||
.add_action(&action.history.forward);
|
||||
|
||||
let page = Rc::new(Page::build(
|
||||
&id,
|
||||
profile,
|
||||
(browser_action, window_action, &action),
|
||||
(
|
||||
&format!("{}.{}", &tab_action.id, action.history.back.name()),
|
||||
&format!("{}.{}", &tab_action.id, action.history.forward.name()),
|
||||
),
|
||||
));
|
||||
|
||||
let widget = Rc::new(Widget::build(
|
||||
@ -128,6 +145,7 @@ impl Item {
|
||||
client,
|
||||
page,
|
||||
widget,
|
||||
action,
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +187,11 @@ impl Item {
|
||||
app_browser_window_tab_id: i64,
|
||||
profile: &Rc<Profile>,
|
||||
// Actions
|
||||
(browser_action, window_action): (&Rc<BrowserAction>, &Rc<WindowAction>),
|
||||
(browser_action, window_action, item_action): (
|
||||
&Rc<BrowserAction>,
|
||||
&Rc<WindowAction>,
|
||||
&Rc<super::Action>,
|
||||
),
|
||||
) -> Result<Vec<Rc<Item>>, String> {
|
||||
let mut items = Vec::new();
|
||||
|
||||
@ -181,7 +203,7 @@ impl Item {
|
||||
tab_view,
|
||||
profile,
|
||||
// Actions
|
||||
(browser_action, window_action),
|
||||
(browser_action, window_action, item_action),
|
||||
// Options tuple
|
||||
(
|
||||
Position::End,
|
||||
|
@ -1,6 +1,8 @@
|
||||
mod history;
|
||||
mod ident;
|
||||
mod load;
|
||||
|
||||
use history::History;
|
||||
use ident::Ident;
|
||||
use load::Load;
|
||||
|
||||
@ -8,6 +10,7 @@ use std::rc::Rc;
|
||||
|
||||
/// [SimpleActionGroup](https://docs.gtk.org/gio/class.SimpleActionGroup.html) wrapper for `Browser` actions
|
||||
pub struct Action {
|
||||
pub history: Rc<History>,
|
||||
pub ident: Rc<Ident>,
|
||||
pub load: Rc<Load>,
|
||||
}
|
||||
@ -23,9 +26,18 @@ impl Action {
|
||||
|
||||
/// Create new `Self`
|
||||
pub fn new() -> Self {
|
||||
let ident = Rc::new(Ident::new());
|
||||
let load = Rc::new(Load::new());
|
||||
|
||||
let history = Rc::new(History::build({
|
||||
let load = load.clone();
|
||||
move |request| load.activate(Some(&request), false)
|
||||
}));
|
||||
|
||||
Self {
|
||||
ident: Rc::new(Ident::new()),
|
||||
load: Rc::new(Load::new()),
|
||||
history,
|
||||
ident,
|
||||
load,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
79
src/app/browser/window/tab/item/action/history.rs
Normal file
79
src/app/browser/window/tab/item/action/history.rs
Normal file
@ -0,0 +1,79 @@
|
||||
mod back;
|
||||
mod forward;
|
||||
mod memory;
|
||||
|
||||
use back::Back;
|
||||
use forward::Forward;
|
||||
use gtk::{gio::SimpleAction, glib::GString};
|
||||
use memory::Memory;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct History {
|
||||
memory: Rc<Memory>,
|
||||
pub back: SimpleAction,
|
||||
pub forward: SimpleAction,
|
||||
}
|
||||
|
||||
impl History {
|
||||
// Constructors
|
||||
|
||||
/// Build new activated `Self`
|
||||
pub fn build(callback: impl Fn(GString) + 'static) -> Self {
|
||||
// Init childs
|
||||
let memory = Rc::new(Memory::new());
|
||||
let back = SimpleAction::back();
|
||||
let forward = SimpleAction::forward();
|
||||
|
||||
// Init events
|
||||
let callback = Rc::new(callback);
|
||||
|
||||
back.connect_activate({
|
||||
let callback = callback.clone();
|
||||
let forward = forward.clone();
|
||||
let memory = memory.clone();
|
||||
move |this, _| {
|
||||
if let Some(request) = memory.back(true) {
|
||||
callback(request)
|
||||
}
|
||||
forward.set_enabled(memory.next(false).is_some());
|
||||
this.set_enabled(memory.back(false).is_some());
|
||||
}
|
||||
});
|
||||
|
||||
forward.connect_activate({
|
||||
let back = back.clone();
|
||||
let callback = callback.clone();
|
||||
let memory = memory.clone();
|
||||
move |this, _| {
|
||||
if let Some(request) = memory.next(true) {
|
||||
callback(request)
|
||||
}
|
||||
back.set_enabled(memory.back(false).is_some());
|
||||
this.set_enabled(memory.next(false).is_some());
|
||||
}
|
||||
});
|
||||
|
||||
// Done
|
||||
Self {
|
||||
memory,
|
||||
back,
|
||||
forward,
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
pub fn add(&self, request: GString, follow_to_index: bool) {
|
||||
self.memory.add(request, follow_to_index);
|
||||
self.back.set_enabled(self.back(false).is_some());
|
||||
self.forward.set_enabled(self.forward(false).is_some());
|
||||
}
|
||||
|
||||
pub fn back(&self, follow_to_index: bool) -> Option<GString> {
|
||||
self.memory.back(follow_to_index)
|
||||
}
|
||||
|
||||
pub fn forward(&self, follow_to_index: bool) -> Option<GString> {
|
||||
self.memory.next(follow_to_index)
|
||||
}
|
||||
}
|
13
src/app/browser/window/tab/item/action/history/back.rs
Normal file
13
src/app/browser/window/tab/item/action/history/back.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use gtk::{gio::SimpleAction, glib::uuid_string_random};
|
||||
|
||||
pub trait Back {
|
||||
fn back() -> Self;
|
||||
}
|
||||
|
||||
impl Back for SimpleAction {
|
||||
fn back() -> Self {
|
||||
let back = SimpleAction::new(&uuid_string_random(), None);
|
||||
back.set_enabled(false);
|
||||
back
|
||||
}
|
||||
}
|
13
src/app/browser/window/tab/item/action/history/forward.rs
Normal file
13
src/app/browser/window/tab/item/action/history/forward.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use gtk::{gio::SimpleAction, glib::uuid_string_random};
|
||||
|
||||
pub trait Forward {
|
||||
fn forward() -> Self;
|
||||
}
|
||||
|
||||
impl Forward for SimpleAction {
|
||||
fn forward() -> Self {
|
||||
let forward = SimpleAction::new(&uuid_string_random(), None);
|
||||
forward.set_enabled(false);
|
||||
forward
|
||||
}
|
||||
}
|
68
src/app/browser/window/tab/item/action/history/memory.rs
Normal file
68
src/app/browser/window/tab/item/action/history/memory.rs
Normal file
@ -0,0 +1,68 @@
|
||||
mod cursor;
|
||||
|
||||
use cursor::Cursor;
|
||||
use gtk::glib::GString;
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct Memory {
|
||||
cursor: RefCell<Cursor>,
|
||||
index: RefCell<Vec<GString>>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
// Constructors
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cursor: RefCell::new(Cursor::new()),
|
||||
index: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
pub fn add(&self, value: GString, follow_to_index: bool) {
|
||||
let mut index = self.index.borrow_mut();
|
||||
|
||||
match index.last() {
|
||||
Some(last) => {
|
||||
if *last != value {
|
||||
index.push(value);
|
||||
}
|
||||
}
|
||||
None => index.push(value),
|
||||
}
|
||||
|
||||
if follow_to_index {
|
||||
self.cursor.borrow_mut().go_last(index.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn back(&self, follow_to_index: bool) -> Option<GString> {
|
||||
let index = self.index.borrow();
|
||||
let len = index.len();
|
||||
|
||||
match if follow_to_index {
|
||||
self.cursor.borrow_mut().go_back(len)
|
||||
} else {
|
||||
self.cursor.borrow().back(len)
|
||||
} {
|
||||
Some(i) => index.get(i).cloned(),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&self, follow_to_index: bool) -> Option<GString> {
|
||||
let index = self.index.borrow();
|
||||
let len = index.len();
|
||||
|
||||
match if follow_to_index {
|
||||
self.cursor.borrow_mut().go_next(len)
|
||||
} else {
|
||||
self.cursor.borrow().next(len)
|
||||
} {
|
||||
Some(i) => index.get(i).cloned(),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
pub struct Cursor(Option<usize>);
|
||||
|
||||
impl Default for Cursor {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
// Constructors
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self(None)
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
pub fn go_last(&mut self, len: usize) -> Option<usize> {
|
||||
self.0 = len2i(len);
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn go_next(&mut self, len: usize) -> Option<usize> {
|
||||
self.0 = self.next(len);
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn go_back(&mut self, len: usize) -> Option<usize> {
|
||||
self.0 = self.back(len);
|
||||
self.0
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
pub fn next(&self, len: usize) -> Option<usize> {
|
||||
let i = len2i(len)?;
|
||||
let n = self.0.unwrap_or_default();
|
||||
|
||||
if n < i {
|
||||
Some(n + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn back(&self, len: usize) -> Option<usize> {
|
||||
len2i(len)?;
|
||||
let n = self.0.unwrap_or_default();
|
||||
|
||||
if n > 0 {
|
||||
Some(n - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
||||
fn len2i(len: usize) -> Option<usize> {
|
||||
if len > 0 {
|
||||
Some(len - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@ impl Client {
|
||||
// begin redirection to new address suggested
|
||||
Err(uri) => subject
|
||||
.page
|
||||
.tab_action
|
||||
.item_action
|
||||
.load
|
||||
.activate(Some(&uri.to_string()), false),
|
||||
}
|
||||
@ -215,10 +215,5 @@ fn snap_history(subject: &Rc<Subject>, uri: Option<&Uri>) {
|
||||
}
|
||||
|
||||
// Add new record into the page navigation history
|
||||
if match subject.page.navigation.history.current() {
|
||||
Some(current) => current != request, // apply additional filters
|
||||
None => true,
|
||||
} {
|
||||
subject.page.navigation.history.add(request, true)
|
||||
}
|
||||
subject.page.item_action.history.add(request, true)
|
||||
}
|
||||
|
@ -185,14 +185,14 @@ fn handle(
|
||||
};
|
||||
if matches!(response.meta.status, Status::SensitiveInput) {
|
||||
subject.page.input.set_new_sensitive(
|
||||
subject.page.tab_action.clone(),
|
||||
subject.page.item_action.clone(),
|
||||
uri,
|
||||
Some(&title),
|
||||
Some(1024),
|
||||
);
|
||||
} else {
|
||||
subject.page.input.set_new_response(
|
||||
subject.page.tab_action.clone(),
|
||||
subject.page.item_action.clone(),
|
||||
uri,
|
||||
Some(&title),
|
||||
Some(1024),
|
||||
@ -369,7 +369,7 @@ fn handle(
|
||||
mime => {
|
||||
let status = subject.page
|
||||
.content
|
||||
.to_status_mime(mime, Some((&subject.page.tab_action, &uri)));
|
||||
.to_status_mime(mime, Some((&subject.page.item_action, &uri)));
|
||||
status.set_description(Some(&format!("Content type `{mime}` yet not supported")));
|
||||
subject.page.navigation.request.widget.entry.set_progress_fraction(0.0);
|
||||
subject.tab_page.set_loading(false);
|
||||
@ -443,7 +443,7 @@ fn handle(
|
||||
.set_text(&uri.to_string());
|
||||
}
|
||||
redirects.replace(total);
|
||||
subject.page.tab_action.load.activate(Some(&target.to_string()), false);
|
||||
subject.page.item_action.load.activate(Some(&target.to_string()), false);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
@ -13,7 +13,7 @@ use navigation::Navigation;
|
||||
use search::Search;
|
||||
use widget::Widget;
|
||||
|
||||
use super::{Action as TabAction, BrowserAction, Profile, WindowAction};
|
||||
use super::{Action as ItemAction, BrowserAction, Profile, WindowAction};
|
||||
|
||||
use gtk::{glib::GString, prelude::EditableExt};
|
||||
use sqlite::Transaction;
|
||||
@ -24,7 +24,7 @@ pub struct Page {
|
||||
pub profile: Rc<Profile>,
|
||||
// Actions
|
||||
pub browser_action: Rc<BrowserAction>,
|
||||
pub tab_action: Rc<TabAction>,
|
||||
pub item_action: Rc<ItemAction>,
|
||||
pub window_action: Rc<WindowAction>,
|
||||
// Components
|
||||
pub content: Rc<Content>,
|
||||
@ -40,20 +40,22 @@ impl Page {
|
||||
pub fn build(
|
||||
id: &Rc<GString>,
|
||||
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 components
|
||||
let content = Rc::new(Content::build((window_action, tab_action)));
|
||||
let content = Rc::new(Content::build((window_action, item_action)));
|
||||
|
||||
let search = Rc::new(Search::new());
|
||||
|
||||
let navigation = Rc::new(Navigation::build(
|
||||
profile,
|
||||
(browser_action, window_action, tab_action),
|
||||
(browser_action, window_action, item_action),
|
||||
(back_action_name, forward_action_name),
|
||||
));
|
||||
|
||||
let input = Rc::new(Input::new());
|
||||
@ -72,7 +74,7 @@ impl Page {
|
||||
profile: profile.clone(),
|
||||
// Actions
|
||||
browser_action: browser_action.clone(),
|
||||
tab_action: tab_action.clone(),
|
||||
item_action: item_action.clone(),
|
||||
window_action: window_action.clone(),
|
||||
// Components
|
||||
content,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -4,4 +4,4 @@ pub mod identity;
|
||||
pub mod loading;
|
||||
pub mod mime;
|
||||
|
||||
use super::TabAction;
|
||||
use super::ItemAction;
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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>,
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user