mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-04-01 09:05:27 +00:00
move is_needs_attention state to page, reorganize TabView access levels
This commit is contained in:
parent
8356c432c1
commit
25db274d2e
5 changed files with 158 additions and 191 deletions
|
|
@ -13,9 +13,11 @@ use gtk::{
|
||||||
gio::Icon,
|
gio::Icon,
|
||||||
glib::{DateTime, Propagation},
|
glib::{DateTime, Propagation},
|
||||||
prelude::ActionExt,
|
prelude::ActionExt,
|
||||||
|
Box, Orientation,
|
||||||
};
|
};
|
||||||
pub use item::Item;
|
pub use item::Item;
|
||||||
use menu::Menu;
|
use menu::Menu;
|
||||||
|
use sourceview::prelude::IsA;
|
||||||
use sqlite::Transaction;
|
use sqlite::Transaction;
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
|
|
@ -113,26 +115,27 @@ impl Tab {
|
||||||
request: Option<&str>,
|
request: Option<&str>,
|
||||||
is_pinned: bool,
|
is_pinned: bool,
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
is_attention: bool,
|
is_needs_attention: bool,
|
||||||
is_load: bool,
|
is_load: bool,
|
||||||
) -> Rc<Item> {
|
) -> Rc<Item> {
|
||||||
|
// Generate new `TabPage` with blank `Widget`
|
||||||
|
let (tab_page, target_child) = new_tab_page(&self.tab_view, position);
|
||||||
|
|
||||||
// Init new tab item
|
// Init new tab item
|
||||||
let item = Rc::new(Item::build(
|
let item = Rc::new(Item::build(
|
||||||
&self.tab_view,
|
(&tab_page, &target_child),
|
||||||
&self.profile,
|
&self.profile,
|
||||||
// Actions
|
// Actions
|
||||||
(&self.browser_action, &self.window_action, &self.action),
|
(&self.browser_action, &self.window_action, &self.action),
|
||||||
// Options
|
// Options
|
||||||
(
|
request,
|
||||||
position,
|
is_load,
|
||||||
request,
|
|
||||||
is_pinned,
|
|
||||||
is_selected,
|
|
||||||
is_attention,
|
|
||||||
is_load,
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Make initial setup
|
||||||
|
item.page.set_needs_attention(is_needs_attention);
|
||||||
|
item.page.set_title("New page");
|
||||||
|
|
||||||
// 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()) {
|
||||||
|
|
@ -142,7 +145,14 @@ impl Tab {
|
||||||
// Register dynamically created tab components in the HashMap index
|
// Register dynamically created tab components in the HashMap index
|
||||||
self.index
|
self.index
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(item.page.tab_page.clone(), item.clone());
|
.insert(item.tab_page.clone(), item.clone());
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
// * important to call these actions after index!
|
||||||
|
self.tab_view.set_page_pinned(&item.tab_page, is_pinned);
|
||||||
|
if is_selected {
|
||||||
|
self.tab_view.set_selected_page(&item.tab_page);
|
||||||
|
}
|
||||||
|
|
||||||
update_actions(
|
update_actions(
|
||||||
&self.tab_view,
|
&self.tab_view,
|
||||||
|
|
@ -281,7 +291,6 @@ impl Tab {
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,30 +300,44 @@ impl Tab {
|
||||||
app_browser_window_id: i64,
|
app_browser_window_id: i64,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match database::select(transaction, app_browser_window_id) {
|
match database::select(transaction, app_browser_window_id) {
|
||||||
Ok(records) => {
|
Ok(tab_records) => {
|
||||||
for record in records {
|
for tab_record in tab_records {
|
||||||
match Item::restore(
|
for item_record in item::restore(transaction, tab_record.id)? {
|
||||||
&self.tab_view,
|
// Generate new `TabPage` with blank `Widget`
|
||||||
transaction,
|
let (tab_page, target_child) =
|
||||||
record.id,
|
new_tab_page(&self.tab_view, Position::After);
|
||||||
&self.profile,
|
|
||||||
(&self.browser_action, &self.window_action, &self.action),
|
// Init new tab item
|
||||||
) {
|
let item = Rc::new(Item::build(
|
||||||
Ok(items) => {
|
(&tab_page, &target_child),
|
||||||
for item in items {
|
&self.profile,
|
||||||
// Register dynamically created tab item in the HashMap index
|
// Actions
|
||||||
self.index
|
(&self.browser_action, &self.window_action, &self.action),
|
||||||
.borrow_mut()
|
// Options
|
||||||
.insert(item.page.tab_page.clone(), item.clone());
|
None,
|
||||||
}
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.index
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(item.tab_page.clone(), item.clone());
|
||||||
|
|
||||||
|
// Restore `Self`
|
||||||
|
// * important to call these actions after index!
|
||||||
|
self.tab_view
|
||||||
|
.set_page_pinned(&item.tab_page, item_record.is_pinned);
|
||||||
|
|
||||||
|
if item_record.is_selected {
|
||||||
|
self.tab_view.set_selected_page(&item.tab_page);
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
|
// Restore children components
|
||||||
|
item.page.restore(transaction, item_record.id)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,22 +350,12 @@ impl Tab {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Delegate save action to childs
|
// Delegate save action to childs
|
||||||
let id = database::last_insert_id(transaction);
|
let id = database::last_insert_id(transaction);
|
||||||
|
|
||||||
// Read collected HashMap index
|
|
||||||
for (_, item) in self.index.borrow().iter() {
|
for (_, item) in self.index.borrow().iter() {
|
||||||
item.save(
|
item.save(transaction, id, self.tab_view.page_position(&item.tab_page))?;
|
||||||
transaction,
|
|
||||||
id,
|
|
||||||
self.tab_view.page_position(&item.page.tab_page),
|
|
||||||
item.page.tab_page.is_pinned(),
|
|
||||||
item.page.tab_page.is_selected(),
|
|
||||||
item.page.tab_page.needs_attention(),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,8 +368,8 @@ impl Tab {
|
||||||
// @TODO other/child features..
|
// @TODO other/child features..
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item(&self, tab_page_position: Option<i32>) -> Option<Rc<Item>> {
|
fn item(&self, page_position: Option<i32>) -> Option<Rc<Item>> {
|
||||||
if let Some(tab_page) = match tab_page_position {
|
if let Some(tab_page) = match page_position {
|
||||||
Some(value) => Some(self.tab_view.nth_page(value)),
|
Some(value) => Some(self.tab_view.nth_page(value)),
|
||||||
None => self.tab_view.selected_page(),
|
None => self.tab_view.selected_page(),
|
||||||
} {
|
} {
|
||||||
|
|
@ -426,3 +439,33 @@ fn update_actions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create new [TabPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabPage.html)
|
||||||
|
/// in [TabView](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabView.html) at given position
|
||||||
|
///
|
||||||
|
/// * if given `position` match pinned tab, GTK will panic with notice:
|
||||||
|
/// adw_tab_view_insert: assertion 'position >= self->n_pinned_pages'\
|
||||||
|
/// as the solution, prepend new page after pinned tabs in this case
|
||||||
|
fn add_tab_page(tab_view: &TabView, child: &impl IsA<gtk::Widget>, position: i32) -> TabPage {
|
||||||
|
if position > tab_view.n_pinned_pages() {
|
||||||
|
tab_view.insert(child, position)
|
||||||
|
} else {
|
||||||
|
tab_view.prepend(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn new_tab_page(tab_view: &TabView, position: Position) -> (TabPage, Box) {
|
||||||
|
let child = Box::builder().orientation(Orientation::Vertical).build();
|
||||||
|
(
|
||||||
|
match position {
|
||||||
|
Position::After => match tab_view.selected_page() {
|
||||||
|
Some(selected_page) => {
|
||||||
|
add_tab_page(tab_view, &child, tab_view.page_position(&selected_page) + 1)
|
||||||
|
}
|
||||||
|
None => tab_view.append(&child),
|
||||||
|
},
|
||||||
|
Position::End => tab_view.append(&child),
|
||||||
|
Position::Number(value) => add_tab_page(tab_view, &child, value),
|
||||||
|
},
|
||||||
|
child,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@ mod client;
|
||||||
mod database;
|
mod database;
|
||||||
mod page;
|
mod page;
|
||||||
|
|
||||||
use super::{Action as TabAction, BrowserAction, Position, WindowAction};
|
use super::{Action as TabAction, BrowserAction, WindowAction};
|
||||||
use crate::Profile;
|
use crate::Profile;
|
||||||
use action::Action;
|
use action::Action;
|
||||||
use adw::TabView;
|
use adw::TabPage;
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use gtk::prelude::ActionMapExt;
|
use gtk::{
|
||||||
|
prelude::{ActionMapExt, BoxExt},
|
||||||
|
Box,
|
||||||
|
};
|
||||||
use page::Page;
|
use page::Page;
|
||||||
use sqlite::Transaction;
|
use sqlite::Transaction;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -19,6 +22,7 @@ pub struct Item {
|
||||||
// Components
|
// Components
|
||||||
pub page: Rc<Page>,
|
pub page: Rc<Page>,
|
||||||
pub action: Rc<Action>,
|
pub action: Rc<Action>,
|
||||||
|
pub tab_page: TabPage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
|
|
@ -26,21 +30,15 @@ impl Item {
|
||||||
|
|
||||||
/// Build new `Self`
|
/// Build new `Self`
|
||||||
pub fn build(
|
pub fn build(
|
||||||
tab_view: &TabView,
|
(tab_page, target_child): (&TabPage, &Box),
|
||||||
profile: &Rc<Profile>,
|
profile: &Rc<Profile>,
|
||||||
(browser_action, window_action, tab_action): (
|
(browser_action, window_action, tab_action): (
|
||||||
&Rc<BrowserAction>,
|
&Rc<BrowserAction>,
|
||||||
&Rc<WindowAction>,
|
&Rc<WindowAction>,
|
||||||
&Rc<TabAction>,
|
&Rc<TabAction>,
|
||||||
),
|
),
|
||||||
(position, request, is_pinned, is_selected, is_needs_attention, is_load): (
|
request: Option<&str>,
|
||||||
Position,
|
is_load: bool,
|
||||||
Option<&str>,
|
|
||||||
bool,
|
|
||||||
bool,
|
|
||||||
bool,
|
|
||||||
bool,
|
|
||||||
),
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Init components
|
// Init components
|
||||||
let action = Rc::new(Action::new());
|
let action = Rc::new(Action::new());
|
||||||
|
|
@ -57,13 +55,18 @@ impl Item {
|
||||||
.simple_action_group
|
.simple_action_group
|
||||||
.add_action(&action.history.forward);
|
.add_action(&action.history.forward);
|
||||||
|
|
||||||
|
// Create new `Page` implementation for `TabPage`
|
||||||
let page = Rc::new(Page::build(
|
let page = Rc::new(Page::build(
|
||||||
profile,
|
profile,
|
||||||
(browser_action, window_action, tab_action, &action),
|
(browser_action, window_action, tab_action, &action),
|
||||||
tab_view,
|
tab_page,
|
||||||
(position, is_pinned, is_selected, is_needs_attention),
|
|
||||||
));
|
));
|
||||||
|
|
||||||
|
target_child.append(&page.navigation.g_box);
|
||||||
|
target_child.append(&page.content.g_box);
|
||||||
|
target_child.append(&page.search.g_box);
|
||||||
|
target_child.append(&page.input.clamp);
|
||||||
|
|
||||||
// Update tab loading indicator
|
// Update tab loading indicator
|
||||||
let client = Rc::new(Client::init(profile, &page));
|
let client = Rc::new(Client::init(profile, &page));
|
||||||
|
|
||||||
|
|
@ -112,11 +115,12 @@ impl Item {
|
||||||
client.handle(text, true);
|
client.handle(text, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Done
|
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
page,
|
page,
|
||||||
action,
|
action,
|
||||||
|
tab_page: tab_page.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,76 +147,22 @@ impl Item {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method does not contain Self context,
|
|
||||||
// because child items creating in the runtime (by parent component)
|
|
||||||
pub fn restore(
|
|
||||||
tab_view: &TabView,
|
|
||||||
transaction: &Transaction,
|
|
||||||
app_browser_window_tab_id: i64,
|
|
||||||
profile: &Rc<Profile>,
|
|
||||||
// Actions
|
|
||||||
(browser_action, window_action, item_action): (
|
|
||||||
&Rc<BrowserAction>,
|
|
||||||
&Rc<WindowAction>,
|
|
||||||
&Rc<super::Action>,
|
|
||||||
),
|
|
||||||
) -> Result<Vec<Rc<Item>>, String> {
|
|
||||||
let mut items = Vec::new();
|
|
||||||
|
|
||||||
match database::select(transaction, app_browser_window_tab_id) {
|
|
||||||
Ok(records) => {
|
|
||||||
for record in records {
|
|
||||||
// Construct new item object
|
|
||||||
let item = Rc::new(Item::build(
|
|
||||||
tab_view,
|
|
||||||
profile,
|
|
||||||
// Actions
|
|
||||||
(browser_action, window_action, item_action),
|
|
||||||
// Options tuple
|
|
||||||
(
|
|
||||||
Position::End,
|
|
||||||
None,
|
|
||||||
record.is_pinned,
|
|
||||||
record.is_selected,
|
|
||||||
record.is_needs_attention,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Delegate restore action to the item childs
|
|
||||||
item.page.restore(transaction, record.id)?;
|
|
||||||
|
|
||||||
// Result
|
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save(
|
pub fn save(
|
||||||
&self,
|
&self,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
app_browser_window_tab_id: i64,
|
app_browser_window_tab_id: i64,
|
||||||
page_position: i32,
|
page_position: i32,
|
||||||
is_pinned: bool,
|
|
||||||
is_selected: bool,
|
|
||||||
is_needs_attention: bool,
|
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
match database::insert(
|
match database::insert(
|
||||||
transaction,
|
transaction,
|
||||||
app_browser_window_tab_id,
|
app_browser_window_tab_id,
|
||||||
page_position,
|
page_position,
|
||||||
is_pinned,
|
self.tab_page.is_pinned(),
|
||||||
is_selected,
|
self.tab_page.is_selected(),
|
||||||
is_needs_attention,
|
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let id = database::last_insert_id(transaction);
|
|
||||||
|
|
||||||
// Delegate save action to childs
|
// Delegate save action to childs
|
||||||
|
let id = database::last_insert_id(transaction);
|
||||||
self.page.save(transaction, id)?;
|
self.page.save(transaction, id)?;
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
|
|
@ -235,3 +185,15 @@ pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||||
// Success
|
// Success
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This feature restore require parental implementation
|
||||||
|
// * see `super::Tab::restore()`
|
||||||
|
pub fn restore(
|
||||||
|
transaction: &Transaction,
|
||||||
|
app_browser_window_tab_id: i64,
|
||||||
|
) -> Result<Vec<database::Table>, String> {
|
||||||
|
match database::select(transaction, app_browser_window_tab_id) {
|
||||||
|
Ok(records) => Ok(records),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,19 @@ pub struct Table {
|
||||||
// pub app_browser_window_tab_id: i64, not in use
|
// pub app_browser_window_tab_id: i64, not in use
|
||||||
pub is_pinned: bool,
|
pub is_pinned: bool,
|
||||||
pub is_selected: bool,
|
pub is_selected: bool,
|
||||||
pub is_needs_attention: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"CREATE TABLE IF NOT EXISTS `app_browser_window_tab_item`
|
"CREATE TABLE IF NOT EXISTS `app_browser_window_tab_item`
|
||||||
(
|
(
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
`app_browser_window_tab_id` INTEGER NOT NULL,
|
`app_browser_window_tab_id` INTEGER NOT NULL,
|
||||||
`page_position` INTEGER NOT NULL,
|
`page_position` INTEGER NOT NULL,
|
||||||
`is_pinned` INTEGER NOT NULL,
|
`is_pinned` INTEGER NOT NULL,
|
||||||
`is_selected` INTEGER NOT NULL,
|
`is_selected` INTEGER NOT NULL,
|
||||||
`is_needs_attention` INTEGER NOT NULL,
|
|
||||||
|
|
||||||
FOREIGN KEY (`app_browser_window_tab_id`) REFERENCES `app_browser_window_tab`(`id`)
|
FOREIGN KEY (`app_browser_window_tab_id`) REFERENCES `app_browser_window_tab` (`id`)
|
||||||
)",
|
)",
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
@ -31,22 +29,19 @@ pub fn insert(
|
||||||
page_position: i32,
|
page_position: i32,
|
||||||
is_pinned: bool,
|
is_pinned: bool,
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
is_needs_attention: bool,
|
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"INSERT INTO `app_browser_window_tab_item` (
|
"INSERT INTO `app_browser_window_tab_item` (
|
||||||
`app_browser_window_tab_id`,
|
`app_browser_window_tab_id`,
|
||||||
`page_position`,
|
`page_position`,
|
||||||
`is_pinned`,
|
`is_pinned`,
|
||||||
`is_selected`,
|
`is_selected`
|
||||||
`is_needs_attention`
|
) VALUES (?, ?, ?, ?)",
|
||||||
) VALUES (?, ?, ?, ?, ?)",
|
|
||||||
[
|
[
|
||||||
app_browser_window_tab_id,
|
app_browser_window_tab_id,
|
||||||
page_position as i64,
|
page_position as i64,
|
||||||
is_pinned as i64,
|
is_pinned as i64,
|
||||||
is_selected as i64,
|
is_selected as i64,
|
||||||
is_needs_attention as i64,
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -56,8 +51,7 @@ pub fn select(tx: &Transaction, app_browser_window_tab_id: i64) -> Result<Vec<Ta
|
||||||
"SELECT `id`,
|
"SELECT `id`,
|
||||||
`app_browser_window_tab_id`,
|
`app_browser_window_tab_id`,
|
||||||
`is_pinned`,
|
`is_pinned`,
|
||||||
`is_selected`,
|
`is_selected`
|
||||||
`is_needs_attention`
|
|
||||||
FROM `app_browser_window_tab_item`
|
FROM `app_browser_window_tab_item`
|
||||||
WHERE `app_browser_window_tab_id` = ?
|
WHERE `app_browser_window_tab_id` = ?
|
||||||
ORDER BY `page_position` ASC", // just order by, no store in struct wanted
|
ORDER BY `page_position` ASC", // just order by, no store in struct wanted
|
||||||
|
|
@ -69,7 +63,6 @@ pub fn select(tx: &Transaction, app_browser_window_tab_id: i64) -> Result<Vec<Ta
|
||||||
// app_browser_window_tab_id: row.get(1)?, not in use
|
// app_browser_window_tab_id: row.get(1)?, not in use
|
||||||
is_pinned: row.get(2)?,
|
is_pinned: row.get(2)?,
|
||||||
is_selected: row.get(3)?,
|
is_selected: row.get(3)?,
|
||||||
is_needs_attention: row.get(4)?,
|
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,13 @@ mod input;
|
||||||
mod navigation;
|
mod navigation;
|
||||||
mod search;
|
mod search;
|
||||||
|
|
||||||
use super::{Action as ItemAction, BrowserAction, Position, Profile, TabAction, WindowAction};
|
use super::{Action as ItemAction, BrowserAction, Profile, TabAction, WindowAction};
|
||||||
use adw::{TabPage, TabView};
|
use adw::TabPage;
|
||||||
use content::Content;
|
use content::Content;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use gtk::{prelude::BoxExt, Box, Orientation};
|
|
||||||
use input::Input;
|
use input::Input;
|
||||||
use navigation::Navigation;
|
use navigation::Navigation;
|
||||||
use search::Search;
|
use search::Search;
|
||||||
use sourceview::prelude::IsA;
|
|
||||||
use sqlite::Transaction;
|
use sqlite::Transaction;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
@ -29,7 +27,12 @@ pub struct Page {
|
||||||
pub input: Rc<Input>,
|
pub input: Rc<Input>,
|
||||||
pub navigation: Rc<Navigation>,
|
pub navigation: Rc<Navigation>,
|
||||||
// System
|
// System
|
||||||
pub tab_page: TabPage,
|
/// Reference to [TabPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabPage.html)
|
||||||
|
/// wanted to update title, loading status and other features related with page.
|
||||||
|
/// * this member sensitively dependent of parental HashMap index,\
|
||||||
|
/// as connection drivers interact with `Page` API,\
|
||||||
|
/// let's keep it private to isolate direct access and prevent their implementation errors
|
||||||
|
tab_page: TabPage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
|
|
@ -43,8 +46,7 @@ impl Page {
|
||||||
&Rc<TabAction>,
|
&Rc<TabAction>,
|
||||||
&Rc<ItemAction>,
|
&Rc<ItemAction>,
|
||||||
),
|
),
|
||||||
tab_view: &TabView,
|
tab_page: &TabPage,
|
||||||
(position, is_pinned, is_selected, is_needs_attention): (Position, bool, bool, bool),
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Init components
|
// Init components
|
||||||
let content = Rc::new(Content::build((window_action, tab_action, item_action)));
|
let content = Rc::new(Content::build((window_action, tab_action, item_action)));
|
||||||
|
|
@ -55,33 +57,6 @@ impl Page {
|
||||||
));
|
));
|
||||||
let input = Rc::new(Input::new());
|
let input = Rc::new(Input::new());
|
||||||
|
|
||||||
// Init main widget
|
|
||||||
let g_box = Box::builder().orientation(Orientation::Vertical).build();
|
|
||||||
|
|
||||||
g_box.append(&navigation.g_box);
|
|
||||||
g_box.append(&content.g_box);
|
|
||||||
g_box.append(&search.g_box);
|
|
||||||
g_box.append(&input.clamp);
|
|
||||||
|
|
||||||
// Generate `TabPage` by append widget into given `TabView`
|
|
||||||
let tab_page = match position {
|
|
||||||
Position::After => match tab_view.selected_page() {
|
|
||||||
Some(page) => add(tab_view, &g_box, tab_view.page_position(&page) + 1),
|
|
||||||
None => tab_view.append(&g_box),
|
|
||||||
},
|
|
||||||
Position::End => tab_view.append(&g_box),
|
|
||||||
Position::Number(value) => add(tab_view, &g_box, value),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setup
|
|
||||||
tab_page.set_needs_attention(is_needs_attention);
|
|
||||||
tab_page.set_title("New page");
|
|
||||||
|
|
||||||
tab_view.set_page_pinned(&tab_page, is_pinned);
|
|
||||||
if is_selected {
|
|
||||||
tab_view.set_selected_page(&tab_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
Self {
|
Self {
|
||||||
profile: profile.clone(),
|
profile: profile.clone(),
|
||||||
|
|
@ -157,15 +132,14 @@ impl Page {
|
||||||
match database::select(transaction, app_browser_window_tab_item_id) {
|
match database::select(transaction, app_browser_window_tab_item_id) {
|
||||||
Ok(records) => {
|
Ok(records) => {
|
||||||
for record in records {
|
for record in records {
|
||||||
// Restore main widget
|
// Restore `Self`
|
||||||
if let Some(title) = record.title {
|
if let Some(title) = record.title {
|
||||||
self.set_title(title.as_str());
|
self.set_title(title.as_str());
|
||||||
}
|
}
|
||||||
// Restore self by last record
|
self.set_needs_attention(record.is_needs_attention);
|
||||||
// Delegate restore action to the item childs
|
// Restore child components
|
||||||
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
|
|
||||||
if let Some(uri) = self.navigation.uri() {
|
if let Some(uri) = self.navigation.uri() {
|
||||||
self.profile.history.memory.request.set(uri);
|
self.profile.history.memory.request.set(uri);
|
||||||
}
|
}
|
||||||
|
|
@ -184,10 +158,10 @@ impl Page {
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// Keep value in memory until operation complete
|
// Keep value in memory until operation complete
|
||||||
let title = self.tab_page.title();
|
let title = self.tab_page.title();
|
||||||
|
|
||||||
match database::insert(
|
match database::insert(
|
||||||
transaction,
|
transaction,
|
||||||
app_browser_window_tab_item_id,
|
app_browser_window_tab_item_id,
|
||||||
|
self.tab_page.needs_attention(),
|
||||||
match title.is_empty() {
|
match title.is_empty() {
|
||||||
true => None,
|
true => None,
|
||||||
false => Some(title.as_str()),
|
false => Some(title.as_str()),
|
||||||
|
|
@ -201,7 +175,6 @@ impl Page {
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +183,11 @@ impl Page {
|
||||||
/// Set title for `Self`
|
/// Set title for `Self`
|
||||||
/// * this method allows to keep `tab_page` isolated from driver implementation
|
/// * this method allows to keep `tab_page` isolated from driver implementation
|
||||||
pub fn set_title(&self, title: &str) {
|
pub fn set_title(&self, title: &str) {
|
||||||
self.tab_page.set_title(title);
|
self.tab_page.set_title(title)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_needs_attention(&self, is_needs_attention: bool) {
|
||||||
|
self.tab_page.set_needs_attention(is_needs_attention)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_progress(&self, progress_fraction: f64) {
|
pub fn set_progress(&self, progress_fraction: f64) {
|
||||||
|
|
@ -233,17 +210,3 @@ pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||||
// Success
|
// Success
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new [TabPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabPage.html)
|
|
||||||
/// in [TabView](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabView.html) at given position
|
|
||||||
///
|
|
||||||
/// * if given `position` match pinned tab, GTK will panic with notice:
|
|
||||||
/// adw_tab_view_insert: assertion 'position >= self->n_pinned_pages'\
|
|
||||||
/// as the solution, prepend new page after pinned tabs in this case
|
|
||||||
fn add(tab_view: &TabView, child: &impl IsA<gtk::Widget>, position: i32) -> TabPage {
|
|
||||||
if position > tab_view.n_pinned_pages() {
|
|
||||||
tab_view.insert(child, position)
|
|
||||||
} else {
|
|
||||||
tab_view.prepend(child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use sqlite::{Error, Transaction};
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
// pub app_browser_window_tab_item_id: i64, not in use,
|
// pub app_browser_window_tab_item_id: i64, not in use,
|
||||||
|
pub is_needs_attention: bool,
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -10,11 +11,12 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"CREATE TABLE IF NOT EXISTS `app_browser_window_tab_item_page`
|
"CREATE TABLE IF NOT EXISTS `app_browser_window_tab_item_page`
|
||||||
(
|
(
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
`app_browser_window_tab_item_id` INTEGER NOT NULL,
|
`app_browser_window_tab_item_id` INTEGER NOT NULL,
|
||||||
`title` VARCHAR(1024),
|
`is_needs_attention` INTEGER NOT NULL,
|
||||||
|
`title` TEXT,
|
||||||
|
|
||||||
FOREIGN KEY (`app_browser_window_tab_item_id`) REFERENCES `app_browser_window_tab_item`(`id`)
|
FOREIGN KEY (`app_browser_window_tab_item_id`) REFERENCES `app_browser_window_tab_item` (`id`)
|
||||||
)",
|
)",
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
@ -23,14 +25,16 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||||
pub fn insert(
|
pub fn insert(
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
app_browser_window_tab_item_id: i64,
|
app_browser_window_tab_item_id: i64,
|
||||||
|
is_needs_attention: bool,
|
||||||
title: Option<&str>,
|
title: Option<&str>,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"INSERT INTO `app_browser_window_tab_item_page` (
|
"INSERT INTO `app_browser_window_tab_item_page` (
|
||||||
`app_browser_window_tab_item_id`,
|
`app_browser_window_tab_item_id`,
|
||||||
|
`is_needs_attention`,
|
||||||
`title`
|
`title`
|
||||||
) VALUES (?, ?)",
|
) VALUES (?, ?, ?)",
|
||||||
(app_browser_window_tab_item_id, title),
|
(app_browser_window_tab_item_id, is_needs_attention, title),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,6 +42,7 @@ pub fn select(tx: &Transaction, app_browser_window_tab_item_id: i64) -> Result<V
|
||||||
let mut stmt = tx.prepare(
|
let mut stmt = tx.prepare(
|
||||||
"SELECT `id`,
|
"SELECT `id`,
|
||||||
`app_browser_window_tab_item_id`,
|
`app_browser_window_tab_item_id`,
|
||||||
|
`is_needs_attention`,
|
||||||
`title`
|
`title`
|
||||||
FROM `app_browser_window_tab_item_page`
|
FROM `app_browser_window_tab_item_page`
|
||||||
WHERE `app_browser_window_tab_item_id` = ?",
|
WHERE `app_browser_window_tab_item_id` = ?",
|
||||||
|
|
@ -47,7 +52,8 @@ pub fn select(tx: &Transaction, app_browser_window_tab_item_id: i64) -> Result<V
|
||||||
Ok(Table {
|
Ok(Table {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
// app_browser_window_tab_item_id: row.get(1)?, not in use
|
// app_browser_window_tab_item_id: row.get(1)?, not in use
|
||||||
title: row.get(2)?,
|
is_needs_attention: row.get(2)?,
|
||||||
|
title: row.get(3)?,
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue