draft profile database implementation, make members public, run initial dialog, rename field from active to is_active

This commit is contained in:
yggverse 2024-11-13 08:03:48 +02:00
parent b0ee52c3f4
commit 4d7b61ef59
4 changed files with 81 additions and 54 deletions

View File

@ -7,7 +7,7 @@ use crate::profile::Profile;
use adw::Application; use adw::Application;
use gtk::{ use gtk::{
glib::ExitCode, glib::ExitCode,
prelude::{ApplicationExt, ApplicationExtManual, GtkApplicationExt, GtkWindowExt}, prelude::{ApplicationExt, ApplicationExtManual, GtkApplicationExt},
}; };
use sqlite::Transaction; use sqlite::Transaction;
use std::rc::Rc; use std::rc::Rc;
@ -41,7 +41,7 @@ impl App {
let profile = profile.clone(); let profile = profile.clone();
move |this| { move |this| {
// Init readable connection // Init readable connection
match profile.database().read() { match profile.database.connection.read() {
Ok(connection) => { Ok(connection) => {
// Create transaction // Create transaction
match connection.unchecked_transaction() { match connection.unchecked_transaction() {
@ -57,9 +57,6 @@ impl App {
todo!("{e}") todo!("{e}")
} }
} }
// Run initial features
browser.init();
} }
Err(e) => todo!("{e}"), Err(e) => todo!("{e}"),
} }
@ -70,11 +67,8 @@ impl App {
Err(e) => todo!("{e}"), Err(e) => todo!("{e}"),
} }
// Assign browser window to this application // Run initial features, show widget
browser.gobject().set_application(Some(this)); browser.init(Some(this)).present();
// Show main widget
browser.gobject().present();
} }
}); });
@ -83,7 +77,7 @@ impl App {
let profile = profile.clone(); let profile = profile.clone();
move |_| { move |_| {
// Init writable connection // Init writable connection
match profile.database().write() { match profile.database.connection.write() {
Ok(mut connection) => { Ok(mut connection) => {
// Create transaction // Create transaction
match connection.transaction() { match connection.transaction() {
@ -240,7 +234,7 @@ impl App {
// Begin database migration @TODO // Begin database migration @TODO
{ {
// Init writable connection // Init writable connection
let mut connection = match self.profile.database().try_write() { let mut connection = match self.profile.database.connection.write() {
Ok(connection) => connection, Ok(connection) => connection,
Err(e) => todo!("{e}"), Err(e) => todo!("{e}"),
}; };

View File

@ -12,11 +12,10 @@ use widget::Widget;
use window::Window; use window::Window;
use crate::profile::Profile; use crate::profile::Profile;
use adw::ApplicationWindow;
use gtk::{ use gtk::{
gio::{Cancellable, File}, gio::{Cancellable, File},
prelude::GtkWindowExt, prelude::{GtkWindowExt, IsA},
FileLauncher, Application, FileLauncher,
}; };
use sqlite::Transaction; use sqlite::Transaction;
use std::rc::Rc; use std::rc::Rc;
@ -76,7 +75,7 @@ impl Browser {
action.profile().connect_activate({ action.profile().connect_activate({
let profile = profile.clone(); let profile = profile.clone();
move || { move || {
FileLauncher::new(Some(&File::for_path(profile.config_path()))).launch( FileLauncher::new(Some(&File::for_path(profile.config_path.as_path()))).launch(
None::<&gtk::Window>, None::<&gtk::Window>,
None::<&Cancellable>, None::<&Cancellable>,
|result| { |result| {
@ -163,12 +162,25 @@ impl Browser {
Ok(()) Ok(())
} }
pub fn init(&self) { pub fn init(&self, application: Option<&impl IsA<Application>>) -> &Self {
// Show welcome dialog on profile not selected yet (e.g. first launch) @TODO // Assign browser window to this application
// Welcome::new(self.profile.clone()).present(Some(self.widget.gobject())); self.widget.gobject().set_application(application); // @TODO
// Init main window // Init main window
self.window.init(); self.window.init();
self
}
pub fn present(&self) -> &Self {
// Show main window
self.widget.gobject().present();
// Show welcome dialog on profile not selected yet (e.g. first launch)
if self.profile.database.selected().is_none() {
Welcome::new(self.profile.clone()).present(Some(self.widget.gobject()));
}
self
} }
pub fn update(&self) { pub fn update(&self) {
@ -181,10 +193,6 @@ impl Browser {
&self.action &self.action
} }
pub fn gobject(&self) -> &ApplicationWindow {
self.widget.gobject()
}
pub fn window(&self) -> &Rc<Window> { pub fn window(&self) -> &Rc<Window> {
&self.window &self.window
} }

View File

@ -3,24 +3,21 @@ mod database;
mod history; mod history;
mod identity; mod identity;
use database::Database;
use gtk::glib::user_config_dir; use gtk::glib::user_config_dir;
use sqlite::{Connection, Transaction}; use sqlite::{Connection, Transaction};
use std::{ use std::{fs::create_dir_all, path::PathBuf, rc::Rc, sync::RwLock};
fs::create_dir_all,
path::{Path, PathBuf},
rc::Rc,
sync::RwLock,
};
const VENDOR: &str = "YGGverse"; const VENDOR: &str = "YGGverse";
const APP_ID: &str = "Yoda"; const APP_ID: &str = "Yoda";
const BRANCH: &str = "master"; const BRANCH: &str = "master";
const DB_NAME: &str = "profile.sqlite3"; const DB_NAME: &str = "database.sqlite3";
pub struct Profile { pub struct Profile {
database: Rc<RwLock<Connection>>, pub database: Rc<Database>,
config_path: PathBuf, pub config_path: PathBuf,
} }
impl Profile { impl Profile {
@ -82,20 +79,10 @@ impl Profile {
// Result // Result
Self { Self {
database: connection, database: Rc::new(Database::new(connection)),
config_path, config_path,
} }
} }
// Getters
pub fn database(&self) -> &Rc<RwLock<Connection>> {
&self.database
}
pub fn config_path(&self) -> &Path {
self.config_path.as_path()
}
} }
pub fn migrate(tx: &Transaction) -> Result<(), String> { pub fn migrate(tx: &Transaction) -> Result<(), String> {

View File

@ -1,22 +1,60 @@
use sqlite::{Error, Transaction};
use gtk::glib::DateTime; use gtk::glib::DateTime;
use sqlite::{Connection, Error, Transaction};
use std::{rc::Rc, sync::RwLock};
#[derive(Debug)]
pub struct Table { pub struct Table {
pub id: i64, pub id: i64,
pub active: bool, pub is_active: bool,
pub time: DateTime, pub time: DateTime,
pub name: Option<String>, pub name: Option<String>,
} }
pub struct Database {
pub connection: Rc<RwLock<Connection>>,
}
impl Database {
// Constructors
/// Create new `Self`
pub fn new(connection: Rc<RwLock<Connection>>) -> Self {
Self { connection }
}
// Getters
/// Get all records
pub fn records(&self) -> Vec<Table> {
let binding = self.connection.read().unwrap();
let tx = binding.unchecked_transaction().unwrap();
records(&tx).unwrap()
}
/// Get selected profile record if exist
pub fn selected(&self) -> Option<Table> {
let binding = self.connection.read().unwrap();
let tx = binding.unchecked_transaction().unwrap();
for record in records(&tx).unwrap() {
if record.is_active {
return Some(record);
}
}
None
}
}
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 `profile` "CREATE TABLE IF NOT EXISTS `profile`
( (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`active` INTEGER NOT NULL, `is_active` INTEGER NOT NULL,
`time` INTEGER NOT NULL, `time` INTEGER NOT NULL,
`name` VARCHAR(255) `name` VARCHAR(255)
)", )",
[], [],
) )
@ -24,19 +62,19 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
pub fn add( pub fn add(
tx: &Transaction, tx: &Transaction,
active: bool, is_active: bool,
time: &DateTime, time: &DateTime,
name: Option<&str>, name: Option<&str>,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
tx.execute("INSERT INTO `profile`", (active, time.to_unix(), name)) tx.execute("INSERT INTO `profile`", (is_active, time.to_unix(), name))
} }
pub fn records(tx: &Transaction) -> Result<Vec<Table>, Error> { pub fn records(tx: &Transaction) -> Result<Vec<Table>, Error> {
let mut stmt = tx.prepare("SELECT `id`, `active`, `time`, `name` FROM `profile`")?; let mut stmt = tx.prepare("SELECT `id`, `is_active`, `time`, `name` FROM `profile`")?;
let result = stmt.query_map([], |row| { let result = stmt.query_map([], |row| {
Ok(Table { Ok(Table {
id: row.get(0)?, id: row.get(0)?,
active: row.get(1)?, is_active: row.get(1)?,
time: DateTime::from_unix_local(row.get(2)?).unwrap(), time: DateTime::from_unix_local(row.get(2)?).unwrap(),
name: row.get(3)?, name: row.get(3)?,
}) })