Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.0.28 - Make transactions clickable #28

Merged
merged 9 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<a href="https://flutter.dev/" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Platform-Flutter%203.16.5-blue">
</a>
<a href="https://github.com/Donnie/Finease/releases/tag/v1.0.27" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Version-1.0.27-orange">
<a href="https://github.com/Donnie/Finease/releases/tag/v1.0.28" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Version-1.0.28-orange">
</a>
<a href="https://github.com/Donnie/Finease/actions/workflows/android_release.yml" style="text-decoration:none" area-label="flutter">
<img src="https://github.com/Donnie/Finease/actions/workflows/android_release.yml/badge.svg">
Expand Down
38 changes: 18 additions & 20 deletions lib/core/extensions/color_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,30 @@ import 'package:flutter/material.dart';

extension ColorHelper on BuildContext {
ColorScheme get colorScheme => Theme.of(this).colorScheme;
Color get outline => colorScheme.outline;
Color get outlineVariant => colorScheme.outlineVariant;
Color get primary => colorScheme.primary;
Color get error => colorScheme.error;
Color get errorContainer => colorScheme.errorContainer;
Color get inverseSurface => colorScheme.inverseSurface;
Color get onError => colorScheme.onError;
Color get onErrorContainer => colorScheme.onErrorContainer;
Color get onInverseSurface => colorScheme.onInverseSurface;
Color get onPrimary => colorScheme.onPrimary;
Color get primaryContainer => colorScheme.primaryContainer;
Color get onPrimaryContainer => colorScheme.onPrimaryContainer;
Color get secondary => colorScheme.secondary;
Color get onSecondary => colorScheme.onSecondary;
Color get inverseSurface => colorScheme.inverseSurface;
Color get onInverseSurface => colorScheme.onInverseSurface;
Color get secondaryContainer => colorScheme.secondaryContainer;
Color get onSecondaryContainer => colorScheme.onSecondaryContainer;
Color get onSurface => colorScheme.onSurface;
Color get onSurfaceVariant => colorScheme.onSurfaceVariant;
Color get onTertiary => colorScheme.tertiary;
Color get tertiary => colorScheme.onTertiary;
Color get tertiaryContainer => colorScheme.tertiaryContainer;
Color get onTertiaryContainer => colorScheme.onTertiaryContainer;
Color get surfaceVariant => colorScheme.surfaceVariant;
Color get onSurfaceVariant => colorScheme.onSurfaceVariant;
Color get outline => colorScheme.outline;
Color get outlineVariant => colorScheme.outlineVariant;
Color get primary => colorScheme.primary;
Color get primaryContainer => colorScheme.primaryContainer;
Color get secondary => colorScheme.secondary;
Color get secondaryContainer => colorScheme.secondaryContainer;
Color get shadow => colorScheme.shadow;
Color get surface => colorScheme.surface;
Color get onSurface => colorScheme.onSurface;
Color get surfaceTint => colorScheme.surfaceTint;
Color get background => colorScheme.background;
Color get onBackground => colorScheme.onBackground;
Color get error => colorScheme.error;
Color get shadow => colorScheme.shadow;
Color get errorContainer => colorScheme.errorContainer;
Color get onError => colorScheme.onError;
Color get onErrorContainer => colorScheme.onErrorContainer;
Color get surfaceVariant => colorScheme.surfaceContainerHighest;
Color get tertiary => colorScheme.onTertiary;
Color get tertiaryContainer => colorScheme.tertiaryContainer;
}
12 changes: 11 additions & 1 deletion lib/db/entries.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,18 @@ class EntryService {
where: 'id = ?',
whereArgs: [id],
);

if (entries.isNotEmpty) {
return Entry.fromJson(entries.first);
Entry entry = Entry.fromJson(entries.first);
final List<Account> allAccounts = await AccountService().getAllAccounts();

// Create a map for quick account lookup by ID
var accountsMap = {for (var account in allAccounts) account.id: account};

entry.creditAccount = accountsMap[entry.creditAccountId];
entry.debitAccount = accountsMap[entry.debitAccountId];

return entry;
}
return null;
}
Expand Down
37 changes: 37 additions & 0 deletions lib/db/migrations/d_update_trigger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:sqflite/sqflite.dart';

// Deciding not to go ahead with this
// as it would be a malpractice to update accounts
// or amounts in purely financial terms

Future<void> dUpdateEntriesTrigger(Database db) async {
await db.execute('''
CREATE TRIGGER UpdateAccountBalanceAfterUpdate
AFTER UPDATE ON Entries
WHEN (SELECT currency FROM Accounts WHERE id = OLD.debit_account_id) =
(SELECT currency FROM Accounts WHERE id = OLD.credit_account_id) AND
(SELECT currency FROM Accounts WHERE id = NEW.debit_account_id) =
(SELECT currency FROM Accounts WHERE id = NEW.credit_account_id)
BEGIN
-- Adjust the balance for the old debit account
UPDATE Accounts
SET balance = balance + OLD.amount
WHERE id = OLD.debit_account_id;

-- Adjust the balance for the old credit account
UPDATE Accounts
SET balance = balance - OLD.amount
WHERE id = OLD.credit_account_id;

-- Adjust the balance for the new debit account
UPDATE Accounts
SET balance = balance - NEW.amount
WHERE id = NEW.debit_account_id;

-- Adjust the balance for the new credit account
UPDATE Accounts
SET balance = balance + NEW.amount
WHERE id = NEW.credit_account_id;
END;
''');
}
2 changes: 1 addition & 1 deletion lib/pages/add_account/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AddAccountScreenState extends State<AddAccountScreen> {
@override
Widget build(BuildContext context) {
return AppAnnotatedRegionWidget(
color: context.background,
color: context.surface,
child: Scaffold(
appBar: AppBar(title: const Text('add account')),
body: AddAccountBody(
Expand Down
88 changes: 88 additions & 0 deletions lib/pages/edit_entry/entry_body.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:finease/db/accounts.dart';
import 'package:finease/db/currency.dart';
import 'package:finease/pages/export.dart';
import 'package:flutter/material.dart';

class EditEntryBody extends StatefulWidget {
const EditEntryBody({
super.key,
required this.creditAccount,
required this.debitAccount,
required this.dateTime,
required this.onDateTimeChanged,
required this.entryAmount,
required this.entryNotes,
required this.formState,
});

final Account creditAccount;
final Account debitAccount;
final DateTime dateTime;
final GlobalKey<FormState> formState;
final String entryAmount;
final TextEditingController entryNotes;
final ValueChanged<DateTime> onDateTimeChanged;

@override
EditEntryBodyState createState() => EditEntryBodyState();
}

class EditEntryBodyState extends State<EditEntryBody> {
@override
Widget build(BuildContext context) {
final String debitCurrencyISO = widget.debitAccount.currency;
final String debitCurrency = SupportedCurrency[debitCurrencyISO]!;

return Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: widget.formState,
child: ListView(
children: [
AccountChoiceFormField(
key: const Key('from_account'),
title: "From Account",
accounts: [widget.debitAccount],
selectedAccount: widget.debitAccount,
),
AccountChoiceFormField(
key: const Key('to_account'),
title: "To Account",
accounts: [widget.creditAccount],
selectedAccount: widget.creditAccount,
),
const SizedBox(height: 32),
TextFormField(
key: const Key('entry_notes'),
controller: widget.entryNotes,
decoration: const InputDecoration(
hintText: 'Enter transaction notes',
label: Text('Enter transaction notes'),
),
keyboardType: TextInputType.text,
),
const SizedBox(height: 16),
TextFormField(
key: const Key('entry_amount'),
initialValue: widget.entryAmount,
decoration: InputDecoration(
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 12, right: 4),
child: Text(debitCurrency),
),
prefixIconConstraints:
const BoxConstraints(minWidth: 0, minHeight: 0),
),
enabled: false,
),
const SizedBox(height: 16),
DateTimePicker(
dateTime: widget.dateTime,
onDateTimeChanged: widget.onDateTimeChanged,
),
],
),
),
);
}
}
95 changes: 95 additions & 0 deletions lib/pages/edit_entry/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:finease/db/accounts.dart';
import 'package:finease/db/entries.dart';
import 'package:finease/pages/edit_entry/entry_body.dart';
import 'package:finease/parts/export.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class EditEntryScreen extends StatefulWidget {
final Function() onFormSubmitted;
final int entryID;

const EditEntryScreen({
super.key,
required this.entryID,
required this.onFormSubmitted,
});

@override
EditEntryScreenState createState() => EditEntryScreenState();
}

class EditEntryScreenState extends State<EditEntryScreen> {
final EntryService _entryService = EntryService();

final _formState = GlobalKey<FormState>();
final _entryNotes = TextEditingController();
Entry? _entry;
DateTime? _entryDate;
Account? _creditAccount;
Account? _debitAccount;

@override
void initState() {
super.initState();
loadEntry(widget.entryID);
}

Future<void> loadEntry(int id) async {
Entry? entry = await _entryService.getEntry(id);
setState(() {
_entry = entry!;
_entryDate = entry.date;
_creditAccount = entry.creditAccount;
_debitAccount = entry.debitAccount;
_entryNotes.text = entry.notes ?? '';
});
}

@override
Widget build(BuildContext context) {
if (_entry == null) {
return Container();
}
return Scaffold(
appBar: AppBar(title: const Text('Edit Transaction')),
body: EditEntryBody(
creditAccount: _creditAccount!,
dateTime: _entryDate!,
debitAccount: _debitAccount!,
entryAmount: _entry!.amount.toString(),
entryNotes: _entryNotes,
formState: _formState,
onDateTimeChanged: _onDateTimeChanged,
),
// body: const Card(),
bottomNavigationBar: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: AppBigButton(
onPressed: _submitForm,
title: "Save",
),
),
),
);
}

void _onDateTimeChanged(DateTime dateTime) {
setState(() {
_entryDate = dateTime;
});
}

Future<void> _submitForm() async {
String entryNotes = _entryNotes.text;
if (_formState.currentState?.validate() ?? false) {
context.pop();
_entry!.date = _entryDate ?? _entry!.date;
_entry!.notes = entryNotes;
await _entryService.updateEntry(_entry!);
widget.onFormSubmitted();
}
}
}

13 changes: 7 additions & 6 deletions lib/pages/export.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ export "add_account/main.dart";
export "add_entry/date_time.dart";
export "add_entry/entry_body.dart";
export "add_entry/main.dart";
export 'add_info/widget.dart';
export 'add_info/main.dart';
export "add_info/main.dart";
export "add_info/widget.dart";
export "edit_account/account_body.dart";
export "edit_account/main.dart";
export "edit_entry/main.dart";
export "home/accounts/account_card.dart";
export "home/accounts/main.dart";
export "home/entries/entry_card.dart";
Expand All @@ -15,10 +16,10 @@ export "home/frame/destinations.dart";
export "home/frame/main.dart";
export "home/frame/mobile.dart";
export "home/frame/tablet.dart";
export 'home/months/main.dart';
export 'home/months/month_card.dart';
export 'home/summary/main.dart';
export 'home/summary/widgets.dart';
export "home/months/main.dart";
export "home/months/month_card.dart";
export "home/summary/main.dart";
export "home/summary/widgets.dart";
export "intro/intro_big.dart";
export "intro/intro_mobile.dart";
export "intro/intro_page.dart";
Expand Down
Loading