summaryrefslogtreecommitdiff
path: root/schist_desktop_gui/src/gui.rs
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2026-02-07 18:45:08 +0000
committerJoe Carstairs <me@joeac.net>2026-02-07 18:45:17 +0000
commit65596363d43995bf2002d4aa8405d84484f2542b (patch)
tree830846f335d97a236c61ff8ac3a9080b455e3b4a /schist_desktop_gui/src/gui.rs
parent0986b29354690327b5dafc852667c7dc191d1a22 (diff)
task-088: cache open file
Diffstat (limited to 'schist_desktop_gui/src/gui.rs')
-rw-r--r--schist_desktop_gui/src/gui.rs128
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(),
}
}
}