start some transactions
parent
1b3203cc9f
commit
3af41dbeec
|
@ -1,7 +1,14 @@
|
|||
gnome = import ('gnome')
|
||||
|
||||
reclaim_resources = gnome.compile_resources(
|
||||
'reclaim-resources',
|
||||
'reclaim.gresource.xml',
|
||||
c_name: 'reclaim'
|
||||
)
|
||||
|
||||
install_data(
|
||||
meson.project_name() + '.gschema.xml',
|
||||
|
||||
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
|
||||
)
|
||||
|
||||
subdir('ui')
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/reclaim">
|
||||
<file alias="application.css" compressed="true">application.css</file>
|
||||
<gresource prefix="/reclaim">
|
||||
<file alias="application.css" compressed="true">application.css</file>
|
||||
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="MainWindow.ui">ui/MainWindow.ui</file>
|
||||
<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="MainWindow.ui">ui/MainWindow.ui</file>
|
||||
<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>
|
||||
<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="EditAccountListRow.ui">ui/EditAccountListRow.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="EditAccountListRowContent.ui">ui/EditAccountListRowContent.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="AccountView.ui">ui/AccountView.ui</file>
|
||||
</gresource>
|
||||
|
||||
</gresources>
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
CREATE TABLE account (
|
||||
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE transaction (
|
||||
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id TEXT PRIMARY KEY,
|
||||
description TEXT NOT NULL,
|
||||
datetimestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
category_id INTEGER REFERENCES category(id),
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE journal (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
transaction_id INTEGER REFERENCES transaction(id),
|
||||
account_id INTEGER REFERENCES account(id),
|
||||
account_id TEXT REFERENCES account(id),
|
||||
amount REAL NOT NULL,
|
||||
is_credit BOOLEAN NOT NULL
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE category (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
parent_id INTEGER REFERENCES category(id) NOT NULL DEFAULT 0,
|
||||
name TEXT NOT NULL,
|
||||
DESCRIPTION TEXT
|
||||
);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ReclaimAccountView" parent="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar" id="titlebar">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="show-start-title-buttons">False</property>
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel" id="title">
|
||||
<property name="single-line-mode">True</property>
|
||||
</object>
|
||||
</property>
|
||||
<child type="end">
|
||||
<object class="GtkSearchEntry" id="search_entry"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scroll">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkColumnView" id="column_view">
|
||||
<property name="show-column-separators">True</property>
|
||||
<property name="show-row-separators">True</property>
|
||||
<property name="reorderable">True</property>
|
||||
<property name="enable-rubberband">True</property>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="date_column">
|
||||
<property name="title" translatable="true">Date</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="category_column">
|
||||
<property name="expand">True</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="true">Category</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="payee_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="title" translatable="true">Payee</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
|
@ -14,11 +14,12 @@
|
|||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="reclaim-titlebar"/>
|
||||
<class name="reclaim-titlebar"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<!--stack?-->
|
||||
<object class="GtkStack" id="accountViews">
|
||||
</object>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="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>
|
||||
<binding name="label">
|
||||
<lookup name="name" type="ReclaimAccount">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</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>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
|
@ -9,7 +9,11 @@
|
|||
<child type="prefix">
|
||||
<object class="GtkLabel" id="account_label">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<binding name="label">
|
||||
<lookup name="name" type="ReclaimAccount">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child type="suffix">
|
|
@ -11,7 +11,7 @@
|
|||
<object class="GtkListView" id="lv">
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="resource">/reclaim/EditAccountRow.ui</property>
|
||||
<property name="resource">/reclaim/EditAccountListRow.ui</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="model">
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<?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>
|
|
@ -67,6 +67,13 @@
|
|||
<property name="margin-bottom">12</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="ReclaimEditAccountListView" id="edit_account_list_view">
|
||||
<binding name="accounts">
|
||||
<lookup name="accounts" type="ReclaimAccountsViewModel">
|
||||
<lookup name="accounts_view_model">ReclaimEditAccountsModal</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
<child>
|
||||
<object class="GtkImage" id="account_badge">
|
||||
<property name="valign">center</property>
|
||||
<property name="icon-name">account-symbolic</property>
|
||||
<property name="icon-name">notebook-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="account_label">
|
||||
<property name="valign">center</property>
|
||||
<binding name="label">
|
||||
<lookup name="title" type="ReclaimAccount">
|
||||
<lookup name="name" type="ReclaimAccount">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ReclaimAccountListView" parent="ReclaimView">
|
||||
<template class="ReclaimMainAccountListView" parent="ReclaimView">
|
||||
<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">
|
||||
<style>
|
||||
<class name="boxed-list"/>
|
||||
<class name="content-sidebar-main"/>
|
||||
</style>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="resource">/reclaim/MainAccountListRow.ui</property>
|
||||
|
@ -20,7 +15,7 @@
|
|||
<property name="model">
|
||||
<object class="GtkNoSelection" id="selection_model">
|
||||
<binding name="model">
|
||||
<lookup name="accounts">ReclaimMainAcountListView</lookup>
|
||||
<lookup name="accounts">ReclaimMainAccountListView</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
<property name="margin-bottom">6</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkStackSidebar" id="account_switcher"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
@ -152,18 +153,7 @@
|
|||
<child>
|
||||
<object class="AdwLeafletPage">
|
||||
<property name="child">
|
||||
<object class="GtkStack" id="grid">
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">content</property>
|
||||
<property name="child">
|
||||
<object class="ReclaimContentView">
|
||||
<property name="hexpand">yes</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkStack" id="views"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
gnome = import ('gnome')
|
||||
|
||||
reclaim_resources = gnome.compile_resources(
|
||||
'reclaim-resources',
|
||||
'reclaim.gresource.xml',
|
||||
c_name: 'reclaim'
|
||||
)
|
|
@ -28,11 +28,13 @@ namespace Reclaim {
|
|||
|
||||
base.startup ();
|
||||
|
||||
// typeof (AccountListView).ensure ();
|
||||
typeof (MainAccountListView).ensure ();
|
||||
|
||||
var account_repository = new SqliteAccountRepository ();
|
||||
var accounts_view_model = new AccountsViewModel (account_repository);
|
||||
|
||||
typeof (EditAccountListRowContent).ensure ();
|
||||
typeof (EditAccountListView).ensure ();
|
||||
typeof (ContentView).ensure ();
|
||||
|
||||
new MainWindow (this, accounts_view_model);
|
||||
|
|
|
@ -12,8 +12,9 @@ source_files = files(
|
|||
|
||||
'ui/EditAccountsModal.vala',
|
||||
'ui/EditAccountListView.vala',
|
||||
'ui/EditAccountRowContent.vala',
|
||||
'ui/EditAccountListRowContent.vala',
|
||||
|
||||
'ui/AccountView.vala',
|
||||
'ui/ContentView.vala',
|
||||
'ui/AccountsViewModel.vala',
|
||||
'ui/MainAccountListView.vala',
|
||||
|
|
|
@ -17,17 +17,67 @@ namespace Reclaim {
|
|||
}
|
||||
|
||||
public Gee.ArrayList<Account> read_all() {
|
||||
const string query = "SELECT * FROM Account;";
|
||||
const string query = "SELECT id, name FROM account;";
|
||||
var accounts = new Gee.ArrayList<Account> ();
|
||||
accounts.add(new Account());
|
||||
Sqlite.Statement statement;
|
||||
int status;
|
||||
|
||||
status = database.prepare_v2 (query, -1, out statement);
|
||||
assert(status == Sqlite.OK);
|
||||
|
||||
while ((status = statement.step ()) == Sqlite.ROW) {
|
||||
var account = new Account ();
|
||||
|
||||
account.id = statement.column_text (0);
|
||||
account.name = statement.column_text (1);
|
||||
|
||||
accounts.add (account);
|
||||
}
|
||||
|
||||
statement.reset ();
|
||||
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public Account read(string id) {
|
||||
return new Account ();
|
||||
const string query = "SELECT id, name FROM account WHERE id = ?;";
|
||||
Sqlite.Statement statement;
|
||||
int status;
|
||||
Account account = new Account ();
|
||||
|
||||
status = database.prepare_v2 (query, -1, out statement);
|
||||
assert (status == Sqlite.OK);
|
||||
|
||||
status = statement.bind_text (1, id);
|
||||
assert (status == Sqlite.OK);
|
||||
|
||||
if (statement.step () == Sqlite.ROW) {
|
||||
account.id = statement.column_text (0);
|
||||
account.name = statement.column_text (1);
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
public void create(Account account) {
|
||||
const string query = "INSERT OR IGNORE INTO account (id, name) VALUES (?, ?);";
|
||||
Sqlite.Statement statement;
|
||||
int status;
|
||||
|
||||
status = database.prepare_v2 (query, -1, out statement);
|
||||
assert (status == Sqlite.OK);
|
||||
|
||||
status = statement.bind_text (1, account.id);
|
||||
assert (status == Sqlite.OK);
|
||||
|
||||
status = statement.bind_text (2, account.name);
|
||||
assert (status == Sqlite.OK);
|
||||
|
||||
if (statement.step () != Sqlite.DONE) {
|
||||
warning ("Error: %d: %s", database.errcode (), database.errmsg ());
|
||||
}
|
||||
|
||||
statement.reset ();
|
||||
}
|
||||
|
||||
public void update(Account account) {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
namespace Reclaim {
|
||||
public class AccountList : Object, ArrayList, ListModel {
|
||||
private IAccountRepository repository { get; construct }
|
||||
|
||||
public AccountList (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);
|
||||
}
|
||||
|
||||
public ovverride
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace Reclaim {
|
||||
[GtkTemplate (ui = "/reclaim/AccountView.ui")]
|
||||
public class AccountView : Gtk.Box {
|
||||
public unowned MainWindow main_window = null;
|
||||
public Account account { get; set; }
|
||||
|
||||
[GtkChild]
|
||||
private unowned Gtk.Label title;
|
||||
[GtkChild]
|
||||
private unowned Gtk.SearchEntry search_entry;
|
||||
|
||||
public AccountView (MainWindow main_window, Account account) {
|
||||
Object (account: account);
|
||||
this.main_window = main_window;
|
||||
|
||||
title.label = account.name;
|
||||
|
||||
search_entry.set_key_capture_widget (main_window);
|
||||
search_entry.placeholder_text = "Search %s".printf (account.name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
namespace Reclaim {
|
||||
public class AccountsViewModel : Object {
|
||||
public ObservableList<Account> accounts { get; default = new ObservableList<Account> (); }
|
||||
public IAccountRepository? repository { get; construct; }
|
||||
public IAccountRepository repository { get; construct; }
|
||||
|
||||
public AccountsViewModel (IAccountRepository repository) {
|
||||
Object(repository: repository);
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
namespace Reclaim {
|
||||
public class EditAccountListRowContent : Adw.Bin {
|
||||
public signal void clicked ();
|
||||
public AccountsViewModel? accounts {get; set;}
|
||||
public Account account { get; set;}
|
||||
|
||||
public EditAccountListRowContent (Account account) {
|
||||
Object(account: account);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
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 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);
|
||||
|
|
|
@ -1,7 +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; }
|
||||
public ObservableList<Account> accounts { get; set; }
|
||||
public AccountsViewModel accounts_view_model { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,12 @@ namespace Reclaim {
|
|||
public Adw.Leaflet? leaflet { get; set; }
|
||||
public AccountsViewModel accounts_view_model {get; construct; }
|
||||
|
||||
public SimpleActionGroup actions { get; construct; }
|
||||
[GtkChild]
|
||||
private unowned Gtk.Stack views;
|
||||
[GtkChild]
|
||||
private unowned Gtk.StackSidebar account_switcher;
|
||||
|
||||
public SimpleActionGroup actions { get; construct; }
|
||||
|
||||
public MainWindow (Reclaim.Application app, AccountsViewModel accounts_view_model) {
|
||||
GLib.Object (
|
||||
|
@ -15,6 +19,13 @@ namespace Reclaim {
|
|||
accounts_view_model: accounts_view_model,
|
||||
title: "Reclaim"
|
||||
);
|
||||
|
||||
foreach (var account in accounts_view_model.accounts) {
|
||||
var accountView = new AccountView(this, account);
|
||||
|
||||
views.add_titled (accountView, account.name, account.name);
|
||||
}
|
||||
account_switcher.set_stack (views);
|
||||
}
|
||||
|
||||
construct {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
namespace Reclaim {
|
||||
public class ObservableList<T> : Object, ListModel {
|
||||
Gee.ArrayList<T> data = new Gee.ArrayList<T> ();
|
||||
private Gee.ArrayList<T> data;
|
||||
|
||||
public ObservableList () {
|
||||
data = new Gee.ArrayList<T> ();
|
||||
}
|
||||
|
||||
public void add (T item) {
|
||||
var position = data.size;
|
||||
|
@ -41,6 +45,10 @@ namespace Reclaim {
|
|||
return true;
|
||||
}
|
||||
|
||||
public Gee.Iterator<T> iterator () {
|
||||
return data.iterator ();
|
||||
}
|
||||
|
||||
Object? get_item (uint position) {
|
||||
return get ((int)position) as Object;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue