2023-09-08 11:50:21 +02:00
|
|
|
import 'package:currency_picker/currency_picker.dart';
|
2024-01-08 21:19:15 +01:00
|
|
|
import 'package:intl/intl.dart';
|
2023-09-08 11:50:21 +02:00
|
|
|
import 'package:json_annotation/json_annotation.dart';
|
2024-01-08 23:22:35 +01:00
|
|
|
import 'package:logger/logger.dart';
|
2023-09-08 11:50:21 +02:00
|
|
|
import 'package:prasule/api/category.dart';
|
2024-01-08 21:19:15 +01:00
|
|
|
import 'package:prasule/api/recurring_entry.dart';
|
|
|
|
import 'package:prasule/api/wallet_entry.dart';
|
|
|
|
import 'package:prasule/api/wallet_manager.dart';
|
|
|
|
import 'package:prasule/main.dart';
|
2023-09-08 11:50:21 +02:00
|
|
|
part 'wallet.g.dart';
|
|
|
|
|
|
|
|
Currency _currencyFromJson(Map<String, dynamic> data) =>
|
|
|
|
Currency.from(json: data);
|
|
|
|
|
2023-12-29 21:39:54 +01:00
|
|
|
/// Represents a single wallet
|
|
|
|
///
|
|
|
|
/// A wallet stores [WalletSingleEntry]s categorized under [WalletCategory]s
|
2023-09-08 11:50:21 +02:00
|
|
|
@JsonSerializable()
|
|
|
|
class Wallet {
|
2023-12-29 21:39:54 +01:00
|
|
|
/// A wallet stores [WalletSingleEntry]s categorized under [WalletCategory]s
|
2023-12-31 12:41:10 +01:00
|
|
|
Wallet({
|
|
|
|
required this.name,
|
|
|
|
required this.currency,
|
|
|
|
this.categories = const [],
|
|
|
|
this.entries = const [],
|
2024-01-08 21:19:15 +01:00
|
|
|
this.recurringEntries = const [],
|
2023-12-31 12:41:10 +01:00
|
|
|
this.starterBalance = 0,
|
|
|
|
});
|
2023-09-08 11:50:21 +02:00
|
|
|
|
2023-12-31 12:41:10 +01:00
|
|
|
/// Connects generated fromJson method
|
2023-09-08 11:50:21 +02:00
|
|
|
factory Wallet.fromJson(Map<String, dynamic> json) => _$WalletFromJson(json);
|
|
|
|
|
2024-01-08 21:19:15 +01:00
|
|
|
/// A list of all [RecurringWalletEntry]s
|
|
|
|
final List<RecurringWalletEntry> recurringEntries;
|
|
|
|
|
2023-12-29 21:39:54 +01:00
|
|
|
/// Name of the wallet
|
|
|
|
final String name;
|
|
|
|
|
|
|
|
/// A list of available categories
|
|
|
|
final List<WalletCategory> categories;
|
|
|
|
|
|
|
|
/// List of saved entries
|
|
|
|
final List<WalletSingleEntry> entries;
|
|
|
|
|
|
|
|
/// The starting balance of the wallet
|
|
|
|
///
|
|
|
|
/// Used to calculate current balance
|
|
|
|
double starterBalance;
|
|
|
|
|
|
|
|
/// Selected currency
|
|
|
|
@JsonKey(fromJson: _currencyFromJson)
|
|
|
|
final Currency currency;
|
|
|
|
|
2023-12-31 12:41:10 +01:00
|
|
|
/// Connects generated toJson method
|
2023-09-08 11:50:21 +02:00
|
|
|
Map<String, dynamic> toJson() => _$WalletToJson(this);
|
2023-11-01 17:58:05 +01:00
|
|
|
|
2023-12-31 12:41:10 +01:00
|
|
|
/// Getter for the next unused unique number ID in the wallet's **entry** list
|
2023-11-01 17:58:05 +01:00
|
|
|
int get nextId {
|
|
|
|
var id = 1;
|
2024-01-08 23:22:35 +01:00
|
|
|
logger.d("Making ID after ${entries.length} entries");
|
2023-11-01 17:58:05 +01:00
|
|
|
while (entries.where((element) => element.id == id).isNotEmpty) {
|
|
|
|
id++; // create unique ID
|
|
|
|
}
|
2024-01-08 23:22:35 +01:00
|
|
|
logger.d("New ID: $id\nLast entry ID: ${entries.lastOrNull?.id}");
|
2023-11-01 17:58:05 +01:00
|
|
|
return id;
|
|
|
|
}
|
2023-11-21 20:23:14 +01:00
|
|
|
|
2023-12-31 12:41:10 +01:00
|
|
|
/// Getter for the next unused unique number ID in the wallet's **category**
|
|
|
|
/// list
|
|
|
|
int get nextCategoryId {
|
|
|
|
var id = 0;
|
|
|
|
while (categories.where((element) => element.id == id).isNotEmpty) {
|
|
|
|
id++; // create unique ID
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2024-01-08 21:19:15 +01:00
|
|
|
/// Handles adding recurring entries to the entry list
|
|
|
|
void recurEntries() {
|
|
|
|
final n = DateTime.now();
|
|
|
|
for (final ent in recurringEntries) {
|
|
|
|
var m = DateTime(
|
|
|
|
(ent.recurType == RecurType.year)
|
|
|
|
? ent.lastRunDate.year + ent.repeatAfter
|
|
|
|
: ent.lastRunDate.year,
|
|
|
|
(ent.recurType == RecurType.month)
|
|
|
|
? ent.lastRunDate.month + ent.repeatAfter
|
|
|
|
: ent.lastRunDate.month,
|
|
|
|
(ent.recurType == RecurType.day)
|
|
|
|
? ent.lastRunDate.day + ent.repeatAfter
|
|
|
|
: ent.lastRunDate.day,
|
|
|
|
); // create the date after which we should recur
|
|
|
|
|
|
|
|
while (n.isAfter(
|
|
|
|
m,
|
|
|
|
)) {
|
2024-01-08 23:22:35 +01:00
|
|
|
logger
|
|
|
|
..i("Adding recurring entry ${ent.data.name}")
|
|
|
|
..d("Current entry count: ${entries.length}");
|
2024-01-08 21:19:15 +01:00
|
|
|
recurringEntries[recurringEntries.indexOf(ent)].lastRunDate =
|
|
|
|
m; // update date on recurring entry
|
|
|
|
logger.i(recurringEntries[recurringEntries.indexOf(ent)].lastRunDate);
|
2024-01-08 23:22:35 +01:00
|
|
|
|
|
|
|
var id = 1;
|
|
|
|
logger.d("Making ID after ${entries.length} entries");
|
|
|
|
while (entries.where((element) => element.id == id).isNotEmpty) {
|
|
|
|
id++; // create unique ID
|
|
|
|
}
|
|
|
|
logger.d("New ID: $id\nLast entry ID: ${entries.lastOrNull?.id}");
|
|
|
|
|
|
|
|
final addedEntry = WalletSingleEntry(
|
|
|
|
data: recurringEntries[recurringEntries.indexOf(ent)].data,
|
|
|
|
type: recurringEntries[recurringEntries.indexOf(ent)].type,
|
|
|
|
date: m,
|
|
|
|
category: recurringEntries[recurringEntries.indexOf(ent)].category,
|
|
|
|
id: id,
|
|
|
|
);
|
|
|
|
|
|
|
|
entries.add(addedEntry);
|
2024-01-08 21:19:15 +01:00
|
|
|
|
|
|
|
m = DateTime(
|
|
|
|
(ent.recurType == RecurType.year)
|
2024-01-08 23:22:35 +01:00
|
|
|
? recurringEntries[recurringEntries.indexOf(ent)]
|
|
|
|
.lastRunDate
|
|
|
|
.year +
|
|
|
|
ent.repeatAfter
|
|
|
|
: recurringEntries[recurringEntries.indexOf(ent)]
|
|
|
|
.lastRunDate
|
|
|
|
.year,
|
2024-01-08 21:19:15 +01:00
|
|
|
(ent.recurType == RecurType.month)
|
2024-01-08 23:22:35 +01:00
|
|
|
? recurringEntries[recurringEntries.indexOf(ent)]
|
|
|
|
.lastRunDate
|
|
|
|
.month +
|
|
|
|
ent.repeatAfter
|
|
|
|
: recurringEntries[recurringEntries.indexOf(ent)]
|
|
|
|
.lastRunDate
|
|
|
|
.month,
|
2024-01-08 21:19:15 +01:00
|
|
|
(ent.recurType == RecurType.day)
|
2024-01-08 23:22:35 +01:00
|
|
|
? recurringEntries[recurringEntries.indexOf(ent)]
|
|
|
|
.lastRunDate
|
|
|
|
.day +
|
|
|
|
ent.repeatAfter
|
|
|
|
: recurringEntries[recurringEntries.indexOf(ent)].lastRunDate.day,
|
|
|
|
); // add the variable again to check if we aren't missing any entries
|
2024-01-08 21:19:15 +01:00
|
|
|
logger.i(
|
|
|
|
"Last recurred date is now on ${DateFormat.yMMMMd().format(m)} (${n.isAfter(m)})");
|
|
|
|
}
|
|
|
|
WalletManager.saveWallet(this); // save wallet
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 12:41:10 +01:00
|
|
|
/// Removes the specified category.
|
|
|
|
///
|
|
|
|
/// All [WalletSingleEntry]s will have their category reassigned
|
|
|
|
/// to the default *No category*
|
|
|
|
Future<void> removeCategory(WalletCategory category) async {
|
|
|
|
// First remove the category from existing entries
|
|
|
|
for (final entryToChange
|
|
|
|
in entries.where((element) => element.category.id == category.id)) {
|
|
|
|
entryToChange.category =
|
|
|
|
categories.where((element) => element.id == 0).first;
|
|
|
|
}
|
|
|
|
// Remove the category
|
|
|
|
categories.removeWhere((element) => element.id == category.id);
|
|
|
|
// Save
|
|
|
|
await WalletManager.saveWallet(this);
|
|
|
|
}
|
|
|
|
|
2023-12-29 21:39:54 +01:00
|
|
|
/// Empty wallet used for placeholders
|
2023-11-21 20:23:14 +01:00
|
|
|
static final Wallet empty = Wallet(
|
|
|
|
name: "Empty",
|
|
|
|
currency: Currency.from(
|
|
|
|
json: {
|
|
|
|
"code": "USD",
|
|
|
|
"name": "United States Dollar",
|
2023-12-29 21:39:54 +01:00
|
|
|
"symbol": r"$",
|
2023-11-21 20:23:14 +01:00
|
|
|
"flag": "USD",
|
|
|
|
"decimal_digits": 2,
|
|
|
|
"number": 840,
|
|
|
|
"name_plural": "US dollars",
|
|
|
|
"thousands_separator": ",",
|
|
|
|
"decimal_separator": ".",
|
|
|
|
"space_between_amount_and_symbol": false,
|
|
|
|
"symbol_on_left": true,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
2023-09-08 11:50:21 +02:00
|
|
|
}
|