Compare commits
No commits in common. "b621133c2405c753ec993a1a5b42fa37a755ca0b" and "741fb1f11a670df18cdb4cfd5fa8fd82e02df2b0" have entirely different histories.
b621133c24
...
741fb1f11a
5 changed files with 31 additions and 100 deletions
|
@ -5,7 +5,6 @@
|
||||||
- Categories now have changeable colors assigned to them
|
- Categories now have changeable colors assigned to them
|
||||||
- Added pie chart for expense/income data per category
|
- Added pie chart for expense/income data per category
|
||||||
- Added recurring entries
|
- Added recurring entries
|
||||||
- Fixed wrong default sorting
|
|
||||||
# 1.0.0-alpha+2
|
# 1.0.0-alpha+2
|
||||||
- Fixed localization issues
|
- Fixed localization issues
|
||||||
- Added graphs for expenses and income per month/year
|
- Added graphs for expenses and income per month/year
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import 'package:currency_picker/currency_picker.dart';
|
import 'package:currency_picker/currency_picker.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:prasule/api/category.dart';
|
import 'package:prasule/api/category.dart';
|
||||||
import 'package:prasule/api/recurring_entry.dart';
|
import 'package:prasule/api/recurring_entry.dart';
|
||||||
import 'package:prasule/api/wallet_entry.dart';
|
import 'package:prasule/api/wallet_entry.dart';
|
||||||
import 'package:prasule/api/wallet_manager.dart';
|
import 'package:prasule/api/wallet_manager.dart';
|
||||||
import 'package:prasule/main.dart';
|
|
||||||
part 'wallet.g.dart';
|
part 'wallet.g.dart';
|
||||||
|
|
||||||
Currency _currencyFromJson(Map<String, dynamic> data) =>
|
Currency _currencyFromJson(Map<String, dynamic> data) =>
|
||||||
|
@ -72,56 +70,6 @@ class Wallet {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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,
|
|
||||||
)) {
|
|
||||||
logger.i("Adding recurring entry ${ent.data.name}");
|
|
||||||
recurringEntries[recurringEntries.indexOf(ent)].lastRunDate =
|
|
||||||
m; // update date on recurring entry
|
|
||||||
logger.i(recurringEntries[recurringEntries.indexOf(ent)].lastRunDate);
|
|
||||||
final addedEntry = (recurringEntries[recurringEntries.indexOf(ent)]
|
|
||||||
as WalletSingleEntry)
|
|
||||||
..date = DateTime.now()
|
|
||||||
..id = nextId; // copy entry with today's date and unique ID
|
|
||||||
entries.add(
|
|
||||||
addedEntry,
|
|
||||||
); // add it to entries
|
|
||||||
|
|
||||||
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,
|
|
||||||
); // add tne variable again to check if we aren't missing any entries
|
|
||||||
logger.i(
|
|
||||||
"Last recurred date is now on ${DateFormat.yMMMMd().format(m)} (${n.isAfter(m)})");
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletManager.saveWallet(this); // save wallet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the specified category.
|
/// Removes the specified category.
|
||||||
///
|
///
|
||||||
/// All [WalletSingleEntry]s will have their category reassigned
|
/// All [WalletSingleEntry]s will have their category reassigned
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
@ -10,6 +11,7 @@ import 'package:prasule/api/wallet_manager.dart';
|
||||||
import 'package:prasule/main.dart';
|
import 'package:prasule/main.dart';
|
||||||
import 'package:prasule/pw/platformbutton.dart';
|
import 'package:prasule/pw/platformbutton.dart';
|
||||||
import 'package:prasule/pw/platformfield.dart';
|
import 'package:prasule/pw/platformfield.dart';
|
||||||
|
import 'package:prasule/util/text_color.dart';
|
||||||
|
|
||||||
/// Used when user wants to add new entry
|
/// Used when user wants to add new entry
|
||||||
class CreateRecurringEntryView extends StatefulWidget {
|
class CreateRecurringEntryView extends StatefulWidget {
|
||||||
|
@ -223,10 +225,6 @@ class _CreateRecurringEntryViewState extends State<CreateRecurringEntryView> {
|
||||||
RegExp(r"^0$"),
|
RegExp(r"^0$"),
|
||||||
replacementString: "1",
|
replacementString: "1",
|
||||||
),
|
),
|
||||||
FilteringTextInputFormatter.deny(
|
|
||||||
r"\d+[\.,]{0,1}\d{0,}",
|
|
||||||
replacementString: "1",
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
onChanged: (s) {
|
onChanged: (s) {
|
||||||
final n = int.tryParse(s);
|
final n = int.tryParse(s);
|
||||||
|
@ -292,7 +290,28 @@ class _CreateRecurringEntryViewState extends State<CreateRecurringEntryView> {
|
||||||
PlatformButton(
|
PlatformButton(
|
||||||
text: DateFormat.yMMMMd(widget.locale)
|
text: DateFormat.yMMMMd(widget.locale)
|
||||||
.format(newEntry.lastRunDate),
|
.format(newEntry.lastRunDate),
|
||||||
|
style: (widget.editEntry != null)
|
||||||
|
? ButtonStyle(
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
Colors.grey.harmonizeWith(
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
foregroundColor: MaterialStateProperty.all(
|
||||||
|
Colors.grey
|
||||||
|
.harmonizeWith(
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
)
|
||||||
|
.calculateTextColor()
|
||||||
|
.harmonizeWith(
|
||||||
|
Theme.of(context).colorScheme.primary),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
if (widget.editEntry != null) {
|
||||||
|
return; // disabled on edit
|
||||||
|
}
|
||||||
final d = await showDatePicker(
|
final d = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
firstDate: DateTime.now(),
|
firstDate: DateTime.now(),
|
||||||
|
|
|
@ -15,7 +15,6 @@ import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:prasule/api/category.dart';
|
import 'package:prasule/api/category.dart';
|
||||||
import 'package:prasule/api/entry_data.dart';
|
import 'package:prasule/api/entry_data.dart';
|
||||||
import 'package:prasule/api/recurring_entry.dart';
|
|
||||||
import 'package:prasule/api/wallet.dart';
|
import 'package:prasule/api/wallet.dart';
|
||||||
import 'package:prasule/api/wallet_entry.dart';
|
import 'package:prasule/api/wallet_entry.dart';
|
||||||
import 'package:prasule/api/wallet_manager.dart';
|
import 'package:prasule/api/wallet_manager.dart';
|
||||||
|
@ -68,7 +67,6 @@ class _HomeViewState extends State<HomeView> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedWallet = wallets.first;
|
selectedWallet = wallets.first;
|
||||||
selectedWallet!.recurEntries();
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +86,6 @@ class _HomeViewState extends State<HomeView> {
|
||||||
// debug option to quickly fill a wallet with data
|
// debug option to quickly fill a wallet with data
|
||||||
if (selectedWallet == null) return;
|
if (selectedWallet == null) return;
|
||||||
selectedWallet!.entries.clear();
|
selectedWallet!.entries.clear();
|
||||||
selectedWallet!.recurringEntries.clear();
|
|
||||||
final random = Random();
|
final random = Random();
|
||||||
for (var i = 0; i < 30; i++) {
|
for (var i = 0; i < 30; i++) {
|
||||||
selectedWallet!.entries.add(
|
selectedWallet!.entries.add(
|
||||||
|
@ -112,41 +109,7 @@ class _HomeViewState extends State<HomeView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.d(
|
logger.i(selectedWallet!.entries.length);
|
||||||
"Created ${selectedWallet!.entries.length} regular entries",
|
|
||||||
);
|
|
||||||
|
|
||||||
for (var i = 0; i < 3; i++) {
|
|
||||||
final type = random.nextInt(3);
|
|
||||||
selectedWallet!.recurringEntries.add(
|
|
||||||
RecurringWalletEntry(
|
|
||||||
data: EntryData(
|
|
||||||
name: "Recurring Entry #${i + 1}",
|
|
||||||
amount: random.nextInt(20000).toDouble(),
|
|
||||||
),
|
|
||||||
type: (random.nextInt(3) > 0)
|
|
||||||
? EntryType.expense
|
|
||||||
: EntryType.income,
|
|
||||||
date: DateTime(
|
|
||||||
2023,
|
|
||||||
random.nextInt(12) + 1,
|
|
||||||
random.nextInt(28) + 1,
|
|
||||||
),
|
|
||||||
category: selectedWallet!.categories[
|
|
||||||
random.nextInt(selectedWallet!.categories.length)],
|
|
||||||
id: selectedWallet!.nextId,
|
|
||||||
lastRunDate: DateTime.now().subtract(
|
|
||||||
Duration(
|
|
||||||
days: (type > 0) ? 3 : 3 * 31,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
recurType: (type > 0) ? RecurType.day : RecurType.month,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.d(
|
|
||||||
"Created ${selectedWallet!.recurringEntries.length} recurring entries");
|
|
||||||
|
|
||||||
// save and reload
|
// save and reload
|
||||||
WalletManager.saveWallet(selectedWallet!).then((value) {
|
WalletManager.saveWallet(selectedWallet!).then((value) {
|
||||||
|
@ -302,8 +265,8 @@ class _HomeViewState extends State<HomeView> {
|
||||||
if (yearA == null) return 0;
|
if (yearA == null) return 0;
|
||||||
final yearB = RegExp(r'\d+').firstMatch(b);
|
final yearB = RegExp(r'\d+').firstMatch(b);
|
||||||
if (yearB == null) return 0;
|
if (yearB == null) return 0;
|
||||||
final compareYears = int.parse(yearB.group(0)!)
|
final compareYears = int.parse(yearA.group(0)!)
|
||||||
.compareTo(int.parse(yearA.group(0)!));
|
.compareTo(int.parse(yearB.group(0)!));
|
||||||
if (compareYears != 0) return compareYears;
|
if (compareYears != 0) return compareYears;
|
||||||
final months = List<String>.generate(
|
final months = List<String>.generate(
|
||||||
12,
|
12,
|
||||||
|
|
|
@ -129,7 +129,6 @@ class _RecurringEntriesViewState extends State<RecurringEntriesView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
shape: const CircleBorder(),
|
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
|
@ -226,8 +225,11 @@ class _RecurringEntriesViewState extends State<RecurringEntriesView> {
|
||||||
text: AppLocalizations.of(context).yes,
|
text: AppLocalizations.of(context).yes,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
selectedWallet!.recurringEntries
|
selectedWallet!.recurringEntries
|
||||||
.remove(
|
.removeWhere(
|
||||||
selectedWallet!.recurringEntries[i],
|
(e) =>
|
||||||
|
e.id ==
|
||||||
|
selectedWallet!
|
||||||
|
.recurringEntries[i].id,
|
||||||
);
|
);
|
||||||
WalletManager.saveWallet(
|
WalletManager.saveWallet(
|
||||||
selectedWallet!,
|
selectedWallet!,
|
||||||
|
|
Loading…
Reference in a new issue