Skip to content

Commit

Permalink
Merge pull request #166 from napitek/main
Browse files Browse the repository at this point in the history
CategoryTransactionType for CategoryTransaction model, Charts in GraphsPage
  • Loading branch information
mikev-cw authored Nov 7, 2024
2 parents b9514db + 4c00959 commit 38f623f
Show file tree
Hide file tree
Showing 29 changed files with 1,584 additions and 579 deletions.
3 changes: 2 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ linter:
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

- prefer_relative_imports

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
5 changes: 5 additions & 0 deletions lib/constants/functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ mixin Functions {
return blue3;
}
}

String capitalizeFirstLetter(String word) {
if (word.isEmpty) return word;
return word[0].toUpperCase() + word.substring(1);
}
}
76 changes: 76 additions & 0 deletions lib/custom_widgets/category_type_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../constants/style.dart';
import '../model/category_transaction.dart';
import '../providers/categories_provider.dart';
import '../providers/transactions_provider.dart';

class CategoryTypeButton extends ConsumerWidget {
const CategoryTypeButton({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final categoryType = ref.watch(categoryTypeProvider);
final width = (MediaQuery.of(context).size.width - 64) * 0.5;

BoxDecoration boxDecoration = const BoxDecoration(
color: blue5,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
);

TextStyle textStyleFromType(CategoryTransactionType type) =>
Theme.of(context).textTheme.bodyLarge!.copyWith(color: categoryType == type ? white : blue2);

void onTap(CategoryTransactionType type) {
ref.invalidate(totalAmountProvider);
ref.read(categoryTypeProvider.notifier).state = type;
ref.read(selectedCategoryProvider.notifier).state = null;
}

return Container(
height: 28,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
),
child: Stack(
children: [
AnimatedAlign(
alignment: Alignment((categoryType == CategoryTransactionType.income) ? -1 : 1, 0),
curve: Curves.decelerate,
duration: const Duration(milliseconds: 180),
child: Container(
width: width,
height: 28,
decoration: boxDecoration,
),
),
Align(
alignment: const Alignment(-1, 0),
child: GestureDetector(
onTap: () => onTap(CategoryTransactionType.income),
child: Container(
width: width,
color: Colors.transparent,
alignment: Alignment.center,
child: Text("Income", style: textStyleFromType(CategoryTransactionType.income)),
),
),
),
Align(
alignment: const Alignment(1, 0),
child: GestureDetector(
onTap: () => onTap(CategoryTransactionType.expense),
child: Container(
width: width,
color: Colors.transparent,
alignment: Alignment.center,
child: Text('Expenses', style: textStyleFromType(CategoryTransactionType.expense)),
),
),
),
],
),
);
}
}
17 changes: 10 additions & 7 deletions lib/custom_widgets/transaction_type_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../constants/style.dart';
import '../model/transaction.dart';
import '../pages/transactions_page/widgets/accounts_tab.dart';
import '../pages/transactions_page/widgets/categories_tab.dart';
import '../providers/categories_provider.dart';

final selectedTransactionTypeProvider =
StateProvider.autoDispose<TransactionType>((ref) => TransactionType.income);
final selectedTransactionTypeProvider = StateProvider.autoDispose<TransactionType>((ref) => TransactionType.income);

class TransactionTypeButton extends ConsumerWidget {
const TransactionTypeButton({
Expand Down Expand Up @@ -63,8 +62,10 @@ class TransactionTypeButton extends ConsumerWidget {
alignment: Alignment.center,
child: Text(
"Income",
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: (transactionType == TransactionType.income) ? white : blue2),
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(color: (transactionType == TransactionType.income) ? white : blue2),
),
),
),
Expand All @@ -81,8 +82,10 @@ class TransactionTypeButton extends ConsumerWidget {
alignment: Alignment.center,
child: Text(
'Expenses',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: (transactionType == TransactionType.expense) ? white : blue2),
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(color: (transactionType == TransactionType.expense) ? white : blue2),
),
),
),
Expand Down
95 changes: 64 additions & 31 deletions lib/database/sossoldi_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class SossoldiDatabase {
static String dbName = 'sossoldi.db';

// Zero args constructor needed to extend this class
SossoldiDatabase({String? dbName}){
SossoldiDatabase({String? dbName}) {
dbName = dbName ?? 'sossoldi.db';
}

Expand Down Expand Up @@ -103,6 +103,7 @@ class SossoldiDatabase {
CREATE TABLE `$categoryTransactionTable`(
`${CategoryTransactionFields.id}` $integerPrimaryKeyAutoincrement,
`${CategoryTransactionFields.name}` $textNotNull,
`${CategoryTransactionFields.type}` $textNotNull,
`${CategoryTransactionFields.symbol}` $textNotNull,
`${CategoryTransactionFields.color}` $integerNotNull,
`${CategoryTransactionFields.note}` $text,
Expand Down Expand Up @@ -135,7 +136,6 @@ class SossoldiDatabase {
`${CurrencyFields.mainCurrency}` $integerNotNull CHECK (${CurrencyFields.mainCurrency} IN (0, 1))
)
''');

}

Future fillDemoData({int countOfGeneratedTransaction = 10000}) async {
Expand All @@ -149,14 +149,15 @@ class SossoldiDatabase {

// Add fake categories
await _database?.execute('''
INSERT INTO categoryTransaction(id, name, symbol, color, note, parent, createdAt, updatedAt) VALUES
(10, "Out", "restaurant", 0, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(11, "Home", "home", 1, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(12, "Furniture", "home", 2, '', 11, '${DateTime.now()}', '${DateTime.now()}'),
(13, "Shopping", "shopping_cart", 3, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(14, "Leisure", "subscriptions", 4, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(15, "Salary", "work", 5, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(16, "Transports", "directions_car_rounded", 6, '', null, '${DateTime.now()}', '${DateTime.now()}');
INSERT INTO categoryTransaction(id, name, type, symbol, color, note, parent, createdAt, updatedAt) VALUES
(10, "Out", "OUT", "restaurant", 0, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(11, "Home", "OUT", "home", 1, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(12, "Furniture","OUT", "home", 2, '', 11, '${DateTime.now()}', '${DateTime.now()}'),
(13, "Shopping", "OUT", "shopping_cart", 3, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(14, "Leisure", "OUT", "subscriptions", 4, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(15, "Transports", "OUT", "directions_car_rounded", 6, '', null, '${DateTime.now()}', '${DateTime.now()}'),
(16, "Salary", "IN", "work", 5, '', null, '${DateTime.now()}', '${DateTime.now()}');
''');

// Add currencies
Expand All @@ -180,22 +181,45 @@ class SossoldiDatabase {
INSERT INTO recurringTransaction(fromDate, toDate, amount, note, recurrency, idCategory, idBankAccount, createdAt, updatedAt) VALUES
("2024-02-23", null, 10.99, "404 Books", "MONTHLY", 14, 70, '${DateTime.now()}', '${DateTime.now()}'),
("2023-12-13", null, 4.97, "ETF Consultant Parcel", "DAILY", 14, 70, '${DateTime.now()}', '${DateTime.now()}'),
("2023-02-11", "2028-02-11", 1193.40, "Car Loan", "QUARTERLY", 16, 72, '${DateTime.now()}', '${DateTime.now()}');
("2023-02-11", "2028-02-11", 1193.40, "Car Loan", "QUARTERLY", 15, 72, '${DateTime.now()}', '${DateTime.now()}');
''');

// Add fake transactions
// First initialize some config stuff
final rnd = Random();
var accounts = [70,71,72];
var outNotes = ['Grocery', 'Tolls', 'Toys', 'Boardgames', 'Concert', 'Clothing', 'Pizza', 'Drugs', 'Laundry', 'Taxes', 'Health insurance', 'Furniture', 'Car Fuel', 'Train', 'Amazon', 'Delivery', 'CHEK dividends', 'Babysitter', 'sono.pove.ro Fees', 'Quingentole trip'];
var categories = [10,11,12,13,14];
var accounts = [70, 71, 72];
var outNotes = [
'Grocery',
'Tolls',
'Toys',
'Boardgames',
'Concert',
'Clothing',
'Pizza',
'Drugs',
'Laundry',
'Taxes',
'Health insurance',
'Furniture',
'Car Fuel',
'Train',
'Amazon',
'Delivery',
'CHEK dividends',
'Babysitter',
'sono.pove.ro Fees',
'Quingentole trip'
];
var categories = [10, 11, 12, 13, 14];
double maxAmountOfSingleTransaction = 250.00;
int dateInPastMaxRange = (countOfGeneratedTransaction / 90 ).round() * 30; // we want simulate about 90 transactions per month
int dateInPastMaxRange = (countOfGeneratedTransaction / 90).round() *
30; // we want simulate about 90 transactions per month
num fakeSalary = 5000;
DateTime now = DateTime.now();

// start building mega-query
const insertDemoTransactionsQuery = '''INSERT INTO `transaction` (date, amount, type, note, idCategory, idBankAccount, idBankAccountTransfer, recurring, idRecurringTransaction, createdAt, updatedAt) VALUES ''';
const insertDemoTransactionsQuery =
'''INSERT INTO `transaction` (date, amount, type, note, idCategory, idBankAccount, idBankAccountTransfer, recurring, idRecurringTransaction, createdAt, updatedAt) VALUES ''';

// init a List with transaction values
final List<String> demoTransactions = [];
Expand All @@ -208,24 +232,29 @@ class SossoldiDatabase {
if (rnd.nextInt(10) < 8) {
randomAmount = rnd.nextDouble() * (19.99 - 1) + 1;
} else {
randomAmount = rnd.nextDouble() * (maxAmountOfSingleTransaction - 100) + 100;
randomAmount =
rnd.nextDouble() * (maxAmountOfSingleTransaction - 100) + 100;
}

var randomType = 'OUT';
var randomAccount = accounts[rnd.nextInt(accounts.length)];
var randomNote = outNotes[rnd.nextInt(outNotes.length)];
var randomCategory = categories[rnd.nextInt(categories.length)];
var idBankAccountTransfer;
DateTime randomDate = now.subtract(Duration(days: rnd.nextInt(dateInPastMaxRange), hours: rnd.nextInt(20), minutes: rnd.nextInt(50)));
DateTime randomDate = now.subtract(Duration(
days: rnd.nextInt(dateInPastMaxRange),
hours: rnd.nextInt(20),
minutes: rnd.nextInt(50)));

if (i % (countOfGeneratedTransaction/100) == 0) {
if (i % (countOfGeneratedTransaction / 100) == 0) {
// simulating a transfer every 1% of total iterations
randomType = 'TRSF';
randomNote = 'Transfer';
randomAccount = 70; // sender account is hardcoded with the one that receives our fake salary
randomAccount =
70; // sender account is hardcoded with the one that receives our fake salary
randomCategory = 0; // no category for transfers
idBankAccountTransfer = accounts[rnd.nextInt(accounts.length)];
randomAmount = (fakeSalary/100)*70;
randomAmount = (fakeSalary / 100) * 70;

// be sure our FROM/TO accounts are not the same
while (idBankAccountTransfer == randomAccount) {
Expand All @@ -234,24 +263,28 @@ class SossoldiDatabase {
}

// put generated transaction in our list
demoTransactions.add('''('$randomDate', ${randomAmount.toStringAsFixed(2)}, '$randomType', '$randomNote', $randomCategory, $randomAccount, $idBankAccountTransfer, 0, null, '$randomDate', '$randomDate')''');
demoTransactions.add(
'''('$randomDate', ${randomAmount.toStringAsFixed(2)}, '$randomType', '$randomNote', $randomCategory, $randomAccount, $idBankAccountTransfer, 0, null, '$randomDate', '$randomDate')''');
}

// add salary every month
for (int i = 1; i < dateInPastMaxRange/30; i++) {
DateTime randomDate = now.subtract(Duration(days: 30*i));
for (int i = 1; i < dateInPastMaxRange / 30; i++) {
DateTime randomDate = now.subtract(Duration(days: 30 * i));
var time = randomDate.toLocal();
DateTime salaryDateTime = DateTime(time.year, time.month, 27, time.hour, time.minute, time.second, time.millisecond, time.microsecond);
demoTransactions.add('''('$salaryDateTime', $fakeSalary, 'IN', 'Salary', 15, 70, null, 0, null, '$salaryDateTime', '$salaryDateTime')''');
DateTime salaryDateTime = DateTime(time.year, time.month, 27, time.hour,
time.minute, time.second, time.millisecond, time.microsecond);
demoTransactions.add(
'''('$salaryDateTime', $fakeSalary, 'IN', 'Salary', 16, 70, null, 0, null, '$salaryDateTime', '$salaryDateTime')''');
}

// finalize query and write!
await _database?.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};");
await _database?.execute(
"$insertDemoTransactionsQuery ${demoTransactions.join(",")};");
}

Future resetDatabase() async {
// delete database
try{
try {
await _database?.transaction((txn) async {
var batch = txn.batch();
// drop tables
Expand All @@ -263,14 +296,14 @@ class SossoldiDatabase {
batch.execute('DROP TABLE IF EXISTS $currencyTable');
await batch.commit();
});
} catch(error){
} catch (error) {
throw Exception('DbBase.resetDatabase: $error');
}
await _createDB(_database!, 1);
}

Future clearDatabase() async {
try{
try {
await _database?.transaction((txn) async {
var batch = txn.batch();
batch.delete(bankAccountTable);
Expand All @@ -281,7 +314,7 @@ class SossoldiDatabase {
batch.delete(currencyTable);
await batch.commit();
});
} catch(error){
} catch (error) {
throw Exception('DbBase.cleanDatabase: $error');
}
}
Expand Down
Loading

0 comments on commit 38f623f

Please sign in to comment.