pub mod browser; mod database; use crate::profile::Profile; use adw::Application; use anyhow::Result; use browser::Browser; use gtk::{ glib::ExitCode, prelude::{ActionExt, ApplicationExt, ApplicationExtManual, GtkApplicationExt}, }; use sqlite::Transaction; use std::{rc::Rc, sync::Arc}; const APPLICATION_ID: &str = "io.github.yggverse.Yoda"; pub struct App { profile: Arc, application: Application, } impl App { // Constructors /// Build new `Self` pub fn build(profile: Profile) -> Result { // Init GTK let application = Application::builder() .application_id(APPLICATION_ID) .build(); // Init components let profile = Arc::new(profile); let browser = Rc::new(Browser::build(&profile)); // Prevent startup warning @TODO application.connect_activate(|_| {}); // Init events application.connect_startup({ let browser = browser.clone(); let profile = profile.clone(); move |this| { // Init readable connection match profile.database.pool.get() { Ok(connection) => { // Create transaction match connection.unchecked_transaction() { Ok(transaction) => { // Restore previous session from DB match database::select(&transaction) { Ok(records) => { // Restore child components for record in records { if let Err(e) = browser.restore(&transaction, record.id) { todo!("{e}") } } } Err(e) => todo!("{e}"), } } Err(e) => todo!("{e}"), } } Err(e) => todo!("{e}"), } // Run initial features, show widget browser.init(Some(this)).present(); } }); application.connect_shutdown({ let browser = browser.clone(); let profile = profile.clone(); move |_| { match profile.save() { Ok(_) => match profile.database.pool.get() { Ok(mut connection) => { // Create transaction match connection.transaction() { Ok(transaction) => { match database::select(&transaction) { Ok(records) => { // Cleanup previous session records for record in records { match database::delete(&transaction, record.id) { Ok(_) => { // Delegate clean action to childs if let Err(e) = browser.clean(&transaction, record.id) { todo!("{e}") } } Err(e) => todo!("{e}"), } } // Save current session to DB match database::insert(&transaction) { Ok(_) => { // Delegate save action to childs if let Err(e) = browser.save( &transaction, database::last_insert_id(&transaction), ) { todo!("{e}") } } Err(e) => todo!("{e}"), } } Err(e) => todo!("{e}"), } // Confirm changes if let Err(e) = transaction.commit() { todo!("{e}") } } Err(e) => todo!("{e}"), } } Err(e) => todo!("{e}"), }, Err(e) => todo!("{e}"), } } }); // Init accels for (detailed_action_name, &accels) in &[ // Browser actions ( format!( "{}.{}", browser.action.id, browser.action.close.simple_action.name() ), &["Escape"], ), ( format!( "{}.{}", browser.action.id, browser.action.debug.simple_action.name() ), &["i"], ), ( format!("{}.{}", browser.action.id, browser.action.escape.name()), &["Escape"], ), // Tab actions ( format!( "{}.{}", browser.window.action.id, browser.window.action.append.simple_action.name() ), &["t"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.bookmark.simple_action.name() ), &["b"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.find.simple_action.name() ), &["f"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.pin.simple_action.name() ), &["p"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.reload.simple_action.name() ), &["r"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.save_as.simple_action.name() ), &["s"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.open.simple_action.name() ), &["o"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.source.simple_action.name() ), &["u"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.home.simple_action.name() ), &["h"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.history_back.simple_action.name() ), &["Left"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.history_forward.simple_action.name() ), &["Right"], ), ( format!( "{}.{}", browser.window.action.id, browser.window.action.close.simple_action.name() ), &["q"], ), ] { application.set_accels_for_action(detailed_action_name, &accels); } // Return activated App struct Ok(Self { profile: profile.clone(), application, }) } // Actions pub fn run(&self) -> Result { // Begin database migration @TODO { let mut connection = self.profile.database.pool.get()?; let transaction = connection.transaction()?; migrate(&transaction)?; transaction.commit()?; } // unlock database // Start application Ok(self.application.run()) } } // Tools fn migrate(tx: &Transaction) -> Result<()> { // Migrate self components database::init(tx)?; // Delegate migration to childs browser::migrate(tx)?; // Success Ok(()) }