mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-04-01 09:05:27 +00:00
begin request entry refactory
This commit is contained in:
parent
5255708be3
commit
e7bd5bbdc6
24 changed files with 351 additions and 849 deletions
|
|
@ -6,7 +6,7 @@ mod reload;
|
|||
mod request;
|
||||
mod widget;
|
||||
|
||||
use super::{BrowserAction, ItemAction, Profile, TabAction, WindowAction};
|
||||
use super::{ItemAction, Profile, TabAction, WindowAction};
|
||||
use bookmark::Bookmark;
|
||||
use gtk::{Box, Button};
|
||||
use history::History;
|
||||
|
|
@ -29,8 +29,7 @@ pub struct Navigation {
|
|||
impl Navigation {
|
||||
pub fn build(
|
||||
profile: &Rc<Profile>,
|
||||
(browser_action, window_action, tab_action, item_action): (
|
||||
&Rc<BrowserAction>,
|
||||
(window_action, tab_action, item_action): (
|
||||
&Rc<WindowAction>,
|
||||
&Rc<TabAction>,
|
||||
&Rc<ItemAction>,
|
||||
|
|
@ -39,7 +38,7 @@ impl Navigation {
|
|||
// init children components
|
||||
|
||||
let history = Box::history((window_action, tab_action, item_action));
|
||||
let request = Rc::new(Request::build((browser_action, item_action)));
|
||||
let request = Rc::new(Request::build(item_action, profile));
|
||||
let reload = Button::reload((window_action, tab_action, item_action), &request);
|
||||
let home = Button::home((window_action, tab_action, item_action), &request);
|
||||
let bookmark = Button::bookmark(window_action);
|
||||
|
|
@ -49,7 +48,7 @@ impl Navigation {
|
|||
&home,
|
||||
&history,
|
||||
&reload,
|
||||
&request.widget.entry, // @TODO
|
||||
&request.entry, // @TODO
|
||||
&bookmark,
|
||||
));
|
||||
|
||||
|
|
@ -73,8 +72,6 @@ impl Navigation {
|
|||
// update children components
|
||||
self.bookmark
|
||||
.update(self.profile.bookmark.get(&request).is_ok());
|
||||
self.request
|
||||
.update(self.profile.identity.get(&request).is_some());
|
||||
}
|
||||
|
||||
pub fn clean(
|
||||
|
|
|
|||
|
|
@ -1,38 +1,132 @@
|
|||
mod database;
|
||||
mod test;
|
||||
mod widget;
|
||||
mod primary_icon;
|
||||
|
||||
use widget::Widget;
|
||||
use primary_icon::PrimaryIcon;
|
||||
|
||||
use crate::app::browser::{window::tab::item::Action as ItemAction, Action as BrowserAction};
|
||||
use super::{ItemAction, Profile};
|
||||
use gtk::{
|
||||
glib::{gformat, GString, Uri, UriFlags},
|
||||
prelude::EditableExt,
|
||||
prelude::{EditableExt, EntryExt, WidgetExt},
|
||||
Entry, EntryIconPosition, StateFlags,
|
||||
};
|
||||
use sqlite::Transaction;
|
||||
use std::rc::Rc;
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
const PLACEHOLDER_TEXT: &str = "URL or search term...";
|
||||
|
||||
// Main
|
||||
pub struct Request {
|
||||
pub widget: Rc<Widget>,
|
||||
pub entry: Entry,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
// Constructors
|
||||
|
||||
/// Build new `Self`
|
||||
pub fn build((browser_action, item_action): (&Rc<BrowserAction>, &Rc<ItemAction>)) -> Self {
|
||||
Self {
|
||||
widget: Rc::new(Widget::build((browser_action, item_action))),
|
||||
}
|
||||
pub fn build(item_action: &Rc<ItemAction>, profile: &Rc<Profile>) -> Self {
|
||||
// Init main widget
|
||||
let entry = Entry::builder()
|
||||
.placeholder_text(PLACEHOLDER_TEXT)
|
||||
.secondary_icon_tooltip_text("Go to the location")
|
||||
.hexpand(true)
|
||||
.build();
|
||||
|
||||
// Connect events
|
||||
entry.connect_icon_release({
|
||||
let item_action = item_action.clone();
|
||||
move |this, position| match position {
|
||||
EntryIconPosition::Primary => item_action.ident.activate(), // @TODO PrimaryIcon impl
|
||||
EntryIconPosition::Secondary => item_action.load.activate(Some(&this.text()), true),
|
||||
_ => todo!(), // unexpected
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_has_focus_notify(|this| {
|
||||
if this.focus_child().is_some_and(|text| text.has_focus()) {
|
||||
this.set_secondary_icon_name(Some("pan-end-symbolic"));
|
||||
} else {
|
||||
this.set_secondary_icon_name(None);
|
||||
this.select_region(0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_changed({
|
||||
let profile = profile.clone();
|
||||
let item_action = item_action.clone();
|
||||
move |this| {
|
||||
// Update actions
|
||||
item_action.reload.set_enabled(!this.text().is_empty());
|
||||
item_action
|
||||
.home
|
||||
.set_enabled(home(uri(&this.text())).is_some());
|
||||
|
||||
// Update primary icon
|
||||
this.first_child().unwrap().remove_css_class("success"); // @TODO handle
|
||||
|
||||
this.set_primary_icon_activatable(false);
|
||||
this.set_primary_icon_sensitive(false);
|
||||
|
||||
match primary_icon::from(&this.text()) {
|
||||
PrimaryIcon::Download { name, tooltip } => {
|
||||
this.set_primary_icon_name(Some(name));
|
||||
this.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
PrimaryIcon::Gemini { name, tooltip }
|
||||
| PrimaryIcon::Titan { name, tooltip } => {
|
||||
this.set_primary_icon_activatable(true);
|
||||
this.set_primary_icon_sensitive(true);
|
||||
this.set_primary_icon_name(Some(name));
|
||||
if profile.identity.get(&strip_prefix(this.text())).is_some() {
|
||||
this.first_child().unwrap().add_css_class("success"); // @TODO handle
|
||||
this.set_primary_icon_tooltip_text(Some(tooltip.1));
|
||||
} else {
|
||||
this.set_primary_icon_tooltip_text(Some(tooltip.0));
|
||||
}
|
||||
}
|
||||
PrimaryIcon::Search { name, tooltip } => {
|
||||
this.set_primary_icon_name(Some(name));
|
||||
this.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
PrimaryIcon::Source { name, tooltip } => {
|
||||
this.set_primary_icon_name(Some(name));
|
||||
this.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_activate({
|
||||
let item_action = item_action.clone();
|
||||
move |entry| {
|
||||
item_action.load.activate(Some(&entry.text()), true);
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_state_flags_changed({
|
||||
// Define last focus state container
|
||||
let has_focus = Cell::new(false);
|
||||
move |entry, state| {
|
||||
// Select entire text on first click (release)
|
||||
// this behavior implemented in most web-browsers,
|
||||
// to simply overwrite current request with new value
|
||||
// Note:
|
||||
// * Custom GestureClick is not an option here, as GTK Entry has default controller
|
||||
// * This is experimental feature does not follow native GTK behavior @TODO make optional
|
||||
if !has_focus.take()
|
||||
&& state.contains(StateFlags::ACTIVE | StateFlags::FOCUS_WITHIN)
|
||||
&& entry.selection_bounds().is_none()
|
||||
{
|
||||
entry.select_region(0, entry.text_length().into());
|
||||
}
|
||||
// Update last focus state
|
||||
has_focus.replace(state.contains(StateFlags::FOCUS_WITHIN));
|
||||
}
|
||||
});
|
||||
|
||||
// Return activated `Self`
|
||||
Self { entry }
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
pub fn update(&self, is_identity_active: bool) {
|
||||
self.widget.update(is_identity_active);
|
||||
}
|
||||
|
||||
pub fn clean(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
|
|
@ -44,7 +138,7 @@ impl Request {
|
|||
match database::delete(transaction, &record.id) {
|
||||
Ok(_) => {
|
||||
// Delegate clean action to the item childs
|
||||
self.widget.clean(transaction, &record.id)?;
|
||||
// nothing yet..
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
|
|
@ -64,8 +158,12 @@ impl Request {
|
|||
match database::select(transaction, app_browser_window_tab_item_page_navigation_id) {
|
||||
Ok(records) => {
|
||||
for record in records {
|
||||
if let Some(text) = record.text {
|
||||
self.entry.set_text(&text);
|
||||
}
|
||||
|
||||
// Delegate restore action to the item childs
|
||||
self.widget.restore(transaction, &record.id)?;
|
||||
// nothing yet..
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
|
|
@ -79,12 +177,22 @@ impl Request {
|
|||
transaction: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_id: &i64,
|
||||
) -> Result<(), String> {
|
||||
match database::insert(transaction, app_browser_window_tab_item_page_navigation_id) {
|
||||
// Keep value in memory until operation complete
|
||||
let text = self.entry.text();
|
||||
|
||||
match database::insert(
|
||||
transaction,
|
||||
app_browser_window_tab_item_page_navigation_id,
|
||||
match text.is_empty() {
|
||||
true => None,
|
||||
false => Some(text.as_str()),
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
let id = database::last_insert_id(transaction);
|
||||
// let id = database::last_insert_id(transaction);
|
||||
|
||||
// Delegate save action to childs
|
||||
self.widget.save(transaction, &id)?;
|
||||
// nothing yet..
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
|
|
@ -95,48 +203,19 @@ impl Request {
|
|||
// Setters
|
||||
|
||||
pub fn to_download(&self) {
|
||||
self.widget.entry.set_text(&self.download());
|
||||
self.entry.set_text(&self.download());
|
||||
}
|
||||
|
||||
pub fn to_source(&self) {
|
||||
self.widget.entry.set_text(&self.source());
|
||||
self.entry.set_text(&self.source());
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
/// Try get current request value as [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
||||
/// * `strip_prefix` on parse
|
||||
pub fn uri(&self) -> Option<Uri> {
|
||||
match Uri::parse(&strip_prefix(self.widget.entry.text()), UriFlags::NONE) {
|
||||
Ok(uri) => Some(uri),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get current request value without system prefix
|
||||
/// * the `prefix` is not `scheme`
|
||||
pub fn strip_prefix(&self) -> GString {
|
||||
strip_prefix(self.widget.entry.text())
|
||||
}
|
||||
|
||||
/// Parse home [Uri](https://docs.gtk.org/glib/struct.Uri.html) of `Self`
|
||||
pub fn home(&self) -> Option<Uri> {
|
||||
self.uri().map(|uri| {
|
||||
Uri::build(
|
||||
UriFlags::NONE,
|
||||
&if uri.scheme() == "titan" {
|
||||
GString::from("gemini")
|
||||
} else {
|
||||
uri.scheme()
|
||||
},
|
||||
uri.userinfo().as_deref(),
|
||||
uri.host().as_deref(),
|
||||
uri.port(),
|
||||
"/",
|
||||
None,
|
||||
None,
|
||||
)
|
||||
})
|
||||
strip_prefix(self.entry.text())
|
||||
}
|
||||
|
||||
/// Get request value in `download:` format
|
||||
|
|
@ -148,13 +227,37 @@ impl Request {
|
|||
pub fn source(&self) -> GString {
|
||||
gformat!("source:{}", self.strip_prefix())
|
||||
}
|
||||
|
||||
/// Try get current request value as [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
||||
/// * `strip_prefix` on parse
|
||||
pub fn uri(&self) -> Option<Uri> {
|
||||
uri(&strip_prefix(self.entry.text()))
|
||||
}
|
||||
|
||||
/// Try build home [Uri](https://docs.gtk.org/glib/struct.Uri.html) for `Self`
|
||||
pub fn home(&self) -> Option<Uri> {
|
||||
home(self.uri())
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
||||
pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||
// Migrate self components
|
||||
if let Err(e) = database::init(tx) {
|
||||
return Err(e.to_string());
|
||||
}
|
||||
|
||||
// Delegate migration to childs
|
||||
// nothing yet..
|
||||
|
||||
// Success
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Strip system prefix from request string
|
||||
/// * the `prefix` is not `scheme`
|
||||
pub fn strip_prefix(mut request: GString) -> GString {
|
||||
fn strip_prefix(mut request: GString) -> GString {
|
||||
if let Some(postfix) = request.strip_prefix("source:") {
|
||||
request = postfix.into()
|
||||
};
|
||||
|
|
@ -166,15 +269,29 @@ pub fn strip_prefix(mut request: GString) -> GString {
|
|||
request
|
||||
} // @TODO move prefix features to page client
|
||||
|
||||
pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||
// Migrate self components
|
||||
if let Err(e) = database::init(tx) {
|
||||
return Err(e.to_string());
|
||||
fn uri(value: &str) -> Option<Uri> {
|
||||
match Uri::parse(value, UriFlags::NONE) {
|
||||
Ok(uri) => Some(uri),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
// Delegate migration to childs
|
||||
widget::migrate(tx)?;
|
||||
|
||||
// Success
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse home [Uri](https://docs.gtk.org/glib/struct.Uri.html) for `subject`
|
||||
fn home(subject: Option<Uri>) -> Option<Uri> {
|
||||
subject.map(|uri| {
|
||||
Uri::build(
|
||||
UriFlags::NONE,
|
||||
&if uri.scheme() == "titan" {
|
||||
GString::from("gemini")
|
||||
} else {
|
||||
uri.scheme()
|
||||
},
|
||||
uri.userinfo().as_deref(),
|
||||
uri.host().as_deref(),
|
||||
uri.port(),
|
||||
"/",
|
||||
None,
|
||||
None,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use sqlite::{Error, Transaction};
|
|||
pub struct Table {
|
||||
pub id: i64,
|
||||
// pub app_browser_window_tab_item_page_navigation_id: i64, not in use
|
||||
pub text: Option<String>, // can be stored as NULL
|
||||
}
|
||||
|
||||
pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||
|
|
@ -11,6 +12,7 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
|||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`app_browser_window_tab_item_page_navigation_id` INTEGER NOT NULL,
|
||||
`text` VARCHAR(1024),
|
||||
|
||||
FOREIGN KEY (`app_browser_window_tab_item_page_navigation_id`) REFERENCES `app_browser_window_tab_item_page_navigation`(`id`)
|
||||
)",
|
||||
|
|
@ -21,12 +23,14 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
|||
pub fn insert(
|
||||
tx: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_id: &i64,
|
||||
text: Option<&str>,
|
||||
) -> Result<usize, Error> {
|
||||
tx.execute(
|
||||
"INSERT INTO `app_browser_window_tab_item_page_navigation_request` (
|
||||
`app_browser_window_tab_item_page_navigation_id`
|
||||
) VALUES (?)",
|
||||
[app_browser_window_tab_item_page_navigation_id],
|
||||
`app_browser_window_tab_item_page_navigation_id`,
|
||||
`text`
|
||||
) VALUES (?, ?)",
|
||||
(app_browser_window_tab_item_page_navigation_id, text),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +40,8 @@ pub fn select(
|
|||
) -> Result<Vec<Table>, Error> {
|
||||
let mut stmt = tx.prepare(
|
||||
"SELECT `id`,
|
||||
`app_browser_window_tab_item_page_navigation_id`
|
||||
`app_browser_window_tab_item_page_navigation_id`,
|
||||
`text`
|
||||
FROM `app_browser_window_tab_item_page_navigation_request`
|
||||
WHERE `app_browser_window_tab_item_page_navigation_id` = ?",
|
||||
)?;
|
||||
|
|
@ -45,6 +50,7 @@ pub fn select(
|
|||
Ok(Table {
|
||||
id: row.get(0)?,
|
||||
// app_browser_window_tab_item_page_navigation_id: row.get(1)?, not in use
|
||||
text: row.get(2)?,
|
||||
})
|
||||
})?;
|
||||
|
||||
|
|
@ -65,6 +71,7 @@ pub fn delete(tx: &Transaction, id: &i64) -> Result<usize, Error> {
|
|||
)
|
||||
}
|
||||
|
||||
/* not in use
|
||||
pub fn last_insert_id(tx: &Transaction) -> i64 {
|
||||
tx.last_insert_rowid()
|
||||
}
|
||||
} */
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
#[test]
|
||||
fn strip_prefix() {
|
||||
assert_eq!(super::strip_prefix("source:gemini".into()), "gemini");
|
||||
assert_eq!(super::strip_prefix("download:gemini".into()), "gemini");
|
||||
}
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
mod database;
|
||||
mod primary_icon;
|
||||
|
||||
use primary_icon::PrimaryIcon;
|
||||
|
||||
use super::{BrowserAction, ItemAction};
|
||||
use gtk::{
|
||||
glib::{timeout_add_local, ControlFlow, SourceId},
|
||||
prelude::{EditableExt, EntryExt, WidgetExt},
|
||||
Entry, EntryIconPosition, StateFlags,
|
||||
};
|
||||
use sqlite::Transaction;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
const PLACEHOLDER_TEXT: &str = "URL or search term...";
|
||||
|
||||
// Progress bar animation setup
|
||||
const PROGRESS_ANIMATION_STEP: f64 = 0.05;
|
||||
const PROGRESS_ANIMATION_TIME: u64 = 20; //ms
|
||||
|
||||
struct Progress {
|
||||
fraction: RefCell<f64>,
|
||||
source_id: RefCell<Option<SourceId>>,
|
||||
}
|
||||
|
||||
pub struct Widget {
|
||||
pub entry: Entry,
|
||||
progress: Rc<Progress>,
|
||||
}
|
||||
|
||||
impl Widget {
|
||||
// Constructors
|
||||
|
||||
/// Build new `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),
|
||||
source_id: RefCell::new(None),
|
||||
});
|
||||
|
||||
// Init main widget
|
||||
let entry = Entry::builder()
|
||||
.placeholder_text(PLACEHOLDER_TEXT)
|
||||
.secondary_icon_tooltip_text("Go to the location")
|
||||
.hexpand(true)
|
||||
.build();
|
||||
|
||||
// Connect events
|
||||
entry.connect_icon_release({
|
||||
let item_action = item_action.clone();
|
||||
move |this, position| match position {
|
||||
EntryIconPosition::Primary => item_action.ident.activate(), // @TODO PrimaryIcon impl
|
||||
EntryIconPosition::Secondary => item_action.load.activate(Some(&this.text()), true),
|
||||
_ => todo!(), // unexpected
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_has_focus_notify(|this| {
|
||||
if this.focus_child().is_some_and(|text| text.has_focus()) {
|
||||
this.set_secondary_icon_name(Some("pan-end-symbolic"));
|
||||
} else {
|
||||
this.set_secondary_icon_name(None);
|
||||
this.select_region(0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_changed({
|
||||
let browser_action = browser_action.clone();
|
||||
move |_| {
|
||||
browser_action.update.activate(None);
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_activate({
|
||||
let item_action = item_action.clone();
|
||||
move |entry| {
|
||||
item_action.load.activate(Some(&entry.text()), true);
|
||||
}
|
||||
});
|
||||
|
||||
entry.connect_state_flags_changed({
|
||||
// Define last focus state container
|
||||
let has_focus = Cell::new(false);
|
||||
move |entry, state| {
|
||||
// Select entire text on first click (release)
|
||||
// this behavior implemented in most web-browsers,
|
||||
// to simply overwrite current request with new value
|
||||
// Note:
|
||||
// * Custom GestureClick is not an option here, as GTK Entry has default controller
|
||||
// * This is experimental feature does not follow native GTK behavior @TODO make optional
|
||||
if !has_focus.take()
|
||||
&& state.contains(StateFlags::ACTIVE | StateFlags::FOCUS_WITHIN)
|
||||
&& entry.selection_bounds().is_none()
|
||||
{
|
||||
entry.select_region(0, entry.text_length().into());
|
||||
}
|
||||
// Update last focus state
|
||||
has_focus.replace(state.contains(StateFlags::FOCUS_WITHIN));
|
||||
}
|
||||
});
|
||||
|
||||
// Return activated `Self`
|
||||
Self { entry, progress }
|
||||
}
|
||||
|
||||
// Actions
|
||||
pub fn clean(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id: &i64,
|
||||
) -> Result<(), String> {
|
||||
match database::select(
|
||||
transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id,
|
||||
) {
|
||||
Ok(records) => {
|
||||
for record in records {
|
||||
match database::delete(transaction, &record.id) {
|
||||
Ok(_) => {
|
||||
// Delegate clean action to the item childs
|
||||
// nothing yet..
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id: &i64,
|
||||
) -> Result<(), String> {
|
||||
match database::select(
|
||||
transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id,
|
||||
) {
|
||||
Ok(records) => {
|
||||
for record in records {
|
||||
if let Some(text) = record.text {
|
||||
self.entry.set_text(&text);
|
||||
}
|
||||
|
||||
// Delegate restore action to the item childs
|
||||
// nothing yet..
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id: &i64,
|
||||
) -> Result<(), String> {
|
||||
// Keep value in memory until operation complete
|
||||
let text = self.entry.text();
|
||||
|
||||
match database::insert(
|
||||
transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id,
|
||||
match text.is_empty() {
|
||||
true => None,
|
||||
false => Some(text.as_str()),
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
// let id = database::last_insert_id(transaction);
|
||||
|
||||
// Delegate save action to childs
|
||||
// nothing yet..
|
||||
}
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update(&self, is_identity_active: bool) {
|
||||
// Update primary icon
|
||||
self.entry
|
||||
.first_child()
|
||||
.unwrap()
|
||||
.remove_css_class("success"); // @TODO handle
|
||||
|
||||
self.entry.set_primary_icon_activatable(false);
|
||||
self.entry.set_primary_icon_sensitive(false);
|
||||
|
||||
match primary_icon::from(&self.entry.text()) {
|
||||
PrimaryIcon::Download { name, tooltip } => {
|
||||
self.entry.set_primary_icon_name(Some(name));
|
||||
self.entry.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
PrimaryIcon::Gemini { name, tooltip } | PrimaryIcon::Titan { name, tooltip } => {
|
||||
self.entry.set_primary_icon_activatable(true);
|
||||
self.entry.set_primary_icon_sensitive(true);
|
||||
self.entry.set_primary_icon_name(Some(name));
|
||||
if is_identity_active {
|
||||
self.entry.first_child().unwrap().add_css_class("success"); // @TODO handle
|
||||
self.entry.set_primary_icon_tooltip_text(Some(tooltip.1));
|
||||
} else {
|
||||
self.entry.set_primary_icon_tooltip_text(Some(tooltip.0));
|
||||
}
|
||||
}
|
||||
PrimaryIcon::Search { name, tooltip } => {
|
||||
self.entry.set_primary_icon_name(Some(name));
|
||||
self.entry.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
PrimaryIcon::Source { name, tooltip } => {
|
||||
self.entry.set_primary_icon_name(Some(name));
|
||||
self.entry.set_primary_icon_tooltip_text(Some(tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress
|
||||
// * @TODO skip update animation for None value
|
||||
let value = self.entry.progress_fraction();
|
||||
|
||||
// Update shared fraction on new value was changed
|
||||
if value != self.progress.fraction.replace(value) {
|
||||
// Start new frame on previous process function completed (`source_id` changed to None)
|
||||
// If previous process still active, we have just updated shared fraction value before, to use it inside the active process
|
||||
if self.progress.source_id.borrow().is_none() {
|
||||
// Start new animation frame iterator, update `source_id`
|
||||
self.progress.source_id.replace(Some(timeout_add_local(
|
||||
Duration::from_millis(PROGRESS_ANIMATION_TIME),
|
||||
{
|
||||
// Clone async pointers dependency
|
||||
let entry = self.entry.clone();
|
||||
let progress = self.progress.clone();
|
||||
|
||||
// Frame
|
||||
move || {
|
||||
// Animate
|
||||
if *progress.fraction.borrow() > entry.progress_fraction() {
|
||||
entry.set_progress_fraction(
|
||||
// Currently, here is no outrange validation, seems that wrapper make this work @TODO
|
||||
entry.progress_fraction() + PROGRESS_ANIMATION_STEP,
|
||||
);
|
||||
return ControlFlow::Continue;
|
||||
}
|
||||
// Deactivate
|
||||
progress.source_id.replace(None);
|
||||
|
||||
// Reset on 100% (to hide progress bar)
|
||||
// or, just await for new value request
|
||||
if entry.progress_fraction() == 1.0 {
|
||||
entry.set_progress_fraction(0.0);
|
||||
}
|
||||
|
||||
// Stop iteration
|
||||
ControlFlow::Break
|
||||
}
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
||||
pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||
// Migrate self components
|
||||
if let Err(e) = database::init(tx) {
|
||||
return Err(e.to_string());
|
||||
}
|
||||
|
||||
// Delegate migration to childs
|
||||
// nothing yet..
|
||||
|
||||
// Success
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
use sqlite::{Error, Transaction};
|
||||
|
||||
pub struct Table {
|
||||
pub id: i64,
|
||||
// pub app_browser_window_tab_item_page_navigation_request_id: i64, not in use
|
||||
pub text: Option<String>, // can be stored as NULL
|
||||
}
|
||||
|
||||
pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||
tx.execute(
|
||||
"CREATE TABLE IF NOT EXISTS `app_browser_window_tab_item_page_navigation_request_widget`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`app_browser_window_tab_item_page_navigation_request_id` INTEGER NOT NULL,
|
||||
`text` VARCHAR(1024),
|
||||
|
||||
FOREIGN KEY (`app_browser_window_tab_item_page_navigation_request_id`) REFERENCES `app_browser_window_tab_item_page_navigation_request`(`id`)
|
||||
)",
|
||||
[],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn insert(
|
||||
tx: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id: &i64,
|
||||
text: Option<&str>,
|
||||
) -> Result<usize, Error> {
|
||||
tx.execute(
|
||||
"INSERT INTO `app_browser_window_tab_item_page_navigation_request_widget` (
|
||||
`app_browser_window_tab_item_page_navigation_request_id`,
|
||||
`text`
|
||||
) VALUES (?, ?)",
|
||||
(app_browser_window_tab_item_page_navigation_request_id, text),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn select(
|
||||
tx: &Transaction,
|
||||
app_browser_window_tab_item_page_navigation_request_id: &i64,
|
||||
) -> Result<Vec<Table>, Error> {
|
||||
let mut stmt = tx.prepare(
|
||||
"SELECT `id`,
|
||||
`app_browser_window_tab_item_page_navigation_request_id`,
|
||||
`text`
|
||||
FROM `app_browser_window_tab_item_page_navigation_request_widget`
|
||||
WHERE `app_browser_window_tab_item_page_navigation_request_id` = ?",
|
||||
)?;
|
||||
|
||||
let result = stmt.query_map(
|
||||
[app_browser_window_tab_item_page_navigation_request_id],
|
||||
|row| {
|
||||
Ok(Table {
|
||||
id: row.get(0)?,
|
||||
// app_browser_window_tab_item_page_navigation_request_id: row.get(1)?, not in use
|
||||
text: row.get(2)?,
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut records = Vec::new();
|
||||
|
||||
for record in result {
|
||||
let table = record?;
|
||||
records.push(table);
|
||||
}
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
|
||||
pub fn delete(tx: &Transaction, id: &i64) -> Result<usize, Error> {
|
||||
tx.execute(
|
||||
"DELETE FROM `app_browser_window_tab_item_page_navigation_request_widget` WHERE `id` = ?",
|
||||
[id],
|
||||
)
|
||||
}
|
||||
|
||||
/* not in use
|
||||
pub fn last_insert_id(tx: &Transaction) -> i64 {
|
||||
tx.last_insert_rowid()
|
||||
} */
|
||||
Loading…
Add table
Add a link
Reference in a new issue