Start migration to sqlite using drift

This commit is contained in:
2025-05-17 23:51:51 +02:00
parent 4d267eff88
commit 5dc474407c
50 changed files with 9549 additions and 6972 deletions

View File

@@ -1,11 +1,9 @@
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/collections/account.dart';
import 'package:okane/database/collections/beneficiary.dart';
import 'package:okane/database/database.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/ui/pages/account/breakdown_card.dart';
import 'package:okane/ui/pages/account/delete_account.dart';
import 'package:okane/ui/pages/account/loan_card.dart';
import 'package:okane/ui/pages/account/total_balance_card.dart';
import 'package:okane/ui/pages/account/upcoming_transactions_card.dart';
@@ -27,7 +25,6 @@ class AccountListPageState extends State<AccountListPage> {
@override
Widget build(BuildContext context) {
final bloc = GetIt.I.get<CoreCubit>();
return Stack(
children: [
ListView(
@@ -66,9 +63,12 @@ class AccountListPageState extends State<AccountListPage> {
children: [
Text(state.accounts[index].name!),
FutureBuilder(
future: getTotalBalance(
state.accounts[index],
),
future: GetIt.I
.get<OkaneDatabase>()
.transactionsDao
.getTotalBalance([
state.accounts[index].id,
]),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container();
@@ -141,16 +141,21 @@ class AccountListPageState extends State<AccountListPage> {
onPressed: () async {
if (_accountNameController.text.isEmpty) return;
final a =
Account()..name = _accountNameController.text;
final b =
Beneficiary()
..name = _accountNameController.text
..account.value =
GetIt.I.get<CoreCubit>().activeAccount
..type = BeneficiaryType.account;
await upsertAccount(a);
await upsertBeneficiary(b);
final db = GetIt.I.get<OkaneDatabase>();
print("Adding account");
final accountId = await db.accountsDao
.upsertAccount(
AccountsCompanion(
name: Value(_accountNameController.text),
),
);
print("Adding beneficiary");
final b = BeneficiariesCompanion(
name: Value(_accountNameController.text),
accountId: Value(accountId),
type: Value(BeneficiaryType.account),
);
await db.beneficiariesDao.upsertBeneficiary(b);
_accountNameController.text = "";
Navigator.of(context).pop();
},

View File

@@ -2,7 +2,7 @@ import 'dart:collection';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/database.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart';
@@ -26,21 +26,27 @@ class AccountBalanceGraphCard extends StatelessWidget {
Future<List<FlSpot>> getAccountBalance() async {
final coreCubit = GetIt.I.get<CoreCubit>();
final today = toMidnight(DateTime.now());
final transactions = await getLastTransactions(
final db = GetIt.I.get<OkaneDatabase>();
print("Getting transactions");
final transactions = await db.transactionsDao.getLastTransactions(
coreCubit.activeAccount!,
today,
30,
);
final totalBalance = await getTotalBalance(coreCubit.activeAccount!);
print("Got transactions. Getting balance");
final totalBalance = await db.transactionsDao.getTotalBalance([
coreCubit.activeAccount!.id,
]);
print("Got balance");
// Compute the differences per day
Map<int, double> differences = Map.fromEntries(
List.generate(30, (i) => i).map((i) => MapEntry(i, 0)),
);
for (final item in transactions) {
final diff = today.difference(toMidnight(item.date)).inDays;
final diff = today.difference(toMidnight(item.transaction.date)).inDays;
final balance = differences[diff]!;
differences[diff] = balance + item.amount;
differences[diff] = balance + item.transaction.amount;
}
// Compute the balance
@@ -74,6 +80,7 @@ class AccountBalanceGraphCard extends StatelessWidget {
child: FutureBuilder(
future: getAccountBalance(),
builder: (context, snapshot) {
print("SNAPSHOT: ${snapshot.data}");
if (!snapshot.hasData) {
return CircularProgressIndicator();
}

View File

@@ -1,11 +1,8 @@
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/collections/transaction.dart';
import 'package:okane/database/database.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart';
@@ -45,31 +42,31 @@ class LegendItem extends StatelessWidget {
class BreakdownCard extends StatelessWidget {
const BreakdownCard({super.key});
LegendData _computeSections(List<Transaction> transactions) {
LegendData _computeSections(List<TransactionDto> transactions) {
Map<String, double> expenses = {};
Map<String, Color> colors = {};
double usableMoney = 0;
transactions.forEach((t) {
String category;
if (t.amount > 0) {
if (t.transaction.amount > 0) {
category = CATEGORY_INCOME;
colors[CATEGORY_INCOME] = Colors.green;
} else {
if (t.expenseCategory.value?.name == null) {
if (t.expenseCategory?.name == null) {
category = CATEGORY_OTHER;
colors[category] = Colors.red;
} else {
category = t.expenseCategory.value!.name;
colors[category] = colorHash(t.expenseCategory.value!.name);
category = t.expenseCategory!.name;
colors[category] = colorHash(t.expenseCategory!.name);
}
}
expenses.update(
category,
(value) => value + t.amount.abs(),
ifAbsent: () => t.amount.abs(),
(value) => value + t.transaction.amount.abs(),
ifAbsent: () => t.transaction.amount.abs().toDouble(),
);
usableMoney += t.amount;
usableMoney += t.transaction.amount;
});
return (expenses: expenses, colors: colors, usable: usableMoney);
}
@@ -97,8 +94,13 @@ class BreakdownCard extends StatelessWidget {
);
}
final db = GetIt.I.get<OkaneDatabase>();
return FutureBuilder(
future: getLastTransactions(bloc.activeAccount!, DateTime.now(), 30),
future: db.transactionsDao.getLastTransactions(
bloc.activeAccount!,
DateTime.now(),
30,
),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return _buildCard(

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/collections/account.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
@@ -39,7 +39,7 @@ class DeleteAccountPopup extends StatelessWidget {
)
: Text(
t.pages.accounts.deleteAccount.content(
name: account.name!,
name: account.name,
),
),
actions: [

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:okane/database/database.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart';
@@ -18,7 +19,7 @@ class TotalLoanCard extends StatelessWidget {
child: Padding(
padding: EdgeInsets.all(16),
child: FutureBuilder(
future: getTotalLoanSum(),
future: GetIt.I.get<OkaneDatabase>().loansDao.getTotalLoanSum(),
builder: (context, snapshot) {
return Text(
snapshot.hasData

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:okane/database/collections/account.dart';
import 'package:okane/database/database.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart';
@@ -15,10 +15,13 @@ class TotalBalanceCard extends StatelessWidget {
return 0;
}
final results = await Future.wait(accounts.map(getTotalBalance).toList());
final loanSum = await getTotalLoanSum();
final db = GetIt.I.get<OkaneDatabase>();
final totalBalance = await db.transactionsDao.getTotalBalance(
accounts.map((a) => a.id),
);
return results.reduce((acc, val) => acc + val) + loanSum;
final loanSum = await db.loansDao.getTotalLoanSum();
return totalBalance + loanSum;
}
@override
@@ -32,6 +35,7 @@ class TotalBalanceCard extends StatelessWidget {
child: FutureBuilder(
future: _getTotalBalance(state.accounts),
builder: (context, snapshot) {
print("SNAPSHOT: ${snapshot.data}");
return Text(
snapshot.hasData
? formatCurrency(snapshot.data!)

View File

@@ -1,9 +1,9 @@
import 'dart:math';
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:okane/database/collections/recurrent.dart';
import 'package:okane/database/database.dart';
import 'package:okane/database/sqlite.dart';
import 'package:okane/i18n/strings.g.dart';
import 'package:okane/ui/state/core.dart';
import 'package:okane/ui/utils.dart';
@@ -20,8 +20,10 @@ class UpcomingTransactionsCard extends StatelessWidget {
builder: (context, state) {
final today = DateTime.now();
final upcomingRaw =
state.recurringTransactions.where((t) => t.isDue(today)).toList();
final List<RecurringTransaction> upcoming =
state.recurringTransactions
.where((t) => isTransactionDue(t.recurring, today))
.toList();
final List<RecurringTransactionDto> upcoming =
upcomingRaw.isEmpty
? List.empty()
: upcomingRaw.sublist(0, min(upcomingRaw.length, 3));
@@ -42,9 +44,9 @@ class UpcomingTransactionsCard extends StatelessWidget {
(transaction) => ListTile(
title: Text(
t.pages.accounts.upcomingTransactions.items.title(
name: transaction.template.value!.name,
name: transaction.template.name,
amount:
"${formatCurrency(transaction.template.value!.amount)}",
"${formatCurrency(transaction.template.amount)}",
),
),
subtitle: Text(
@@ -52,17 +54,18 @@ class UpcomingTransactionsCard extends StatelessWidget {
number:
today
.difference(
transaction.lastExecution ?? today,
transaction.recurring.lastExecution ??
today,
)
.inDays,
),
),
leading: Icon(
transaction.template.value!.amount < 0
transaction.template.amount < 0
? Icons.remove
: Icons.add,
color:
transaction.template.value!.amount < 0
transaction.template.amount < 0
? Colors.red
: Colors.green,
),
@@ -74,14 +77,27 @@ class UpcomingTransactionsCard extends StatelessWidget {
builder:
(context) => AddTransactionWidget(
activeAccountItem: bloc.activeAccount!,
template: transaction.template.value!,
template: (
template: transaction.template,
beneficiary: transaction.beneficiary,
expenseCategory: null,
),
onAdd: (newTransaction) async {
// Update the recurring template
transaction.lastExecution =
newTransaction.date;
await upsertRecurringTransaction(
transaction,
);
await GetIt.I
.get<OkaneDatabase>()
.recurringTransactionsDao
.upsertRecurringTransaction(
transaction.recurring
.copyWith(
lastExecution: Value(
newTransaction
.transaction
.date,
),
)
.toCompanion(true),
);
Navigator.of(context).pop();
},
),