diff options
| author | Joe Carstairs <me@joeac.net> | 2026-02-07 18:45:08 +0000 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2026-02-07 18:45:17 +0000 |
| commit | 65596363d43995bf2002d4aa8405d84484f2542b (patch) | |
| tree | 830846f335d97a236c61ff8ac3a9080b455e3b4a /schist_desktop_gui/src/gui.rs | |
| parent | 0986b29354690327b5dafc852667c7dc191d1a22 (diff) | |
task-088: cache open file
Diffstat (limited to 'schist_desktop_gui/src/gui.rs')
| -rw-r--r-- | schist_desktop_gui/src/gui.rs | 128 |
1 files changed, 113 insertions, 15 deletions
diff --git a/schist_desktop_gui/src/gui.rs b/schist_desktop_gui/src/gui.rs index eb2fce9..26f147b 100644 --- a/schist_desktop_gui/src/gui.rs +++ b/schist_desktop_gui/src/gui.rs @@ -1,22 +1,33 @@ pub mod components; +use actualbudget_to_schist_transformer::schist_state::{export_schist_state, SchistState}; +use itertools::Itertools; pub mod screens; +use std::{path::PathBuf, str::FromStr}; + use diesel::SqliteConnection; -use iced::Element; +use iced::{Element, Task}; use schist_models::{Account, Bucket}; use schist_queries::{accounts::get_all_accounts, buckets::get_all_buckets}; use crate::{ + cache::{put_to_cache, remove_from_cache, CACHE_KEYS}, config::Config, + dialog::{import_from_actualbudget_dialog, new_file_dialog, pick_file_dialog}, gui::screens::{files_screen, main_screen, FilesScreen, MainScreen, Screen}, - paths::get_file_paths, + paths::{get_file_paths, get_schist_database_directory}, shortcut::KeyBind, traits::{Component, Viewable}, + Cache, DatabaseConnection, }; #[derive(Clone, Debug)] pub enum Message { Event(iced::Event), + FailedToCreateFile(String), + FailedToOpenFile(PathBuf, String), + FailedToPickFile(String), + FailedToImportFromActualbudget(String), FilesScreenMessage(files_screen::Message), MainScreenMessage(main_screen::Message), RefetchedAccounts(FetchResult<Vec<Account>>), @@ -47,16 +58,24 @@ pub struct Gui { } impl Gui { - pub fn new() -> (Self, iced::Task<Message>) { + pub fn new(cache: &Cache) -> (Self, iced::Task<Message>) { let file_paths = get_file_paths(); - let gui = Self { + let mut gui = Self { active_screen: Screen::FilesScreen, connection: None, files_screen: FilesScreen::new(&file_paths), main_screen: MainScreen::new(), config: Config::default(), }; - (gui, iced::Task::none()) + + let mut tasks = Vec::new(); + + if let Some(last_open_file) = &cache.last_open_file { + let Ok(last_open_file) = PathBuf::from_str(&last_open_file); + tasks.push(gui.open_file(&last_open_file)); + } + + (gui, Task::batch(tasks)) } } @@ -167,23 +186,102 @@ impl Gui { iced::Task::none() } Message::FilesScreenMessage(message) => self.update_files_screen(message), + Message::FailedToCreateFile(err) => { + self.update_files_screen(files_screen::Message::ReportFailedToCreateFile(err)) + } + Message::FailedToOpenFile(path, err) => { + self.update_files_screen(files_screen::Message::ReportFailedToOpenFile(path, err)) + } + Message::FailedToImportFromActualbudget(err) => self.update_files_screen( + files_screen::Message::ReportFailedToImportFromActualbudget(err), + ), + Message::FailedToPickFile(err) => { + self.update_files_screen(files_screen::Message::ReportFailedToPickFile(err)) + } } } fn update_files_screen(&mut self, message: files_screen::Message) -> iced::Task<Message> { match self.files_screen.update(message) { + files_screen::Action::ImportFromActualbudget => self.import_from_actualbudget(), + files_screen::Action::NewFile => self.new_file(), files_screen::Action::None => iced::Task::none(), - files_screen::Action::OpenedFile(sqlite_connection) => { - let mut connection = sqlite_connection.connection; - let buckets = get_all_buckets(&mut connection).map_err(FetchError::new); - let accounts = get_all_accounts(&mut connection).map_err(FetchError::new); - self.connection = Some(connection); - self.active_screen = Screen::MainScreen; - iced::Task::batch(vec![ - self.update(Message::RefetchedBuckets(buckets)), - self.update(Message::RefetchedAccounts(accounts)), - ]) + files_screen::Action::OpenFile(path) => self.open_file(&path), + files_screen::Action::PickFile => self.pick_file(), + } + } + + fn open_file(&mut self, file_path: &PathBuf) -> Task<Message> { + let sqlite_connection = DatabaseConnection::establish(file_path.to_path_buf()).ok(); + if let Err((path, err)) = sqlite_connection { + return Task::done(Message::FailedToOpenFile(path, err.chain().join("\n | "))); + } + self.on_new_connection(sqlite_connection.unwrap().connection, file_path) + } + + fn on_new_connection( + &mut self, + mut connection: SqliteConnection, + path: &PathBuf, + ) -> Task<Message> { + let buckets = get_all_buckets(&mut connection).map_err(FetchError::new); + let accounts = get_all_accounts(&mut connection).map_err(FetchError::new); + self.connection = Some(connection); + self.active_screen = Screen::MainScreen; + if let Some(path) = path.to_str() { + let _ = put_to_cache(CACHE_KEYS.last_open_file, path); + } else { + let _ = remove_from_cache(CACHE_KEYS.last_open_file); + } + iced::Task::batch(vec![ + self.update(Message::RefetchedBuckets(buckets)), + self.update(Message::RefetchedAccounts(accounts)), + ]) + } + + fn new_file(&mut self) -> Task<Message> { + match new_file_dialog(get_schist_database_directory().ok()) { + Some(path) => self.open_file(&path), + None => Task::none(), + } + } + + fn new_file_with_state(&mut self, state: &SchistState) -> Task<Message> { + match new_file_dialog(get_schist_database_directory().ok()) { + Some(path) => { + let sqlite_connection = DatabaseConnection::establish(path.clone()).ok(); + if let Err((path, err)) = sqlite_connection { + return Task::done(Message::FailedToOpenFile(path, err.chain().join("\n | "))); + } + let mut db_conn = sqlite_connection.unwrap().connection; + export_schist_state(state, &mut db_conn).map_or_else( + |err| Task::done(Message::FailedToCreateFile(err.chain().join("\n | "))), + move |()| self.on_new_connection(db_conn, &path), + ) } + None => Task::none(), + } + } + + fn import_from_actualbudget(&mut self) -> Task<Message> { + match import_from_actualbudget_dialog() { + Some(Ok(state)) => self.new_file_with_state(&state), + Some(Err((_path, err))) => Task::done(Message::FailedToImportFromActualbudget( + err.chain().join("\n | "), + )), + None => Task::none(), + } + } + + fn pick_file(&mut self) -> Task<Message> { + match pick_file_dialog(get_schist_database_directory().ok()) { + Some(path) => match DatabaseConnection::establish(path.clone()).ok() { + Ok(db_conn) => self.on_new_connection(db_conn.connection, &path), + Err((_path, err)) => { + Task::done(Message::FailedToPickFile(err.chain().join("\n | "))) + } + }, + None => Task::none(), } } } |
