move is_needs_attention state to page, reorganize TabView access levels

This commit is contained in:
yggverse 2025-01-30 22:40:47 +02:00
parent 8356c432c1
commit 25db274d2e
5 changed files with 158 additions and 191 deletions

View file

@ -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,
)
}

View file

@ -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()),
}
}

View file

@ -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)?,
}) })
})?; })?;

View file

@ -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)
}
}

View file

@ -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)?,
}) })
})?; })?;