diff --git a/Build.PL b/Build.PL index 4cca69d..46b1f55 100755 --- a/Build.PL +++ b/Build.PL @@ -15,6 +15,7 @@ my $build = Module::Build->new( 'DBD::SQLite' => 0, 'DBI' => 0, 'File::HomeDir' => 0, + 'Moo' => 0, }, ); $build->create_build_script; diff --git a/lib/GEmeTool/Config.pm b/lib/GEmeTool/Config.pm new file mode 100644 index 0000000..db3fb24 --- /dev/null +++ b/lib/GEmeTool/Config.pm @@ -0,0 +1,22 @@ +package GEmeTool::Config; + +use v5.16.3; + +use strict; +use warnings; + +use Moo; +use File::HomeDir; +use Path::Tiny; + +my $dist = 'GEmeTool'; + +sub config_dir { + my $class = shift; + return path(File::HomeDir->my_dist_config($dist, { create => 1 })); +} +sub data_dir { + my $class = shift; + return path(File::HomeDir->my_dist_data($dist, { create => 1 })); +} +1; diff --git a/lib/GEmeTool/DB.pm b/lib/GEmeTool/DB.pm new file mode 100644 index 0000000..de95401 --- /dev/null +++ b/lib/GEmeTool/DB.pm @@ -0,0 +1,96 @@ +package GEmeTool::DB; + +use v5.16.3; + +use strict; +use warnings; + +use DBI; +use DBD::SQLite; +use DBD::SQLite::Constants qw/:all/; + +use GEmeTool::DB::Migrations; +use GEmeTool::Config; + +my $dbh; + +sub connect { + if ( defined $dbh ) { + return $dbh; + } + my $class = shift; + my $app = shift; + my $data_dir = GEmeTool::Config->new->data_dir; + say $data_dir; + $dbh = DBI->connect( + "dbi:SQLite:dbname=@{[$data_dir->child('gemetool.sqlite')]}", + undef, undef, + { + RaiseError => 1, + sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_STRICT, + }, + ); + $class->_migrate($dbh); + return $dbh; +} + +sub _migrate { + my $class = shift; + my $dbh = shift; + local $dbh->{RaiseError} = 0; + local $dbh->{PrintError} = 0; + my @migrations = GEmeTool::DB::Migrations::MIGRATIONS(); + if ( $class->get_current_migration($dbh) > @migrations ) { + warn "Something happened there, wrong migration number."; + } + if ( $class->get_current_migration($dbh) >= @migrations ) { + say STDERR "Migrations already applied."; + return; + } + $class->_apply_migrations( $dbh, \@migrations ); +} + +sub _apply_migrations { + my $class = shift; + my $dbh = shift; + my $migrations = shift; + for ( + my $i = $class->get_current_migration($dbh) ; + $i < @$migrations ; + $i++ + ) + { + local $dbh->{RaiseError} = 1; + my $current_migration = $migrations->[$i]; + my $migration_number = $i + 1; + $class->_apply_migration( $dbh, $current_migration, $migration_number ); + } +} + +sub _apply_migration { + my $class = shift; + my $dbh = shift; + my $current_migration = shift; + my $migration_number = shift; + { + if (ref $current_migration eq 'CODE') { + $current_migration->($dbh); + next; + } + $dbh->do($current_migration); + } + $dbh->do( <<'EOF', undef, 'current_migration', $migration_number ); +INSERT OR REPLACE INTO options +VALUES ($1, $2); +EOF +} + +sub get_current_migration { + my $class = shift; + my $dbh = shift; + my $result = $dbh->selectrow_hashref( <<'EOF', undef, 'current_migration' ); +select value from options where name = ?; +EOF + return int( $result->{value} // 0 ); +} +1; diff --git a/lib/GEmeTool/DB/Migrations.pm b/lib/GEmeTool/DB/Migrations.pm new file mode 100644 index 0000000..dc9882a --- /dev/null +++ b/lib/GEmeTool/DB/Migrations.pm @@ -0,0 +1,19 @@ +package GEmeTool::DB::Migrations; + +use v5.16.3; + +use strict; +use warnings; +use utf8; + +use feature 'signatures'; + +sub MIGRATIONS { + return ( + 'CREATE TABLE options ( + name TEXT PRIMARY KEY, + value TEXT + )', + ); +} +1; diff --git a/lib/GEmeTool/Options.pm b/lib/GEmeTool/Options.pm new file mode 100644 index 0000000..4d83870 --- /dev/null +++ b/lib/GEmeTool/Options.pm @@ -0,0 +1,65 @@ +package GEmeTool::Options; + +use v5.16.3; + +use strict; +use warnings; + +use Moo; +use GEmeTool::DB; + +my $db = GEmeTool::DB->connect; + +my $query_get_option = <<'EOF'; +SELECT value +FROM options +WHERE name = ?; +EOF + +my $query_replace_option = <<'EOF'; +INSERT OR REPLACE +INTO options (name, value) +VALUES (?, ?); +EOF + +sub _get_option_value { + my $self = shift; + my $name = shift; + my $result = $db->selectrow_hashref($query_get_option, {}, $name); + if (!defined $result) { + return; + } + return $result->{value}; +} + +sub _set_option_value { + my $self = shift; + my $name = shift; + my $value = shift; + return $db->do($query_replace_option, {}, $name, $value); +} + +sub get_last_dir_open { + my $self = shift; + return $self->_get_option_value('last_dir_open'); +} + +sub set_last_dir_open { + my $self = shift; + my $value = shift; + die '$value must be defined' if !defined $value; + return $self->_set_option_value('last_dir_open', $value); +} + +sub get_last_dir_save { + my $self = shift; + return $self->_get_option_value('last_dir_save') // $self->get_last_dir_open; +} + +sub set_last_dir_save { + my $self = shift; + my $value = shift; + die '$value must be defined' if !defined $value; + return $self->_set_option_value('last_dir_save', $value); +} +1; diff --git a/scripts/start.pl b/scripts/start.pl index 04d1217..d348eef 100644 --- a/scripts/start.pl +++ b/scripts/start.pl @@ -10,6 +10,7 @@ use Glib::IO; use Glib::Object::Introspection; use Data::Dumper; use Path::Tiny; +use GEmeTool::Options; use utf8; use Rsaves @@ -34,6 +35,7 @@ Glib::Object::Introspection->setup( my %rematches = @Rsaves::Constants::Emerald::Rematches::REMATCHES; my $app = Gtk4::Application->new( 'tech.owlcode.GEmeTool', 'default-flags' ); +my $options = GEmeTool::Options->new; $app->signal_connect( activate => \&activate ); $app->run; @@ -98,12 +100,12 @@ sub activate_open { my $extra = shift; my $save_as = shift; my $cancellable = Glib::IO::Cancellable->new; - $cancellable->signal_connect(cancelled => sub { - say 'cancelled'; - }); my $dialog = Gtk4::FileDialog->new; - my $curdir = Glib::IO::File::new_for_path('.'); - $dialog->set_initial_folder($curdir); + my $last_dir = $options->get_last_dir_open; + if (defined $last_dir && -d $last_dir) { + my $curdir = Glib::IO::File::new_for_path($last_dir); + $dialog->set_initial_folder($curdir); + } $dialog->open( $win, $cancellable, sub { @@ -114,6 +116,7 @@ sub activate_open { my $file = $dialog->open_finish($res); return if !defined $file; $file = path( $file->get_path ); + $options->set_last_dir_open($file->parent.''); start_editing_file( $win, $file, $saves, $extra, $save_as ); } ); @@ -124,18 +127,22 @@ sub activate_save { my $saves = shift; my $extra = shift; my $dialog = Gtk4::FileDialog->new; - my $curdir = Glib::IO::File::new_for_path('.'); - $dialog->set_initial_folder($curdir); - $dialog->open( + my $last_dir = $options->get_last_dir_save; + if (defined $last_dir && -d $last_dir) { + my $curdir = Glib::IO::File::new_for_path($last_dir); + $dialog->set_initial_folder($curdir); + } + $dialog->save( $win, undef, sub { my ( $self, $res ) = @_; if ($res->had_error) { return; } - my $file = $dialog->open_finish($res); + my $file = $dialog->save_finish($res); return if !defined $file; $file = path( $file->get_path ); + $options->set_last_dir_save($file->parent.''); save( $file, $saves, $extra ); } );