From 07908797d50e28c75b8961663d0f4ca126c446d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Sun, 30 Jun 2024 11:30:07 +0200 Subject: [PATCH] feat: use less Futures --- CHANGELOG.md | 1 + integration_test/app_test.dart | 25 +++++++------- lib/api/wallet.dart | 8 ++--- lib/api/wallet_manager.dart | 46 +++++++++++++------------ lib/main.dart | 9 +++-- lib/views/create_entry.dart | 5 ++- lib/views/create_recur_entry.dart | 5 ++- lib/views/graph_view.dart | 8 ++--- lib/views/home.dart | 42 +++++++++++----------- lib/views/initialization_screen.dart | 41 ++++++++++++++++++++++ lib/views/recurring_view.dart | 8 ++--- lib/views/settings/edit_categories.dart | 18 +++++----- lib/views/settings/settings.dart | 2 +- lib/views/setup.dart | 6 ++-- pubspec.lock | 4 +-- pubspec.yaml | 2 +- 16 files changed, 139 insertions(+), 91 deletions(-) create mode 100644 lib/views/initialization_screen.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ad0e7c..e5eaffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # newVersion - Upgrade dependencies +- Use less `await`s in WalletManager class # 1.1.1 - Removed deprecated code diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index fd707c7..5e0b426 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -18,11 +18,11 @@ void main() { group("Test classes and API", () { test("Test wallet operations", () async { expect( - (await WalletManager.listWallets()).length, + WalletManager.listWallets().length, equals(0), ); // check that there are no other wallets - await WalletManager.saveWallet(Wallet.empty); - var w = (await WalletManager.listWallets()).firstOrNull; + WalletManager.saveWallet(Wallet.empty); + var w = WalletManager.listWallets().firstOrNull; expect(w, isNotNull); // check that the wallet was successfully saved expect(w!.categories.length, equals(1)); w.categories.add( @@ -43,8 +43,8 @@ void main() { id: w.nextId, ), ); // create test entry - await WalletManager.saveWallet(w); // save again - w = await WalletManager.loadWallet(w.name); // try loading manually + WalletManager.saveWallet(w); // save again + w = WalletManager.loadWallet(w.name); // try loading manually final e = w.entries.where((element) => element.id == testId).firstOrNull; expect( e, @@ -55,9 +55,9 @@ void main() { equals(1), ); // check that the category exists too - await WalletManager.deleteWallet(w); + WalletManager.deleteWallet(w); expect( - (await WalletManager.listWallets()).length, + WalletManager.listWallets().length, equals(0), ); }); @@ -66,7 +66,7 @@ void main() { group("Test app functionality:", () { testWidgets('First-time setup', (WidgetTester tester) async { // Delete all data - await WalletManager.deleteAllData(); + WalletManager.deleteAllData(); // Build our app and trigger a frame. await tester.pumpWidget( const MyApp( @@ -113,13 +113,12 @@ void main() { testWidgets('Test rendering of entries', (WidgetTester tester) async { // Delete all data - await WalletManager.deleteAllData(); - expect((await WalletManager.listWallets()).length, equals(0)); + WalletManager.deleteAllData(); + expect(WalletManager.listWallets().length, equals(0)); // Create test data - final w = Wallet.empty; - await w.createTestEntries(); - expect((await WalletManager.listWallets()).length, equals(1)); + Wallet.empty.createTestEntries(); + expect(WalletManager.listWallets().length, equals(1)); // Build our app and trigger a frame. await tester.pumpWidget( diff --git a/lib/api/wallet.dart b/lib/api/wallet.dart index 06bca51..0310067 100644 --- a/lib/api/wallet.dart +++ b/lib/api/wallet.dart @@ -147,7 +147,7 @@ class Wallet { /// /// All [WalletSingleEntry]s will have their category reassigned /// to the default *No category* - Future removeCategory(WalletCategory category) async { + void removeCategory(WalletCategory category) { // First remove the category from existing entries for (final entryToChange in entries.where((element) => element.category.id == category.id)) { @@ -157,7 +157,7 @@ class Wallet { // Remove the category categories.removeWhere((element) => element.id == category.id); // Save - await WalletManager.saveWallet(this); + WalletManager.saveWallet(this); } /// Returns the current balance @@ -216,7 +216,7 @@ class Wallet { ); /// Creates test data used for debugging purposes - Future createTestEntries() async { + void createTestEntries() { entries.clear(); recurringEntries.clear(); final random = Random(); @@ -274,6 +274,6 @@ class Wallet { ); // save and reload - await WalletManager.saveWallet(this); + WalletManager.saveWallet(this); } } diff --git a/lib/api/wallet_manager.dart b/lib/api/wallet_manager.dart index 1ff5ff5..8f5d086 100644 --- a/lib/api/wallet_manager.dart +++ b/lib/api/wallet_manager.dart @@ -11,10 +11,17 @@ import 'package:prasule/main.dart'; /// Used for [Wallet]-managing operations class WalletManager { + /// Currently selected wallet + static Wallet? selectedWallet; + + /// Path to the directory with wallet files + /// + /// Saved beforehand so we don't have to use async everywhere + static late String walletPath; + /// Returns a list of all [Wallet]s - static Future> listWallets() async { - final path = - Directory("${(await getApplicationDocumentsDirectory()).path}/wallets"); + static List listWallets() { + final path = Directory(walletPath); if (!path.existsSync()) { path.createSync(); } @@ -22,7 +29,7 @@ class WalletManager { for (final w in path.listSync().map((e) => e.path.split("/").last).toList()) { try { - wallets.add(await loadWallet(w)); + wallets.add(loadWallet(w)); } catch (e) { logger.e(e); // TODO: do something with unreadable wallets @@ -32,9 +39,8 @@ class WalletManager { } /// Deletes all [Wallet]s - static Future deleteAllData() async { - final path = - Directory("${(await getApplicationDocumentsDirectory()).path}/wallets"); + static void deleteAllData() { + final path = Directory(walletPath); if (!path.existsSync()) { return; } @@ -124,10 +130,10 @@ class WalletManager { d = File(filePath).readAsStringSync(); } final w = Wallet.fromJson(jsonDecode(d) as Map); - if (await WalletManager.exists(w.name)) { + if (WalletManager.exists(w.name)) { throw Exception("Wallet already exists!"); } - await WalletManager.saveWallet( + WalletManager.saveWallet( w, ); } @@ -166,15 +172,14 @@ class WalletManager { } /// Loads and returns a single [Wallet] by name - static Future loadWallet(String name) async { - final path = - Directory("${(await getApplicationDocumentsDirectory()).path}/wallets"); + static Wallet loadWallet(String name) { + final path = Directory(walletPath); final wallet = File("${path.path}/$name"); if (!path.existsSync()) { path.createSync(); } if (!wallet.existsSync()) { - return Future.error("Wallet does not exist"); + throw Exception("Wallet does not exist"); } return Wallet.fromJson( jsonDecode(wallet.readAsStringSync()) as Map, @@ -182,29 +187,26 @@ class WalletManager { } /// Converts [Wallet] to JSON and saves it to AppData - static Future saveWallet(Wallet w) async { - final path = - Directory("${(await getApplicationDocumentsDirectory()).path}/wallets"); + static void saveWallet(Wallet w) { + final path = Directory(walletPath); final wallet = File("${path.path}/${w.name}"); if (!path.existsSync()) { path.createSync(); } // if (!wallet.existsSync()) return false; wallet.writeAsStringSync(jsonEncode(w.toJson())); - return true; } /// Deletes the corresponding [Wallet] file - static Future deleteWallet(Wallet w) async { - final path = - Directory("${(await getApplicationDocumentsDirectory()).path}/wallets"); + static void deleteWallet(Wallet w) { + final path = Directory(walletPath); File("${path.path}/${w.name}").deleteSync(); } /// Checks if the wallet exists - static Future exists(String name) async { + static bool exists(String name) { return File( - "${(await getApplicationDocumentsDirectory()).path}/wallets/$name", + "$walletPath/$name", ).existsSync(); } } diff --git a/lib/main.dart b/lib/main.dart index d6791ea..a281b88 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,8 +6,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:logger/logger.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:prasule/api/wallet_manager.dart'; import 'package:prasule/util/color_schemes.g.dart'; import 'package:prasule/views/home.dart'; +import 'package:prasule/views/initialization_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; var _materialYou = false; @@ -20,6 +23,7 @@ void main() async { } _materialYou = s.getBool("useMaterialYou") ?? true; + runApp(const MyApp()); } @@ -39,6 +43,7 @@ class MyApp extends StatelessWidget { /// Override locale, used for testing final Locale? locale; // This widget is the root of your application. + @override Widget build(BuildContext context) { return (Platform.isAndroid) @@ -66,7 +71,7 @@ class MyApp extends StatelessWidget { colorScheme: _materialYou ? dark ?? darkColorScheme : darkColorScheme, ), - home: const HomeView(), + home: const InitializationScreen(), ); }, ) @@ -85,7 +90,7 @@ class MyApp extends StatelessWidget { ...GlobalCupertinoLocalizations.delegates, ], title: 'PraĊĦule', - home: HomeView(), + home: InitializationScreen(), ), ); } diff --git a/lib/views/create_entry.dart b/lib/views/create_entry.dart index 77d8492..02d9ab4 100644 --- a/lib/views/create_entry.dart +++ b/lib/views/create_entry.dart @@ -236,9 +236,8 @@ class _CreateSingleEntryViewState extends State { return; } widget.w.entries.add(newEntry); - WalletManager.saveWallet(widget.w).then( - (value) => Navigator.of(context).pop(widget.w), - ); // TODO loading circle? + WalletManager.saveWallet(widget.w); // TODO loading circle? + Navigator.of(context).pop(widget.w); }, ), ], diff --git a/lib/views/create_recur_entry.dart b/lib/views/create_recur_entry.dart index 5224277..2356a4b 100644 --- a/lib/views/create_recur_entry.dart +++ b/lib/views/create_recur_entry.dart @@ -323,9 +323,8 @@ class _CreateRecurringEntryViewState extends State { return; } widget.w.recurringEntries.add(newEntry); - WalletManager.saveWallet(widget.w).then( - (value) => Navigator.of(context).pop(widget.w), - ); // TODO loading circle? + WalletManager.saveWallet(widget.w); // TODO loading circle? + Navigator.of(context).pop(widget.w); }, ), ], diff --git a/lib/views/graph_view.dart b/lib/views/graph_view.dart index 4a25c4c..f447808 100644 --- a/lib/views/graph_view.dart +++ b/lib/views/graph_view.dart @@ -67,8 +67,8 @@ class _GraphViewState extends State { final availableYears = >[]; - Future loadWallet() async { - wallets = await WalletManager.listWallets(); + void loadWallet() { + wallets = WalletManager.listWallets(); if (wallets.isEmpty && mounted) { unawaited( Navigator.of(context) @@ -224,7 +224,7 @@ class _GraphViewState extends State { ), ), ); - wallets = await WalletManager.listWallets(); + wallets = WalletManager.listWallets(); logger.i(wallets.length); selectedWallet = wallets.last; setState(() {}); @@ -250,7 +250,7 @@ class _GraphViewState extends State { ) .then((value) async { selectedWallet = - await WalletManager.loadWallet(selectedWallet!.name); + WalletManager.loadWallet(selectedWallet!.name); final s = await SharedPreferences.getInstance(); chartType = s.getInt("monthlygraph") ?? 2; setState(() {}); diff --git a/lib/views/home.dart b/lib/views/home.dart index 64476ff..f8530a5 100644 --- a/lib/views/home.dart +++ b/lib/views/home.dart @@ -63,8 +63,8 @@ class _HomeViewState extends State { loadWallet(); } - Future loadWallet() async { - wallets = await WalletManager.listWallets(); + void loadWallet() { + wallets = WalletManager.listWallets(); if (wallets.isEmpty && mounted) { unawaited( Navigator.of(context) @@ -82,7 +82,7 @@ class _HomeViewState extends State { return PopScope( canPop: !_searchActive, // don't pop when we just want // to deactivate searchfield - onPopInvoked: (b) { + onPopInvokedWithResult: (b, d) { if (b) return; _searchActive = false; _filter = ""; @@ -105,13 +105,12 @@ class _HomeViewState extends State { onTap: () { // debug option to quickly fill a wallet with data if (selectedWallet == null) return; - selectedWallet!.createTestEntries().then((_) { - Navigator.of(context).pushReplacement( - platformRoute( - (p0) => const HomeView(), - ), - ); - }); + selectedWallet!.createTestEntries(); + Navigator.of(context).pushReplacement( + platformRoute( + (p0) => const HomeView(), + ), + ); }, ), SpeedDialChild( @@ -194,7 +193,7 @@ class _HomeViewState extends State { ), ), ); - wallets = await WalletManager.listWallets(); + wallets = WalletManager.listWallets(); selectedWallet = wallets.last; setState(() {}); return; @@ -248,9 +247,9 @@ class _HomeViewState extends State { (context) => const SettingsView(), ), ) - .then((value) async { - wallets = await WalletManager.listWallets(); - selectedWallet = await WalletManager.loadWallet( + .then((value) { + wallets = WalletManager.listWallets(); + selectedWallet = WalletManager.loadWallet( selectedWallet!.name, ); setState(() {}); @@ -630,11 +629,14 @@ class _HomeViewState extends State { onPressed: () { Navigator.of(context) .push( - platformRoute( - (c) => const TessdataListView(), - ), - ) - .then((value) => Navigator.of(c).pop()); + platformRoute( + (c) => const TessdataListView(), + ), + ) + .then((value) { + if (!c.mounted) return; + Navigator.of(c).pop(); + }); }, ), PlatformButton( @@ -741,7 +743,7 @@ class _HomeViewState extends State { ); if (newEntry == null) return; selectedWallet!.entries.add(newEntry); - await WalletManager.saveWallet(selectedWallet!); + WalletManager.saveWallet(selectedWallet!); setState(() {}); }, child: const Text("Ok"), diff --git a/lib/views/initialization_screen.dart b/lib/views/initialization_screen.dart new file mode 100644 index 0000000..3289e09 --- /dev/null +++ b/lib/views/initialization_screen.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:prasule/api/wallet_manager.dart'; +import 'package:prasule/pw/platformroute.dart'; +import 'package:prasule/views/home.dart'; +import 'package:prasule/views/setup.dart'; + +class InitializationScreen extends StatefulWidget { + const InitializationScreen({super.key}); + + @override + State createState() => _InitializationScreenState(); +} + +class _InitializationScreenState extends State { + @override + void initState() { + super.initState(); + getApplicationDocumentsDirectory().then((v) { + WalletManager.walletPath = v.path; + if (!mounted) return; + final wallets = WalletManager.listWallets(); + if (wallets.isEmpty && mounted) { + Navigator.of(context) + .pushReplacement(platformRoute((c) => const SetupView())); + return; + } + Navigator.of(context) + .pushReplacement(platformRoute((c) => const HomeView())); + }); + } + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: Align( + child: CircularProgressIndicator(), + ), + ); + } +} diff --git a/lib/views/recurring_view.dart b/lib/views/recurring_view.dart index c5edbaa..10e9c12 100644 --- a/lib/views/recurring_view.dart +++ b/lib/views/recurring_view.dart @@ -44,8 +44,8 @@ class _RecurringEntriesViewState extends State { loadWallet(); } - Future loadWallet() async { - wallets = await WalletManager.listWallets(); + void loadWallet() { + wallets = WalletManager.listWallets(); if (wallets.isEmpty && mounted) { unawaited( Navigator.of(context) @@ -91,7 +91,7 @@ class _RecurringEntriesViewState extends State { ), ), ); - wallets = await WalletManager.listWallets(); + wallets = WalletManager.listWallets(); selectedWallet = wallets.last; setState(() {}); return; @@ -116,7 +116,7 @@ class _RecurringEntriesViewState extends State { ) .then((value) async { selectedWallet = - await WalletManager.loadWallet(selectedWallet!.name); + WalletManager.loadWallet(selectedWallet!.name); }); } else if (value == AppLocalizations.of(context).about) { showAbout(context); diff --git a/lib/views/settings/edit_categories.dart b/lib/views/settings/edit_categories.dart index d6cf5ad..bb860e1 100644 --- a/lib/views/settings/edit_categories.dart +++ b/lib/views/settings/edit_categories.dart @@ -39,7 +39,7 @@ class _EditCategoriesViewState extends State { } Future loadWallet() async { - wallets = await WalletManager.listWallets(); + wallets = WalletManager.listWallets(); if (wallets.isEmpty && mounted) { unawaited( Navigator.of(context) @@ -82,7 +82,7 @@ class _EditCategoriesViewState extends State { ), ), ); - wallets = await WalletManager.listWallets(); + wallets = WalletManager.listWallets(); logger.i(wallets.length); selectedWallet = wallets.last; setState(() {}); @@ -122,7 +122,7 @@ class _EditCategoriesViewState extends State { textAlign: TextAlign.center, ), IconButton( - onPressed: () async { + onPressed: () { selectedWallet!.categories.add( WalletCategory( name: AppLocalizations.of(context) @@ -137,7 +137,7 @@ class _EditCategoriesViewState extends State { ), ), ); - await WalletManager.saveWallet(selectedWallet!); + WalletManager.saveWallet(selectedWallet!); setState(() {}); }, icon: const Icon(Icons.add), @@ -206,7 +206,7 @@ class _EditCategoriesViewState extends State { ), ), ); - await WalletManager.saveWallet(selectedWallet!); + WalletManager.saveWallet(selectedWallet!); setState(() {}); }, child: Container( @@ -226,8 +226,8 @@ class _EditCategoriesViewState extends State { ), trailing: IconButton( icon: const Icon(Icons.cancel), - onPressed: () async { - await selectedWallet!.removeCategory( + onPressed: () { + selectedWallet!.removeCategory( selectedWallet!.categories[i], ); setState(() {}); @@ -243,11 +243,11 @@ class _EditCategoriesViewState extends State { builder: (c) => AlertDialog.adaptive( actions: [ TextButton( - onPressed: () async { + onPressed: () { if (controller.text.isEmpty) return; selectedWallet!.categories[i].name = controller.text; - await WalletManager.saveWallet( + WalletManager.saveWallet( selectedWallet!, ); if (!context.mounted) return; diff --git a/lib/views/settings/settings.dart b/lib/views/settings/settings.dart index 0570525..8a91c52 100644 --- a/lib/views/settings/settings.dart +++ b/lib/views/settings/settings.dart @@ -117,7 +117,7 @@ class _SettingsViewState extends State { description: Text(AppLocalizations.of(context).exportSingleDesc), onPressed: (ctx) async { - final all = await WalletManager.listWallets(); + final all = WalletManager.listWallets(); if (!ctx.mounted) return; final w = await showAdaptiveDialog( context: ctx, diff --git a/lib/views/setup.dart b/lib/views/setup.dart index f260887..82111df 100644 --- a/lib/views/setup.dart +++ b/lib/views/setup.dart @@ -131,7 +131,7 @@ class _SetupViewState extends State { next: Text(AppLocalizations.of(context).next), back: Text(AppLocalizations.of(context).back), done: Text(AppLocalizations.of(context).finish), - onDone: () async { + onDone: () { if (_nameController.text.isEmpty) { unawaited( showMessage( @@ -141,7 +141,7 @@ class _SetupViewState extends State { ); return; } - if (await WalletManager.exists(_nameController.text) && + if (WalletManager.exists(_nameController.text) && context.mounted) { unawaited( showMessage( @@ -157,7 +157,7 @@ class _SetupViewState extends State { categories: categories, starterBalance: double.parse(_balanceController.text), ); - await WalletManager.saveWallet(wallet); + WalletManager.saveWallet(wallet); if (widget.newWallet && context.mounted) { Navigator.of(context).pop(); diff --git a/pubspec.lock b/pubspec.lock index f78a65c..05e0dbb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -409,10 +409,10 @@ packages: dependency: "direct main" description: name: flutter_tesseract_ocr - sha256: f6f55804d2c1fe385dba150a2c1c8641e5add2694fdaa72d835aca051f9faa75 + sha256: a45b76842f9670a3b69a4d1276367926aa8428d33e439e80541e699b7c5fb96b url: "https://pub.dev" source: hosted - version: "0.4.25" + version: "0.4.23" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 0dcda01..48cb2f4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: sdk: flutter flutter_slidable: ^3.0.0 flutter_speed_dial: ^7.0.0 - flutter_tesseract_ocr: ^0.4.23 + flutter_tesseract_ocr: 0.4.23 fluttertoast: ^8.2.4 grouped_list: ^5.1.2 intl: any