starting account crud
parent
520e3fa609
commit
1b3203cc9f
|
@ -7,6 +7,12 @@
|
|||
<file compressed="true" preprocess="xml-stripblanks" alias="MainAccountListView.ui">ui/MainAccountListView.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="MainAccountListRow.ui">ui/MainAccountListRow.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="ContentView.ui">ui/ContentView.ui</file>
|
||||
|
||||
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="EditAccountsModal.ui">ui/EditAccountsModal.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="EditAcountListView.ui">ui/EditAccountListView.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="EditAccountRow.ui">ui/EditAccountRow.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="EditAccountRowContent.ui">ui/EditAccountRowContent.ui</file>
|
||||
</gresource>
|
||||
|
||||
</gresources>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ReclaimEditAccountListView" parent="ReclaimView">
|
||||
<signal name="account_removal_requested" handler="on_account_removal_requested" />
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="width-request">250</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkListView" id="lv">
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="resource">/reclaim/EditAccountRow.ui</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="model">
|
||||
<object class="GtkNoSelection" id="selection_model">
|
||||
<binding name="model">
|
||||
<lookup name="accounts">ReclaimEditAccountListView</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="ReclaimEditAccountRowContent">
|
||||
<binding name="account">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ReclaimEditAccountRowContent" parent="AdwBin">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="spacing">12</property>
|
||||
<child type="prefix">
|
||||
<object class="GtkLabel" id="account_label">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="suffix">
|
||||
<object class="GtkButton" id="delete_button">
|
||||
<property name="icon-name">window-close-symbolic</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="on_delete_button_clicked" />
|
||||
<style>
|
||||
<class name="flat" />
|
||||
<class name="circular" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="libadwaita" version="1.0"/>
|
||||
<template class="ReclaimEditAccountsModal" parent="AdwWindow">
|
||||
<property name="title" translatable="yes">Manage Accounts</property>
|
||||
<property name="modal">1</property>
|
||||
<property name="default-width">360</property>
|
||||
<property name="default-height">480</property>
|
||||
<property name="default-widget">account_add_button</property>
|
||||
<child>
|
||||
<object class="GtkShortcutController">
|
||||
<property name="scope">managed</property>
|
||||
<child>
|
||||
<object class="GtkShortcut">
|
||||
<property name="trigger">Escape</property>
|
||||
<property name="action">action(window.close)</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar">
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-top">12</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="margin-start">12</property>
|
||||
<property name="margin-end">12</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="account_name_entry">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="activates-default">1</property>
|
||||
<property name="placeholder-text" translatable="yes">Account Name</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="account_add_button">
|
||||
<property name="sensitive">0</property>
|
||||
<signal name="clicked" handler="on_new_account_requested" />
|
||||
<property name="child">
|
||||
<object class="AdwButtonContent">
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="label" translatable="yes">Add</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
|
@ -25,7 +25,7 @@
|
|||
<property name="hexpand">0</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar" id="nbtitlebar">
|
||||
<object class="AdwHeaderBar" id="accounts_title_bar">
|
||||
<property name="show-end-title-buttons" bind-source="leaf" bind-property="folded" bind-flags="sync-create"/>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">0</property>
|
||||
|
@ -53,6 +53,7 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="en_button">
|
||||
<property name="action-name">win.action_edit_accounts</property>
|
||||
<property name="icon-name">x-office-spreadsheet-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Manage Accounts…</property>
|
||||
</object>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
public class Reclaim.Application : Adw.Application {
|
||||
namespace Reclaim {
|
||||
public class Application : Adw.Application {
|
||||
public static int main (string[] args) {
|
||||
var app = new Reclaim.Application ();
|
||||
|
||||
|
@ -27,14 +28,14 @@ public class Reclaim.Application : Adw.Application {
|
|||
|
||||
base.startup ();
|
||||
|
||||
// typeof (AccountListView).ensure ();
|
||||
// typeof (AccountListView).ensure ();
|
||||
|
||||
var account_repository = new SqliteAccountRepository ();
|
||||
var accounts_view_model = new AccountsViewModel (account_repository);
|
||||
|
||||
// var account_repository = new AccountRespository ();
|
||||
// var account_view_model = new AccountViewModel (account_repository);
|
||||
//
|
||||
typeof (ContentView).ensure ();
|
||||
|
||||
new MainWindow (this);
|
||||
new MainWindow (this, accounts_view_model);
|
||||
}
|
||||
|
||||
protected override void shutdown () {
|
||||
|
@ -47,4 +48,5 @@ public class Reclaim.Application : Adw.Application {
|
|||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Reclaim {
|
||||
public class Account : Object {
|
||||
public int id { get; set; }
|
||||
public string id { get; set; default = Uuid.string_random (); }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,19 @@ source_files = files(
|
|||
|
||||
'utils/ObservableList.vala',
|
||||
|
||||
'repositories/AccountRepository.vala',
|
||||
|
||||
'core/Account.vala',
|
||||
|
||||
'repositories/AccountRepository.vala',
|
||||
'repositories/IAccountRepository.vala',
|
||||
'repositories/SqliteAccountRepository.vala',
|
||||
|
||||
'ui/View.vala',
|
||||
|
||||
'ui/EditAccountsModal.vala',
|
||||
'ui/EditAccountListView.vala',
|
||||
'ui/EditAccountRowContent.vala',
|
||||
|
||||
'ui/ContentView.vala',
|
||||
'ui/AccountViewModel.vala',
|
||||
'ui/AccountsViewModel.vala',
|
||||
'ui/MainAccountListView.vala',
|
||||
'ui/MainWindow.vala'
|
||||
)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
namespace Reclaim {
|
||||
public class AccountRepository : Object {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Gee;
|
||||
using GLib;
|
||||
|
||||
namespace Reclaim {
|
||||
public interface IAccountRepository : Object {
|
||||
public abstract signal void opened ();
|
||||
|
||||
public abstract ArrayList<Account> read_all ();
|
||||
public abstract Account read (string id);
|
||||
public abstract void create (Account account);
|
||||
public abstract void update (Account account);
|
||||
public abstract void delete (string id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
namespace Reclaim {
|
||||
public class SqliteAccountRepository : IAccountRepository, GLib.Object {
|
||||
private Sqlite.Database database;
|
||||
|
||||
public SqliteAccountRepository () {
|
||||
var path = get_database_path ();
|
||||
|
||||
var status = Sqlite.Database.open (path, out database);
|
||||
|
||||
if (status != Sqlite.OK) {
|
||||
stderr.printf (
|
||||
"Can't open database: %d: %s\n",
|
||||
database.errcode (),
|
||||
database.errmsg ());
|
||||
(GLib.Application.get_default ()).quit ();
|
||||
}
|
||||
}
|
||||
|
||||
public Gee.ArrayList<Account> read_all() {
|
||||
const string query = "SELECT * FROM Account;";
|
||||
var accounts = new Gee.ArrayList<Account> ();
|
||||
accounts.add(new Account());
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public Account read(string id) {
|
||||
return new Account ();
|
||||
}
|
||||
|
||||
public void create(Account account) {
|
||||
}
|
||||
|
||||
public void update(Account account) {
|
||||
|
||||
}
|
||||
|
||||
public void delete (string id) {
|
||||
|
||||
}
|
||||
|
||||
private string get_database_path () {
|
||||
// TODO: make configurable
|
||||
string path = Path.build_path (
|
||||
Path.DIR_SEPARATOR_S,
|
||||
Environment.get_user_data_dir (),
|
||||
Config.APP_ID,
|
||||
Config.PROJECT_NAME + ".db");
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Reclaim {
|
||||
public class AccountViewModel : Object {
|
||||
public ObservableList<Account> accounts { get; default = new ObservableList<Account> (); }
|
||||
public AccountRepository? repository { get; construct; }
|
||||
|
||||
public AccountViewModel (AccountRepository repository) {
|
||||
Object(repository: repository);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
namespace Reclaim {
|
||||
public class AccountsViewModel : Object {
|
||||
public ObservableList<Account> accounts { get; default = new ObservableList<Account> (); }
|
||||
public IAccountRepository? repository { get; construct; }
|
||||
|
||||
public AccountsViewModel (IAccountRepository repository) {
|
||||
Object(repository: repository);
|
||||
}
|
||||
|
||||
construct {
|
||||
populate_accounts ();
|
||||
}
|
||||
|
||||
public void create_new_account (Account account) {
|
||||
repository.create (account);
|
||||
|
||||
accounts.add (account);
|
||||
}
|
||||
|
||||
public void populate_accounts () {
|
||||
var accounts = repository.read_all ();
|
||||
|
||||
this.accounts.add_all (accounts);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace Reclaim {
|
||||
[GtkTemplate (ui = "/reclaim/EditAcountListView.ui")]
|
||||
public class EditAccountListView : View {
|
||||
public ObservableList<Account>? accounts { get; set; }
|
||||
public AccountsViewModel? accounts_view_model { get; set; }
|
||||
|
||||
public signal void new_account_requested (Account account);
|
||||
public signal void account_removal_requested (Account account);
|
||||
|
||||
[GtkCallback]
|
||||
public void on_account_removal_requested (Account account) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
[GtkTemplate (ui = "/reclaim/EditAccountListRowContent.ui")]
|
||||
namespace Reclaim {
|
||||
public class EditAccountListRowContent : Adw.Bin {
|
||||
public signal void clicked ();
|
||||
public AccountsViewModel? accounts {get; set;}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
namespace Reclaim {
|
||||
[GtkTemplate (ui = "/reclaim/EditAccountsModal.ui")]
|
||||
public class EditAccountsModal : Adw.Window {
|
||||
public unowned MainWindow main_window = null;
|
||||
public AccountsViewModel accounts_view_model { get; set; }
|
||||
|
||||
[GtkChild]
|
||||
public unowned Gtk.Entry account_name_entry;
|
||||
[GtkChild]
|
||||
public unowned Gtk.Button account_add_button;
|
||||
|
||||
public EditAccountsModal (MainWindow main_window, AccountsViewModel accounts_view_model) {
|
||||
Object (
|
||||
accounts_view_model: accounts_view_model
|
||||
);
|
||||
|
||||
this.main_window = main_window;
|
||||
set_modal (true);
|
||||
set_transient_for (main_window);
|
||||
|
||||
account_name_entry.notify["text"].connect (() => {
|
||||
account_add_button.sensitive = account_name_entry.get_text () != "";
|
||||
});
|
||||
}
|
||||
|
||||
[GtkCallback]
|
||||
void on_new_account_requested () {
|
||||
var account = new Account ();
|
||||
|
||||
account.name = account_name_entry.text;
|
||||
accounts_view_model.create_new_account (account);
|
||||
|
||||
account_name_entry.text = "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
namespace Reclaim {
|
||||
[GtkTemplate (ui = "/reclaim/MainAccountListView.ui")]
|
||||
public class MainAccountListView : View {
|
||||
public ObservableList<Account>? accounts { get; set; }
|
||||
public AccountsViewModel? accounts_view_model { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,33 @@ namespace Reclaim {
|
|||
public Reclaim.Application app { get; construct; }
|
||||
public MainWindow? main_window { get; set; }
|
||||
public Adw.Leaflet? leaflet { get; set; }
|
||||
public AccountsViewModel accounts_view_model {get; construct; }
|
||||
|
||||
public MainWindow (Reclaim.Application app) {
|
||||
public SimpleActionGroup actions { get; construct; }
|
||||
|
||||
|
||||
public MainWindow (Reclaim.Application app, AccountsViewModel accounts_view_model) {
|
||||
GLib.Object (
|
||||
application: app,
|
||||
accounts_view_model: accounts_view_model,
|
||||
title: "Reclaim"
|
||||
);
|
||||
}
|
||||
|
||||
construct {
|
||||
actions = new SimpleActionGroup ();
|
||||
actions.add_action_entries(
|
||||
{
|
||||
{"action_edit_accounts", action_edit_accounts}
|
||||
},
|
||||
this);
|
||||
insert_action_group ("win", actions);
|
||||
}
|
||||
|
||||
public void action_edit_accounts () {
|
||||
var edit_accounts_modal = new EditAccountsModal (this, accounts_view_model);
|
||||
|
||||
edit_accounts_modal.show ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
namespace Reclaim {
|
||||
public class ObservableList<T> : Object, ListModel {
|
||||
List<T> data = new List<T> ();
|
||||
Gee.ArrayList<T> data = new Gee.ArrayList<T> ();
|
||||
|
||||
public void add (T item) {
|
||||
var position = data.length ();
|
||||
var position = data.size;
|
||||
|
||||
data.append (item);
|
||||
data.add (item);
|
||||
|
||||
items_changed (position, 0, 1);
|
||||
}
|
||||
|
||||
public void add_all (List<T> items) {
|
||||
var position = data.length ();
|
||||
public void add_all (Gee.ArrayList<T> items) {
|
||||
var position = data.size;
|
||||
|
||||
foreach (var item in items)
|
||||
data.append (item);
|
||||
data.add (item);
|
||||
|
||||
items_changed (position, 0, items.length ());
|
||||
items_changed (position, 0, items.size);
|
||||
}
|
||||
|
||||
public new T @get (int index) {
|
||||
return data.get (index);
|
||||
}
|
||||
|
||||
public void remove_all () {
|
||||
var current_size = data.length ();
|
||||
data = new List<T> ();
|
||||
var current_size = data.size;
|
||||
data = new Gee.ArrayList<T> ();
|
||||
items_changed (0, current_size, 0);
|
||||
}
|
||||
|
||||
public new T @get (uint index) {
|
||||
return data.nth_data (index);
|
||||
}
|
||||
|
||||
public bool remove (T item) {
|
||||
var position = data.index (item);
|
||||
var position = data.index_of (item);
|
||||
|
||||
if (position == -1)
|
||||
return false;
|
||||
|
@ -42,7 +42,7 @@ namespace Reclaim {
|
|||
}
|
||||
|
||||
Object? get_item (uint position) {
|
||||
return this[position] as Object;
|
||||
return get ((int)position) as Object;
|
||||
}
|
||||
|
||||
Type get_item_type () {
|
||||
|
@ -50,7 +50,7 @@ namespace Reclaim {
|
|||
}
|
||||
|
||||
uint get_n_items () {
|
||||
return data.length ();
|
||||
return data.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue