176 lines
5.1 KiB
Rust
Raw Normal View History

use std::error::Error;
use std::time::Duration;
use once_cell::sync::OnceCell;
use sqlx::{
SqlitePool,
sqlite::SqlitePoolOptions,
sqlite::SqliteConnectOptions,
};
use tauri::{
App,
AppHandle,
Manager,
async_runtime as rt,
};
use crate::{
config::{self, AppConfig},
credentials::Session,
ipc,
server::Server,
errors::*,
shortcuts,
state::AppState,
tray,
};
pub static APP: OnceCell<AppHandle> = OnceCell::new();
pub fn run() -> tauri::Result<()> {
tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
show_main_window(app)
2024-06-01 20:17:50 -04:00
.blocking_error_popup("Failed to show main window")
}))
2024-06-01 20:17:50 -04:00
.plugin(tauri_plugin_global_shortcut::Builder::default().build())
.invoke_handler(tauri::generate_handler![
ipc::unlock,
ipc::respond,
ipc::get_session_status,
ipc::signal_activity,
ipc::save_credentials,
ipc::get_config,
ipc::save_config,
2023-08-02 19:57:37 -07:00
ipc::launch_terminal,
ipc::get_setup_errors,
])
.setup(|app| rt::block_on(setup(app)))
.build(tauri::generate_context!())?
.run(|app, run_event| match run_event {
tauri::RunEvent::WindowEvent { event, .. } => match event {
tauri::WindowEvent::CloseRequested { api, .. } => {
let _ = hide_main_window(app);
api.prevent_close();
}
_ => ()
}
_ => ()
});
Ok(())
}
pub async fn connect_db() -> Result<SqlitePool, SetupError> {
let conn_opts = SqliteConnectOptions::new()
.filename(config::get_or_create_db_path()?)
.create_if_missing(true);
let pool_opts = SqlitePoolOptions::new();
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
sqlx::migrate!().run(&pool).await?;
Ok(pool)
}
async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
2024-06-01 20:17:50 -04:00
APP.set(app.handle().clone()).unwrap();
tray::setup(app)?;
2023-09-13 11:06:40 -07:00
// get_or_create_db_path doesn't create the actual db file, just the directory
let is_first_launch = !config::get_or_create_db_path()?.exists();
let pool = connect_db().await?;
let mut setup_errors: Vec<String> = vec![];
2023-09-13 11:06:40 -07:00
let mut conf = match AppConfig::load(&pool).await {
2023-09-13 11:06:40 -07:00
Ok(c) => c,
Err(SetupError::ConfigParseError(_)) => {
setup_errors.push(
"Could not load configuration from database. Reverting to defaults.".into()
);
2023-09-13 11:06:40 -07:00
AppConfig::default()
},
err => err?,
};
let session = Session::load(&pool).await?;
2024-06-01 20:17:50 -04:00
Server::start(app.handle().clone())?;
config::set_auto_launch(conf.start_on_login)?;
if let Err(_e) = config::set_auto_launch(conf.start_on_login) {
setup_errors.push("Error: Failed to manage autolaunch.".into());
}
// if hotkeys fail to register, disable them so that this error doesn't have to keep showing up
if let Err(_e) = shortcuts::register_hotkeys(&conf.hotkeys) {
conf.hotkeys.disable_all();
conf.save(&pool).await?;
setup_errors.push("Failed to register hotkeys. Hotkey settings have been disabled.".into());
}
2023-09-13 11:06:40 -07:00
let desktop_is_gnome = std::env::var("XDG_CURRENT_DESKTOP")
.map(|names| names.split(':').any(|n| n == "GNOME"))
.unwrap_or(false);
2023-07-11 16:13:20 -07:00
// if session is empty, this is probably the first launch, so don't autohide
if !conf.start_minimized || is_first_launch {
show_main_window(&app.handle())?;
}
let state = AppState::new(conf, session, pool, setup_errors, desktop_is_gnome);
app.manage(state);
// make sure we do this after managing app state, so that it doesn't panic
2024-06-01 20:17:50 -04:00
start_auto_locker(app.app_handle().clone());
Ok(())
}
fn start_auto_locker(app: AppHandle) {
rt::spawn(async move {
let state = app.state::<AppState>();
loop {
// this gives our session-timeout a minimum resolution of 10s, which seems fine?
let delay = Duration::from_secs(10);
tokio::time::sleep(delay).await;
if state.should_auto_lock().await {
2024-06-01 20:17:50 -04:00
state.lock().await.error_popup("Failed to lock Creddy").await;
}
}
});
}
pub fn show_main_window(app: &AppHandle) -> Result<(), WindowError> {
2024-06-01 20:17:50 -04:00
let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?;
w.show()?;
2024-06-01 20:17:50 -04:00
// app.tray_handle()
// .get_item("show_hide")
// .set_title("Hide")?;
Ok(())
}
pub fn hide_main_window(app: &AppHandle) -> Result<(), WindowError> {
2024-06-01 20:17:50 -04:00
let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?;
w.hide()?;
2024-06-01 20:17:50 -04:00
// app.tray_handle()
// .get_item("show_hide")
// .set_title("Show")?;
Ok(())
}
pub fn toggle_main_window(app: &AppHandle) -> Result<(), WindowError> {
2024-06-01 20:17:50 -04:00
let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?;
if w.is_visible()? {
hide_main_window(app)
}
else {
show_main_window(app)
}
}