test: create basic tests (#24)
Related to #1 but more tests should be added, so not closing Reviewed-on: #24
This commit is contained in:
parent
dcc38645c8
commit
96e672f1d5
18 changed files with 276 additions and 124 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -42,3 +42,4 @@ app.*.map.json
|
||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
reports
|
|
@ -51,7 +51,7 @@ android {
|
||||||
applicationId "cafe.caras.prasule"
|
applicationId "cafe.caras.prasule"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdkVersion flutter.minSdkVersion
|
minSdkVersion 21
|
||||||
targetSdkVersion 33
|
targetSdkVersion 33
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
@ -76,4 +76,6 @@ flutter {
|
||||||
source '../..'
|
source '../..'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {}
|
dependencies {
|
||||||
|
implementation 'com.android.support:multidex:1.0.3'
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,3 @@
|
||||||
buildscript {
|
|
||||||
ext.kotlin_version = '1.7.10'
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
|
|
@ -10,11 +10,17 @@ pluginManagement {
|
||||||
|
|
||||||
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
plugins {
|
repositories {
|
||||||
id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
|
id "com.android.application" version "7.3.0" apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||||
|
}
|
||||||
|
|
||||||
include ":app"
|
include ":app"
|
||||||
|
|
||||||
apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
|
||||||
|
|
140
integration_test/app_test.dart
Normal file
140
integration_test/app_test.dart
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:logger/logger.dart';
|
||||||
|
import 'package:prasule/api/category.dart';
|
||||||
|
import 'package:prasule/api/entry_data.dart';
|
||||||
|
import 'package:prasule/api/wallet.dart';
|
||||||
|
import 'package:prasule/api/wallet_entry.dart';
|
||||||
|
import 'package:prasule/api/wallet_manager.dart';
|
||||||
|
|
||||||
|
import 'package:prasule/main.dart';
|
||||||
|
import 'package:prasule/pw/platformfield.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final logger = Logger();
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group("Test classes and API", () {
|
||||||
|
test("Test wallet operations", () async {
|
||||||
|
expect(
|
||||||
|
(await WalletManager.listWallets()).length,
|
||||||
|
equals(0),
|
||||||
|
); // check that there are no other wallets
|
||||||
|
await WalletManager.saveWallet(Wallet.empty);
|
||||||
|
var w = (await WalletManager.listWallets()).firstOrNull;
|
||||||
|
expect(w, isNotNull); // check that the wallet was successfully saved
|
||||||
|
expect(w!.categories.length, equals(1));
|
||||||
|
w.categories.add(
|
||||||
|
WalletCategory(
|
||||||
|
name: "Testing",
|
||||||
|
id: w.nextCategoryId,
|
||||||
|
icon: Icons.abc,
|
||||||
|
color: Colors.orange,
|
||||||
|
),
|
||||||
|
); // create test category
|
||||||
|
final testId = w.nextId;
|
||||||
|
w.entries.add(
|
||||||
|
WalletSingleEntry(
|
||||||
|
data: EntryData(amount: 200, name: "Automated"),
|
||||||
|
type: EntryType.expense,
|
||||||
|
date: DateTime.now(),
|
||||||
|
category: w.categories.last,
|
||||||
|
id: w.nextId,
|
||||||
|
),
|
||||||
|
); // create test entry
|
||||||
|
await WalletManager.saveWallet(w); // save again
|
||||||
|
w = await WalletManager.loadWallet(w.name); // try loading manually
|
||||||
|
final e = w.entries.where((element) => element.id == testId).firstOrNull;
|
||||||
|
expect(
|
||||||
|
e,
|
||||||
|
isNotNull,
|
||||||
|
); // check that the entry was successfully created
|
||||||
|
expect(
|
||||||
|
w.categories.where((element) => element.id == e!.category.id).length,
|
||||||
|
equals(1),
|
||||||
|
); // check that the category exists too
|
||||||
|
|
||||||
|
await WalletManager.deleteWallet(w);
|
||||||
|
expect(
|
||||||
|
(await WalletManager.listWallets()).length,
|
||||||
|
equals(0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("Test app functionality:", () {
|
||||||
|
testWidgets('First-time setup', (WidgetTester tester) async {
|
||||||
|
// Delete all data
|
||||||
|
await WalletManager.deleteAllData();
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const MyApp(
|
||||||
|
locale: Locale('en', 'US'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
logger.i("Looking for welcome header");
|
||||||
|
expect(find.text('Welcome!'), findsOneWidget);
|
||||||
|
|
||||||
|
// Tap "Next" button
|
||||||
|
await tester.tap(find.text("Next"));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
logger.i("Next view, looking for name+balance fields");
|
||||||
|
|
||||||
|
final firstFields = find.byType(PlatformField);
|
||||||
|
|
||||||
|
expect(firstFields, findsExactly(2));
|
||||||
|
|
||||||
|
logger.i("Entering text");
|
||||||
|
await tester.enterText(find.byType(PlatformField).first, "Debugging");
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
await tester.enterText(find.byType(PlatformField).last, "100");
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Tap "Next" button
|
||||||
|
await tester.tap(find.text("Next"));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Tap "Finish" button
|
||||||
|
await tester.tap(find.text("Finish"));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byWidgetPredicate(
|
||||||
|
(widget) =>
|
||||||
|
widget is DropdownButton &&
|
||||||
|
((widget as DropdownButton<int>).value ?? -1) == 0,
|
||||||
|
),
|
||||||
|
findsOne,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Test rendering of entries', (WidgetTester tester) async {
|
||||||
|
// Delete all data
|
||||||
|
await WalletManager.deleteAllData();
|
||||||
|
expect((await WalletManager.listWallets()).length, equals(0));
|
||||||
|
|
||||||
|
// Create test data
|
||||||
|
final w = Wallet.empty;
|
||||||
|
await w.createTestEntries();
|
||||||
|
expect((await WalletManager.listWallets()).length, equals(1));
|
||||||
|
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const MyApp(
|
||||||
|
locale: Locale('en', 'US'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// TODO: better test
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byType(ListTile, skipOffstage: false),
|
||||||
|
findsAtLeast(10),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,24 +0,0 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:integration_test/integration_test.dart';
|
|
||||||
|
|
||||||
import 'package:prasule/main.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
group("Test Setup screen:", () {
|
|
||||||
testWidgets('First-time setup', (WidgetTester tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(const MyApp());
|
|
||||||
|
|
||||||
expect(find.text('Welcome!'), findsOneWidget);
|
|
||||||
|
|
||||||
// // Tap the '+' icon and trigger a frame.
|
|
||||||
// await tester.tap(find.byIcon(Icons.add));
|
|
||||||
// await tester.pump();
|
|
||||||
|
|
||||||
// // Verify that our counter has incremented.
|
|
||||||
// expect(find.text('0'), findsNothing);
|
|
||||||
// expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:currency_picker/currency_picker.dart';
|
import 'package:currency_picker/currency_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.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/entry_data.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';
|
||||||
|
@ -132,7 +136,8 @@ class Wallet {
|
||||||
: recurringEntries[recurringEntries.indexOf(ent)].lastRunDate.day,
|
: recurringEntries[recurringEntries.indexOf(ent)].lastRunDate.day,
|
||||||
); // add the variable again to check if we aren't missing any entries
|
); // add the variable again to check if we aren't missing any entries
|
||||||
logger.i(
|
logger.i(
|
||||||
"Last recurred date is now on ${DateFormat.yMMMMd().format(m)} (${n.isAfter(m)})");
|
"Last recurred date is now on ${DateFormat.yMMMMd().format(m)} (${n.isAfter(m)})",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
WalletManager.saveWallet(this); // save wallet
|
WalletManager.saveWallet(this); // save wallet
|
||||||
}
|
}
|
||||||
|
@ -158,6 +163,19 @@ class Wallet {
|
||||||
/// Empty wallet used for placeholders
|
/// Empty wallet used for placeholders
|
||||||
static final Wallet empty = Wallet(
|
static final Wallet empty = Wallet(
|
||||||
name: "Empty",
|
name: "Empty",
|
||||||
|
entries: [],
|
||||||
|
recurringEntries: [],
|
||||||
|
categories: [
|
||||||
|
WalletCategory(
|
||||||
|
name: "Default",
|
||||||
|
id: 0,
|
||||||
|
icon: IconData(
|
||||||
|
Icons.payments.codePoint,
|
||||||
|
fontFamily: 'MaterialIcons',
|
||||||
|
),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
],
|
||||||
currency: Currency.from(
|
currency: Currency.from(
|
||||||
json: {
|
json: {
|
||||||
"code": "USD",
|
"code": "USD",
|
||||||
|
@ -174,4 +192,66 @@ class Wallet {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Creates test data used for debugging purposes
|
||||||
|
Future<void> createTestEntries() async {
|
||||||
|
entries.clear();
|
||||||
|
recurringEntries.clear();
|
||||||
|
final random = Random();
|
||||||
|
for (var i = 0; i < 30; i++) {
|
||||||
|
entries.add(
|
||||||
|
WalletSingleEntry(
|
||||||
|
data: EntryData(
|
||||||
|
name: "Test 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: categories[random.nextInt(categories.length)],
|
||||||
|
id: nextId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.d(
|
||||||
|
"Created ${entries.length} regular entries",
|
||||||
|
);
|
||||||
|
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
final type = random.nextInt(3);
|
||||||
|
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: categories[random.nextInt(categories.length)],
|
||||||
|
id: nextId,
|
||||||
|
lastRunDate: DateTime.now().subtract(
|
||||||
|
Duration(
|
||||||
|
days: (type > 0) ? 3 : 3 * 31,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
recurType: (type > 0) ? RecurType.day : RecurType.month,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.d(
|
||||||
|
"Created ${recurringEntries.length} recurring entries",
|
||||||
|
);
|
||||||
|
|
||||||
|
// save and reload
|
||||||
|
await WalletManager.saveWallet(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,23 @@ class WalletManager {
|
||||||
// TODO: do something with unreadable wallets
|
// TODO: do something with unreadable wallets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.i(wallets.length);
|
|
||||||
return wallets;
|
return wallets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes all [Wallet]s
|
||||||
|
static Future<void> deleteAllData() async {
|
||||||
|
final path =
|
||||||
|
Directory("${(await getApplicationDocumentsDirectory()).path}/wallets");
|
||||||
|
if (!path.existsSync()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final entry in path.listSync()) {
|
||||||
|
logger.d("Deleting ${entry.path}");
|
||||||
|
entry.deleteSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads and returns a single [Wallet] by name
|
/// Loads and returns a single [Wallet] by name
|
||||||
static Future<Wallet> loadWallet(String name) async {
|
static Future<Wallet> loadWallet(String name) async {
|
||||||
final path =
|
final path =
|
||||||
|
|
|
@ -29,12 +29,15 @@ final logger = Logger();
|
||||||
/// The application itself
|
/// The application itself
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
/// The application itself
|
/// The application itself
|
||||||
const MyApp({super.key});
|
const MyApp({super.key, this.locale});
|
||||||
|
|
||||||
/// If Material You was applied
|
/// If Material You was applied
|
||||||
///
|
///
|
||||||
/// Used to check if it is supported
|
/// Used to check if it is supported
|
||||||
static bool appliedYou = false;
|
static bool appliedYou = false;
|
||||||
|
|
||||||
|
/// Override locale, used for testing
|
||||||
|
final Locale? locale;
|
||||||
// This widget is the root of your application.
|
// This widget is the root of your application.
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -50,6 +53,7 @@ class MyApp extends StatelessWidget {
|
||||||
...GlobalCupertinoLocalizations.delegates,
|
...GlobalCupertinoLocalizations.delegates,
|
||||||
],
|
],
|
||||||
supportedLocales: AppLocalizations.supportedLocales,
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
locale: locale,
|
||||||
title: 'Prašule',
|
title: 'Prašule',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: _materialYou
|
colorScheme: _materialYou
|
||||||
|
|
|
@ -522,6 +522,7 @@ class Indicator extends StatelessWidget {
|
||||||
/// Text shown next to the indicator circle
|
/// Text shown next to the indicator circle
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
|
/// Text style of the indicator
|
||||||
final TextStyle textStyle;
|
final TextStyle textStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -192,7 +192,9 @@ class _CreateSingleEntryViewState extends State<CreateSingleEntryView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (newEntry.data.name.isEmpty) {
|
if (newEntry.data.name.isEmpty) {
|
||||||
showMessage(
|
showMessage(
|
||||||
AppLocalizations.of(context).errorEmptyName, context);
|
AppLocalizations.of(context).errorEmptyName,
|
||||||
|
context,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (widget.editEntry != null) {
|
if (widget.editEntry != null) {
|
||||||
|
|
|
@ -315,7 +315,9 @@ class _CreateRecurringEntryViewState extends State<CreateRecurringEntryView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (newEntry.data.name.isEmpty) {
|
if (newEntry.data.name.isEmpty) {
|
||||||
showMessage(
|
showMessage(
|
||||||
AppLocalizations.of(context).errorEmptyName, context);
|
AppLocalizations.of(context).errorEmptyName,
|
||||||
|
context,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (widget.editEntry != null) {
|
if (widget.editEntry != null) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// ignore_for_file: inference_failure_on_function_invocation
|
// ignore_for_file: inference_failure_on_function_invocation
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -16,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';
|
||||||
|
@ -88,70 +86,7 @@ class _HomeViewState extends State<HomeView> {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// 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!.createTestEntries().then((_) {
|
||||||
selectedWallet!.recurringEntries.clear();
|
|
||||||
final random = Random();
|
|
||||||
for (var i = 0; i < 30; i++) {
|
|
||||||
selectedWallet!.entries.add(
|
|
||||||
WalletSingleEntry(
|
|
||||||
data: EntryData(
|
|
||||||
name: "Test 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,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.d(
|
|
||||||
"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
|
|
||||||
WalletManager.saveWallet(selectedWallet!).then((value) {
|
|
||||||
Navigator.of(context).pushReplacement(
|
Navigator.of(context).pushReplacement(
|
||||||
platformRoute(
|
platformRoute(
|
||||||
(p0) => const HomeView(),
|
(p0) => const HomeView(),
|
||||||
|
@ -555,6 +490,7 @@ class _HomeViewState extends State<HomeView> {
|
||||||
}
|
}
|
||||||
description.write("${line.replaceAll(regex, "")}\n");
|
description.write("${line.replaceAll(regex, "")}\n");
|
||||||
}
|
}
|
||||||
|
if (!ctx.mounted) return;
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
// show edit
|
// show edit
|
||||||
final newEntry =
|
final newEntry =
|
||||||
|
|
|
@ -146,7 +146,7 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
||||||
(await SharedPreferences.getInstance())
|
(await SharedPreferences.getInstance())
|
||||||
.getBool("useMaterialYou") ??
|
.getBool("useMaterialYou") ??
|
||||||
false;
|
false;
|
||||||
if (!mounted) return;
|
if (!context.mounted) return;
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (c) => PlatformDialog(
|
builder: (c) => PlatformDialog(
|
||||||
|
@ -227,7 +227,7 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
||||||
await WalletManager.saveWallet(
|
await WalletManager.saveWallet(
|
||||||
selectedWallet!,
|
selectedWallet!,
|
||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!context.mounted) return;
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -70,7 +70,7 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
||||||
final s = await SharedPreferences.getInstance();
|
final s = await SharedPreferences.getInstance();
|
||||||
await s.setInt("yearlygraph", 1);
|
await s.setInt("yearlygraph", 1);
|
||||||
_yearly = 1;
|
_yearly = 1;
|
||||||
if (!mounted) return;
|
if (!ctx.mounted) return;
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
@ -90,7 +90,7 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
||||||
final s = await SharedPreferences.getInstance();
|
final s = await SharedPreferences.getInstance();
|
||||||
await s.setInt("yearlygraph", 2);
|
await s.setInt("yearlygraph", 2);
|
||||||
_yearly = 2;
|
_yearly = 2;
|
||||||
if (!mounted) return;
|
if (!ctx.mounted) return;
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
@ -128,7 +128,7 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
||||||
final s = await SharedPreferences.getInstance();
|
final s = await SharedPreferences.getInstance();
|
||||||
await s.setInt("monthlygraph", 1);
|
await s.setInt("monthlygraph", 1);
|
||||||
_monthly = 1;
|
_monthly = 1;
|
||||||
if (!mounted) return;
|
if (!ctx.mounted) return;
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
@ -148,7 +148,7 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
||||||
final s = await SharedPreferences.getInstance();
|
final s = await SharedPreferences.getInstance();
|
||||||
await s.setInt("monthlygraph", 2);
|
await s.setInt("monthlygraph", 2);
|
||||||
_monthly = 2;
|
_monthly = 2;
|
||||||
if (!mounted) return;
|
if (!ctx.mounted) return;
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,7 +75,9 @@ class _TessdataListViewState extends State<TessdataListView> {
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await TessdataApi.deleteData(lang);
|
await TessdataApi.deleteData(lang);
|
||||||
_tessdata[i][lang] = true;
|
_tessdata[i][lang] = true;
|
||||||
if (mounted) Navigator.of(context).pop();
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
PlatformButton(
|
PlatformButton(
|
||||||
|
|
|
@ -297,7 +297,7 @@ class _SetupViewState extends State<SetupView> {
|
||||||
(await SharedPreferences.getInstance())
|
(await SharedPreferences.getInstance())
|
||||||
.getBool("useMaterialYou") ??
|
.getBool("useMaterialYou") ??
|
||||||
false;
|
false;
|
||||||
if (!mounted) return;
|
if (!context.mounted) return;
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (c) => PlatformDialog(
|
builder: (c) => PlatformDialog(
|
||||||
|
|
|
@ -325,10 +325,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flex_color_picker
|
name: flex_color_picker
|
||||||
sha256: f37476ab3e80dcaca94e428e159944d465dd16312fda9ff41e07e86f04bfa51c
|
sha256: "0871edc170153cfc3de316d30625f40a85daecfa76ce541641f3cc0ec7757cbf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.0"
|
version: "3.3.1"
|
||||||
flex_seed_scheme:
|
flex_seed_scheme:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
Loading…
Reference in a new issue