From 8a5129711927c8783b355c9484a23d92e798fe0b Mon Sep 17 00:00:00 2001 From: Luca Antonelli Date: Thu, 21 Nov 2024 22:12:21 +0100 Subject: [PATCH 1/3] Fix: Resolve many warnings --- android/app/build.gradle | 54 ++--- android/app/src/main/AndroidManifest.xml | 21 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- android/settings.gradle | 4 +- lib/custom_widgets/account_modal.dart | 15 +- lib/custom_widgets/accounts_sum.dart | 1 - lib/custom_widgets/alert_dialog.dart | 47 ++-- .../budget_circular_indicator.dart | 16 +- .../circular_menu_item_wrap.dart | 32 --- lib/custom_widgets/line_chart.dart | 6 +- lib/custom_widgets/transactions_list.dart | 57 ++--- lib/database/sossoldi_database.dart | 4 +- lib/main.dart | 23 +- lib/model/bank_account.dart | 57 +++-- lib/model/budget.dart | 41 ++-- lib/model/currency.dart | 43 ++-- lib/pages/accounts/account_list.dart | 4 +- lib/pages/accounts/add_account.dart | 12 +- lib/pages/add_page/add_page.dart | 11 +- .../add_page/widgets/account_selector.dart | 4 +- .../add_page/widgets/amount_section.dart | 7 +- .../add_page/widgets/category_selector.dart | 5 +- .../widgets/details_list_disabled_tile.dart | 17 +- .../add_page/widgets/details_list_tile.dart | 9 +- .../add_page/widgets/label_list_tile.dart | 8 +- .../widgets/recurrence_list_tile.dart | 6 +- .../widgets/recurrence_list_tile_edit.dart | 6 +- lib/pages/add_page/widgets/type_tab.dart | 4 +- lib/pages/categories/add_category.dart | 10 +- lib/pages/categories/category_list.dart | 4 +- .../general_options/general_settings.dart | 36 ++- .../widgets/currency_selector.dart | 134 +++++------ lib/pages/graphs_page/graphs_page.dart | 3 +- .../categories/categories_bar_chart.dart | 1 - lib/pages/home_page.dart | 16 +- .../more_info_page/collaborators_page.dart | 39 +--- lib/pages/more_info_page/privacy_policy.dart | 156 +++++++------ .../notifications/notifications_service.dart | 22 -- .../notifications/notifications_settings.dart | 161 ++++++-------- .../widgets/NotificationTypeTile.dart | 89 -------- .../widgets/notification_type_tile.dart | 58 +++++ .../onboarding_page/onboarding_page.dart | 22 +- .../widgets/account_setup.dart | 78 +++---- .../onboarding_page/widgets/add_budget.dart | 20 +- .../onboarding_page/widgets/budget_setup.dart | 72 ++---- .../planning_page/manage_budget_page.dart | 16 +- lib/pages/planning_page/planning_page.dart | 6 +- .../planning_page/widget/budget_card.dart | 4 +- .../widget/budget_category_selector.dart | 21 +- .../widget/budget_pie_chart.dart | 5 +- .../widget/edit_recurring_transaction.dart | 5 +- .../widget/older_recurring_payments.dart | 2 +- .../widget/recurring_payment_card.dart | 10 +- .../widget/recurring_payments_list.dart | 4 +- lib/pages/search_page/search_page.dart | 86 +++---- lib/pages/settings_page.dart | 2 +- lib/pages/structure.dart | 8 +- .../widgets/category_list_tile.dart | 1 - .../widgets/custom_sliver_delegate.dart | 2 +- lib/providers/budgets_provider.dart | 1 + lib/providers/settings_provider.dart | 65 ++++-- lib/providers/transactions_provider.dart | 2 - lib/utils/app_theme.dart | 6 +- lib/utils/notifications_service.dart | 122 ++++++++++ lib/utils/worker_manager.dart | 38 ++-- pubspec.lock | 209 ++++++++---------- pubspec.yaml | 112 ++-------- test/model/bank_account_test.dart | 32 ++- test/model/transaction_test.dart | 72 +++--- test/widget/accounts_sum_test.dart | 3 +- 70 files changed, 1063 insertions(+), 1209 deletions(-) delete mode 100644 lib/custom_widgets/circular_menu_item_wrap.dart delete mode 100644 lib/pages/notifications/notifications_service.dart delete mode 100644 lib/pages/notifications/widgets/NotificationTypeTile.dart create mode 100644 lib/pages/notifications/widgets/notification_type_tile.dart create mode 100644 lib/utils/notifications_service.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 97c8e6f4..0a572549 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -4,50 +4,26 @@ plugins { id "dev.flutter.flutter-gradle-plugin" } -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - android { - compileSdkVersion 34 - ndkVersion flutter.ndkVersion + namespace "com.example.sossoldi" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.sossoldi" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + applicationId = "com.example.sossoldi" + minSdkVersion = flutter.minSdkVersion + targetSdkVersion = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { @@ -60,5 +36,11 @@ android { } flutter { - source '../..' + source = "../.." } + +dependencies { + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' + implementation 'androidx.window:window:1.0.0' + implementation 'androidx.window:window-java:1.0.0' +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 99e2c6e2..67be1a21 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,16 @@ + + + + + + + + + + + + + + + + + + + [], - line2Color: Color(0xffffffff), - colorBackground: Color(0xff356CA3), - period: Period.month, - ), - const Padding( - padding: EdgeInsets.only(bottom: 14.0), ), + const SizedBox(height: 14.0), ], ), ), diff --git a/lib/custom_widgets/accounts_sum.dart b/lib/custom_widgets/accounts_sum.dart index 4189e416..346056ba 100644 --- a/lib/custom_widgets/accounts_sum.dart +++ b/lib/custom_widgets/accounts_sum.dart @@ -1,4 +1,3 @@ -import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; diff --git a/lib/custom_widgets/alert_dialog.dart b/lib/custom_widgets/alert_dialog.dart index 3e0dd11b..a7065fa0 100644 --- a/lib/custom_widgets/alert_dialog.dart +++ b/lib/custom_widgets/alert_dialog.dart @@ -58,7 +58,8 @@ class AlertDialogBuilder { showDialog( context: context, builder: (context) { - return _AlertDialog(dialogType, text, primaryActionText, primaryActionFunction, secondaryActionText, secondaryActionFunction); + return _AlertDialog(dialogType, text, primaryActionText, primaryActionFunction, + secondaryActionText, secondaryActionFunction); }, barrierDismissible: isDismissible); } @@ -68,33 +69,41 @@ class AlertDialogBuilder { /// Shows an info dialog with given text /// void showInfoDialog(BuildContext context, String text) => - AlertDialogBuilder(text: text, dialogType: AlertDialogType.info, primaryActionText: "OK").show(context); + AlertDialogBuilder(text: text, dialogType: AlertDialogType.info, primaryActionText: "OK") + .show(context); /// /// Shows a success dialog with given text /// void showSuccessDialog(BuildContext context, String text) => - AlertDialogBuilder(text: text, dialogType: AlertDialogType.success, primaryActionText: "OK").show(context); + AlertDialogBuilder(text: text, dialogType: AlertDialogType.success, primaryActionText: "OK") + .show(context); /// /// Shows a warning dialog with given text /// void showWarningDialog(BuildContext context, String text) => - AlertDialogBuilder(text: text, dialogType: AlertDialogType.warning, primaryActionText: "OK").show(context); + AlertDialogBuilder(text: text, dialogType: AlertDialogType.warning, primaryActionText: "OK") + .show(context); /// /// Shows an error dialog with given text /// void showErrorDialog(BuildContext context, String text) => - AlertDialogBuilder(text: text, dialogType: AlertDialogType.error, primaryActionText: "OK").show(context); + AlertDialogBuilder(text: text, dialogType: AlertDialogType.error, primaryActionText: "OK") + .show(context); enum AlertDialogType { info, success, warning, error } class _AlertDialog extends StatelessWidget { const _AlertDialog( - this._dialogType, this._text, this._primaryActionText, this._primaryActionFunction, this._secondaryActionText, this._secondaryActionFunction, - {Key? key}) - : super(key: key); + this._dialogType, + this._text, + this._primaryActionText, + this._primaryActionFunction, + this._secondaryActionText, + this._secondaryActionFunction, + ); final AlertDialogType _dialogType; final String _text; @@ -134,19 +143,21 @@ class _AlertDialog extends StatelessWidget { // Secondary action comes first, since actions are displayed on screen left to right // if (_secondaryActionText != null) { actionWidgets.add(TextButton( - onPressed: () { - _secondaryActionFunction?.call(); - Navigator.of(context).pop(); - }, - child: Text(_secondaryActionText!))); - } - - actionWidgets.add(TextButton( onPressed: () { - _primaryActionFunction?.call(); + _secondaryActionFunction?.call(); Navigator.of(context).pop(); }, - child: Text(_primaryActionText))); + child: Text(_secondaryActionText), + )); + } + + actionWidgets.add(TextButton( + onPressed: () { + _primaryActionFunction?.call(); + Navigator.of(context).pop(); + }, + child: Text(_primaryActionText), + )); return actionWidgets; } diff --git a/lib/custom_widgets/budget_circular_indicator.dart b/lib/custom_widgets/budget_circular_indicator.dart index c6f78b1a..f796f9b3 100644 --- a/lib/custom_widgets/budget_circular_indicator.dart +++ b/lib/custom_widgets/budget_circular_indicator.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:percent_indicator/circular_percent_indicator.dart'; @@ -62,7 +60,10 @@ class BudgetCircularIndicator extends ConsumerWidget with Functions { const SizedBox(height: 6), Text( "LEFT", - style: Theme.of(context).textTheme.labelLarge!.copyWith(color: Theme.of(context).colorScheme.primary), + style: Theme.of(context) + .textTheme + .labelLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), ), ], ), @@ -71,11 +72,10 @@ class BudgetCircularIndicator extends ConsumerWidget with Functions { progressColor: color, ), const SizedBox(height: 10), - Row( - children: [ - perc >= 0.9 ? const Icon(Icons.error_outline, color: Colors.red, size: 15) : Container(), - const SizedBox(width: 3), - Text(title, style: Theme.of(context).textTheme.bodyLarge), + Row(children: [ + perc >= 0.9 ? const Icon(Icons.error_outline, color: Colors.red, size: 15) : Container(), + const SizedBox(width: 3), + Text(title, style: Theme.of(context).textTheme.bodyLarge), ]) ], ); diff --git a/lib/custom_widgets/circular_menu_item_wrap.dart b/lib/custom_widgets/circular_menu_item_wrap.dart deleted file mode 100644 index 1921c90e..00000000 --- a/lib/custom_widgets/circular_menu_item_wrap.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:circular_menu/circular_menu.dart'; -import 'package:flutter/material.dart'; - -class CircularMenuItemWrap extends CircularMenuItem { - final VoidCallback onTap; - final String text; - final Color? iconColor; - final Color? color; - final IconData? icon; - - CircularMenuItemWrap({ - required this.onTap, - this.color, - required this.text, - this.icon, - this.iconColor, - }) : super(onTap: onTap, icon: icon, iconColor: iconColor, color: color); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - super.build(context), - Text(text, - style: const TextStyle( - color: Colors.black, - fontSize: 12.0, - fontFamily: 'SF Pro Text')), - ], - ); - } -} diff --git a/lib/custom_widgets/line_chart.dart b/lib/custom_widgets/line_chart.dart index 7c72e197..e9bb8a17 100644 --- a/lib/custom_widgets/line_chart.dart +++ b/lib/custom_widgets/line_chart.dart @@ -219,7 +219,7 @@ class _LineChartSample2State extends State { LineTooltipItem first = LineTooltipItem( '$dateFormat \n\n', TextStyle( - color: Theme.of(context).colorScheme.onBackground, + color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.bold, ), children: [ @@ -279,9 +279,7 @@ class _LineChartSample2State extends State { dotData: const FlDotData( show: false, ), - belowBarData: BarAreaData( - show: true, - color: lineColor.withOpacity(0.3)), + belowBarData: BarAreaData(show: true, color: lineColor.withOpacity(0.3)), ), LineChartBarData( spots: widget.line2Data, diff --git a/lib/custom_widgets/transactions_list.dart b/lib/custom_widgets/transactions_list.dart index 26d58447..cd01adf2 100644 --- a/lib/custom_widgets/transactions_list.dart +++ b/lib/custom_widgets/transactions_list.dart @@ -69,12 +69,10 @@ class _TransactionsListState extends State with Functions { child: Column( children: transactions.map((transaction) { int index = transactions.indexOf(transaction); - bool first = index == 0 || - !transaction.date - .isSameDate(transactions[index - 1].date); + bool first = + index == 0 || !transaction.date.isSameDate(transactions[index - 1].date); bool last = index == transactions.length - 1 || - !transaction.date - .isSameDate(transactions[index + 1].date); + !transaction.date.isSameDate(transactions[index + 1].date); return Column( children: [ @@ -137,17 +135,11 @@ class TransactionTitle extends ConsumerWidget with Functions { children: [ TextSpan( text: numToCurrency(total), - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith(color: color), + style: Theme.of(context).textTheme.bodyLarge!.copyWith(color: color), ), TextSpan( text: currencyState.selectedCurrency.symbol, - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith(color: color), + style: Theme.of(context).textTheme.labelMedium!.copyWith(color: color), ), ], ), @@ -162,8 +154,7 @@ class TransactionTitle extends ConsumerWidget with Functions { } class TransactionRow extends ConsumerWidget with Functions { - const TransactionRow(this.transaction, - {this.first = false, this.last = false, super.key}); + const TransactionRow(this.transaction, {this.first = false, this.last = false, super.key}); final Transaction transaction; final bool first; @@ -172,7 +163,7 @@ class TransactionRow extends ConsumerWidget with Functions { @override Widget build(BuildContext context, WidgetRef ref) { final currencyState = ref.watch(currencyStateNotifier); - + return Column( children: [ Material( @@ -232,12 +223,8 @@ class TransactionRow extends ConsumerWidget with Functions { if (transaction.note != null) Text( transaction.note!, - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith( - color: - Theme.of(context).colorScheme.primary, + style: Theme.of(context).textTheme.titleLarge!.copyWith( + color: Theme.of(context).colorScheme.primary, ), ), const Spacer(), @@ -250,18 +237,14 @@ class TransactionRow extends ConsumerWidget with Functions { style: Theme.of(context) .textTheme .labelLarge! - .copyWith( - color: - typeToColor(transaction.type)), + .copyWith(color: typeToColor(transaction.type)), ), TextSpan( text: currencyState.selectedCurrency.symbol, style: Theme.of(context) .textTheme .labelSmall! - .copyWith( - color: - typeToColor(transaction.type)), + .copyWith(color: typeToColor(transaction.type)), ), ], ), @@ -274,12 +257,8 @@ class TransactionRow extends ConsumerWidget with Functions { if (transaction.categoryName != null) Text( transaction.categoryName!, - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: - Theme.of(context).colorScheme.primary, + style: Theme.of(context).textTheme.labelMedium!.copyWith( + color: Theme.of(context).colorScheme.primary, ), ), const Spacer(), @@ -287,12 +266,8 @@ class TransactionRow extends ConsumerWidget with Functions { transaction.type == TransactionType.transfer ? "${transaction.bankAccountName ?? ''}→${transaction.bankAccountTransferName ?? ''}" : transaction.bankAccountName ?? '', - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: - Theme.of(context).colorScheme.primary, + style: Theme.of(context).textTheme.labelMedium!.copyWith( + color: Theme.of(context).colorScheme.primary, ), ), ], @@ -308,7 +283,7 @@ class TransactionRow extends ConsumerWidget with Functions { ), if (!last) Container( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, child: Divider( height: 1, indent: 12, diff --git a/lib/database/sossoldi_database.dart b/lib/database/sossoldi_database.dart index 775950ef..77c0e88f 100644 --- a/lib/database/sossoldi_database.dart +++ b/lib/database/sossoldi_database.dart @@ -157,7 +157,7 @@ class SossoldiDatabase { (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 @@ -240,7 +240,7 @@ class SossoldiDatabase { var randomAccount = accounts[rnd.nextInt(accounts.length)]; var randomNote = outNotes[rnd.nextInt(outNotes.length)]; var randomCategory = categories[rnd.nextInt(categories.length)]; - var idBankAccountTransfer; + int? idBankAccountTransfer; DateTime randomDate = now.subtract(Duration( days: rnd.nextInt(dateInPastMaxRange), hours: rnd.nextInt(20), diff --git a/lib/main.dart b/lib/main.dart index 049ea769..b18d9321 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,32 +1,28 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:workmanager/workmanager.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:timezone/timezone.dart' as tz; import 'model/recurring_transaction.dart'; -import 'utils/worker_manager.dart'; -import 'pages/notifications/notifications_service.dart'; import 'providers/theme_provider.dart'; import 'routes.dart'; import 'utils/app_theme.dart'; +import 'utils/notifications_service.dart'; bool? _isFirstLogin = true; void main() async { WidgetsFlutterBinding.ensureInitialized(); - - if(Platform.isAndroid){ - requestNotificationPermissions(); - initializeNotifications(); - Workmanager().initialize(callbackDispatcher); - } + NotificationService().requestNotificationPermissions(); + NotificationService().initializeNotifications(); + tz.initializeTimeZones(); + tz.setLocalLocation(tz.local); SharedPreferences preferences = await SharedPreferences.getInstance(); - bool? getPref = preferences.getBool('is_first_login'); + bool? getPref = preferences.getBool('is_first_login'); getPref == null ? await preferences.setBool('is_first_login', false) : null; _isFirstLogin = getPref; @@ -54,8 +50,7 @@ class Launcher extends ConsumerWidget { title: 'Sossoldi', theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, - themeMode: - appThemeState.isDarkModeEnabled ? ThemeMode.dark : ThemeMode.light, + themeMode: appThemeState.isDarkModeEnabled ? ThemeMode.dark : ThemeMode.light, onGenerateRoute: makeRoute, initialRoute: _isFirstLogin == null || _isFirstLogin! ? '/onboarding' : '/', ); diff --git a/lib/model/bank_account.dart b/lib/model/bank_account.dart index b33eb41d..5d7f4457 100644 --- a/lib/model/bank_account.dart +++ b/lib/model/bank_account.dart @@ -41,17 +41,18 @@ class BankAccount extends BaseEntity { final bool mainAccount; final num? total; - const BankAccount( - {super.id, - required this.name, - required this.symbol, - required this.color, - required this.startingValue, - required this.active, - required this.mainAccount, - this.total, - super.createdAt, - super.updatedAt}); + const BankAccount({ + super.id, + required this.name, + required this.symbol, + required this.color, + required this.startingValue, + required this.active, + required this.mainAccount, + this.total, + super.createdAt, + super.updatedAt, + }); BankAccount copy( {int? id, @@ -94,9 +95,8 @@ class BankAccount extends BaseEntity { BankAccountFields.startingValue: startingValue, BankAccountFields.active: active ? 1 : 0, BankAccountFields.mainAccount: mainAccount ? 1 : 0, - BaseEntityFields.createdAt: update - ? createdAt?.toIso8601String() - : DateTime.now().toIso8601String(), + BaseEntityFields.createdAt: + update ? createdAt?.toIso8601String() : DateTime.now().toIso8601String(), BaseEntityFields.updatedAt: DateTime.now().toIso8601String(), }; } @@ -205,8 +205,7 @@ class BankAccountMethods extends SossoldiDatabase { Future deleteById(int id) async { final db = await database; - return await db.delete(bankAccountTable, - where: '${BankAccountFields.id} = ?', whereArgs: [id]); + return await db.delete(bankAccountTable, where: '${BankAccountFields.id} = ?', whereArgs: [id]); } Future deactivateById(int id) async { @@ -224,8 +223,8 @@ class BankAccountMethods extends SossoldiDatabase { final db = await database; //get account infos first - final result = await db.query(bankAccountTable, - where: '${BankAccountFields.id} = $id', limit: 1); + final result = + await db.query(bankAccountTable, where: '${BankAccountFields.id} = $id', limit: 1); final singleObject = result.isNotEmpty ? result[0] : null; if (singleObject != null) { @@ -269,18 +268,18 @@ class BankAccountMethods extends SossoldiDatabase { final resultQuery = await db.rawQuery(''' SELECT t.*, - c.${CategoryTransactionFields.name} as ${TransactionFields.categoryName}, - c.${CategoryTransactionFields.color} as ${TransactionFields.categoryColor}, + c.${CategoryTransactionFields.name} as ${TransactionFields.categoryName}, + c.${CategoryTransactionFields.color} as ${TransactionFields.categoryColor}, c.${CategoryTransactionFields.symbol} as ${TransactionFields.categorySymbol} - FROM + FROM "$transactionTable" as t - LEFT JOIN - $categoryTransactionTable as c ON t.${TransactionFields.idCategory} = c.${CategoryTransactionFields.id} - WHERE + LEFT JOIN + $categoryTransactionTable as c ON t.${TransactionFields.idCategory} = c.${CategoryTransactionFields.id} + WHERE $accountFilter ORDER BY ${TransactionFields.date} DESC - LIMIT + LIMIT $numTransactions '''); @@ -322,16 +321,14 @@ class BankAccountMethods extends SossoldiDatabase { double runningTotal = statritngValue[0]['Value'] as double; var result = resultQuery.map((e) { - runningTotal += double.parse(e['income'].toString()) - - double.parse(e['expense'].toString()); + runningTotal += double.parse(e['income'].toString()) - double.parse(e['expense'].toString()); return {"day": e["day"], "balance": runningTotal}; }).toList(); if (dateRangeStart != null) { return result - .where((element) => dateRangeStart.isBefore( - DateTime.parse(element["day"].toString()) - .add(const Duration(days: 1)))) + .where((element) => dateRangeStart + .isBefore(DateTime.parse(element["day"].toString()).add(const Duration(days: 1)))) .toList(); } diff --git a/lib/model/budget.dart b/lib/model/budget.dart index 71745940..0ff773a4 100644 --- a/lib/model/budget.dart +++ b/lib/model/budget.dart @@ -31,15 +31,15 @@ class Budget extends BaseEntity { final num amountLimit; final bool active; - const Budget( - {int? id, - required this.idCategory, - this.name, - required this.amountLimit, - required this.active, - DateTime? createdAt, - DateTime? updatedAt}) - : super(id: id, createdAt: createdAt, updatedAt: updatedAt); + const Budget({ + super.id, + required this.idCategory, + this.name, + required this.amountLimit, + required this.active, + super.createdAt, + super.updatedAt, + }); Budget copy( {int? id, @@ -85,12 +85,16 @@ class BudgetStats extends BaseEntity { final num amountLimit; final num spent; - BudgetStats({required this.idCategory, required this.name, required this.amountLimit, required this.spent}); + BudgetStats( + {required this.idCategory, + required this.name, + required this.amountLimit, + required this.spent}); static BudgetStats fromJson(Map json) => BudgetStats( idCategory: json[BudgetFields.idCategory] as int, name: json[BudgetFields.name] as String?, - amountLimit: json[BudgetFields.amountLimit] as num, + amountLimit: json[BudgetFields.amountLimit] as num, spent: json['spent'] as num); Map toJson() => { @@ -113,7 +117,8 @@ class BudgetMethods extends SossoldiDatabase { final exists = await checkIfExists(item); if (exists) { - await db.rawQuery("UPDATE $budgetTable SET amountLimit = ${item.amountLimit} WHERE idCategory = ${item.idCategory}"); + await db.rawQuery( + "UPDATE $budgetTable SET amountLimit = ${item.amountLimit} WHERE idCategory = ${item.idCategory}"); } else { await db.insert(budgetTable, item.toJson()); } @@ -125,8 +130,9 @@ class BudgetMethods extends SossoldiDatabase { final db = await database; try { - final exists = await db.rawQuery("SELECT * FROM ${budgetTable} WHERE ${item.idCategory} = idCategory"); - if(exists.isNotEmpty) { + final exists = + await db.rawQuery("SELECT * FROM $budgetTable WHERE ${item.idCategory} = idCategory"); + if (exists.isNotEmpty) { return true; } return false; @@ -170,11 +176,8 @@ class BudgetMethods extends SossoldiDatabase { Future> selectMonthlyBudgetsStats() async { final db = await database; - var query = "SELECT bt.*, SUM(t.amount) as spent FROM $budgetTable as bt " - + " LEFT JOIN $categoryTransactionTable as ct ON bt.${BudgetFields.idCategory} = ct.${CategoryTransactionFields.id} " - + " LEFT JOIN '$transactionTable' as t ON t.${TransactionFields.idCategory} = ct.${CategoryTransactionFields.id} " - + " WHERE bt.active = 1 AND strftime('%m', t.date) = strftime('%m', 'now') AND strftime('%Y', t.date) = strftime('%Y', 'now') " - + " GROUP BY bt.${BudgetFields.idCategory};"; + var query = + "SELECT bt.*, SUM(t.amount) as spent FROM $budgetTable as bt LEFT JOIN $categoryTransactionTable as ct ON bt.${BudgetFields.idCategory} = ct.${CategoryTransactionFields.id} LEFT JOIN '$transactionTable' as t ON t.${TransactionFields.idCategory} = ct.${CategoryTransactionFields.id} WHERE bt.active = 1 AND strftime('%m', t.date) = strftime('%m', 'now') AND strftime('%Y', t.date) = strftime('%Y', 'now') GROUP BY bt.${BudgetFields.idCategory};"; final result = await db.rawQuery(query); return result.map((json) => BudgetStats.fromJson(json)).toList(); } diff --git a/lib/model/currency.dart b/lib/model/currency.dart index 8f3a7a86..ec275b13 100644 --- a/lib/model/currency.dart +++ b/lib/model/currency.dart @@ -25,20 +25,15 @@ class Currency extends BaseEntity { final String name; final bool mainCurrency; - const Currency( - {int? id, - required this.symbol, - required this.code, - required this.name, - required this.mainCurrency}) - : super(id: id); - - Currency copy( - {int? id, - String? symbol, - String? code, - String? name, - bool? mainCurrency,t}) => + const Currency({ + super.id, + required this.symbol, + required this.code, + required this.name, + required this.mainCurrency, + }); + + Currency copy({int? id, String? symbol, String? code, String? name, bool? mainCurrency, t}) => Currency( id: id ?? this.id, symbol: symbol ?? this.symbol, @@ -78,12 +73,7 @@ class CurrencyMethods extends SossoldiDatabase { } else { //fallback return const Currency( - id: 2, - symbol: '\$', - code: 'USD', - name: "United States Dollar", - mainCurrency: true - ); + id: 2, symbol: '\$', code: 'USD', name: "United States Dollar", mainCurrency: true); } } @@ -95,7 +85,7 @@ class CurrencyMethods extends SossoldiDatabase { Future insertAll(List list) async { final db = await database; - for(Currency currency in list){ + for (Currency currency in list) { await db.insert(currencyTable, currency.toJson()); } } @@ -133,8 +123,7 @@ class CurrencyMethods extends SossoldiDatabase { return db.update( currencyTable, item.toJson(), - where: - '${CurrencyFields.id} = ?', + where: '${CurrencyFields.id} = ?', whereArgs: [item.id], ); } @@ -142,10 +131,7 @@ class CurrencyMethods extends SossoldiDatabase { Future deleteById(int id) async { final db = await database; - return await db.delete(currencyTable, - where: - '${CurrencyFields.id} = ?', - whereArgs: [id]); + return await db.delete(currencyTable, where: '${CurrencyFields.id} = ?', whereArgs: [id]); } void changeMainCurrency(int id) async { @@ -154,5 +140,4 @@ class CurrencyMethods extends SossoldiDatabase { db.rawUpdate("UPDATE currency SET mainCurrency = 0"); db.rawUpdate("UPDATE currency SET mainCurrency = 1 WHERE id = $id"); } - -} \ No newline at end of file +} diff --git a/lib/pages/accounts/account_list.dart b/lib/pages/accounts/account_list.dart index e454a429..bef7478a 100644 --- a/lib/pages/accounts/account_list.dart +++ b/lib/pages/accounts/account_list.dart @@ -52,7 +52,7 @@ class _AccountListState extends ConsumerState with Functions { child: Icon( Icons.account_balance_wallet, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), const SizedBox(width: 12.0), @@ -95,7 +95,7 @@ class _AccountListState extends ConsumerState with Functions { ? Icon( icon, size: 30.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ) : const SizedBox(), ), diff --git a/lib/pages/accounts/add_account.dart b/lib/pages/accounts/add_account.dart index 25fe235b..7dda91cb 100644 --- a/lib/pages/accounts/add_account.dart +++ b/lib/pages/accounts/add_account.dart @@ -46,7 +46,7 @@ class _AddAccountState extends ConsumerState with Functions { final currencyState = ref.watch(currencyStateNotifier); return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, appBar: AppBar(title: Text("${selectedAccount == null ? "New" : "Edit"} account")), body: Column( children: [ @@ -120,7 +120,7 @@ class _AddAccountState extends ConsumerState with Functions { child: Icon( accountIconList[accountIcon], size: 48, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -390,7 +390,11 @@ class _AddAccountState extends ConsumerState with Functions { } else { ref .read(accountsProvider.notifier) - .addAccount(nameController.text, startingValueController.text.isEmpty ? null : currencyToNum(startingValueController.text)) + .addAccount( + nameController.text, + startingValueController.text.isEmpty + ? null + : currencyToNum(startingValueController.text)) .whenComplete(() => Navigator.of(context).pop()); } }, @@ -403,7 +407,7 @@ class _AddAccountState extends ConsumerState with Functions { style: Theme.of(context) .textTheme .bodyLarge! - .copyWith(color: Theme.of(context).colorScheme.background), + .copyWith(color: Theme.of(context).colorScheme.onPrimary), ), ), ), diff --git a/lib/pages/add_page/add_page.dart b/lib/pages/add_page/add_page.dart index ca885cb1..a87e4bf8 100644 --- a/lib/pages/add_page/add_page.dart +++ b/lib/pages/add_page/add_page.dart @@ -31,10 +31,8 @@ class _AddPageState extends ConsumerState with Functions { @override void initState() { - amountController.text = - numToCurrency(ref.read(selectedTransactionUpdateProvider)?.amount); - noteController.text = - ref.read(selectedTransactionUpdateProvider)?.note ?? ''; + amountController.text = numToCurrency(ref.read(selectedTransactionUpdateProvider)?.amount); + noteController.text = ref.read(selectedTransactionUpdateProvider)?.note ?? ''; amountController.addListener(_updateAmount); @@ -62,8 +60,7 @@ class _AddPageState extends ConsumerState with Functions { String getCleanAmountString() { // Remove all non-numeric characters - var cleanNumberString = - amountController.text.replaceAll(RegExp(r'[^0-9\.]'), ''); + var cleanNumberString = amountController.text.replaceAll(RegExp(r'[^0-9\.]'), ''); // Remove leading zeros return cleanNumberString.replaceAll(RegExp(r'^[0\.]+(?=.)'), ''); @@ -356,7 +353,7 @@ class _AddPageState extends ConsumerState with Functions { style: Theme.of(context) .textTheme .bodyLarge! - .copyWith(color: Theme.of(context).colorScheme.background), + .copyWith(color: Theme.of(context).colorScheme.onPrimary), ), ), ), diff --git a/lib/pages/add_page/widgets/account_selector.dart b/lib/pages/add_page/widgets/account_selector.dart index fb651540..c3c8b5b7 100644 --- a/lib/pages/add_page/widgets/account_selector.dart +++ b/lib/pages/add_page/widgets/account_selector.dart @@ -91,7 +91,7 @@ class _AccountSelectorState extends ConsumerState with Function ? Icon( icon, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ) : const SizedBox(), ), @@ -147,7 +147,7 @@ class _AccountSelectorState extends ConsumerState with Function ? Icon( icon, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ) : const SizedBox(), ), diff --git a/lib/pages/add_page/widgets/amount_section.dart b/lib/pages/add_page/widgets/amount_section.dart index 1a8fa194..37c76da9 100644 --- a/lib/pages/add_page/widgets/amount_section.dart +++ b/lib/pages/add_page/widgets/amount_section.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import "package:flutter_riverpod/flutter_riverpod.dart"; import '../../../constants/functions.dart'; import "../../../constants/style.dart"; import '../../../model/transaction.dart'; -import '../../../providers/currency_provider.dart'; +// import '../../../providers/currency_provider.dart'; import '../../../providers/transactions_provider.dart'; import '../../../pages/add_page/widgets/amount_widget.dart'; import 'account_selector.dart'; @@ -45,7 +44,7 @@ class _AmountSectionState extends ConsumerState with Functions { Widget build(BuildContext context) { final trsncTypeList = ref.watch(transactionTypeList); final selectedType = ref.watch(transactionTypeProvider); - final currencyState = ref.watch(currencyStateNotifier); + // final currencyState = ref.watch(currencyStateNotifier); return Container( color: Theme.of(context).colorScheme.surface, @@ -55,7 +54,7 @@ class _AmountSectionState extends ConsumerState with Functions { Container( height: 30, decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, borderRadius: const BorderRadius.all(Radius.circular(4)), ), padding: const EdgeInsets.symmetric(horizontal: 2), diff --git a/lib/pages/add_page/widgets/category_selector.dart b/lib/pages/add_page/widgets/category_selector.dart index b07cfe90..fe318820 100644 --- a/lib/pages/add_page/widgets/category_selector.dart +++ b/lib/pages/add_page/widgets/category_selector.dart @@ -73,8 +73,7 @@ class _CategorySelectorState extends ConsumerState Color? color = categoryColorListTheme[category.color]; return GestureDetector( onTap: () => { - ref.read(categoryProvider.notifier).state = - category, + ref.read(categoryProvider.notifier).state = category, Navigator.of(context).pop(), }, child: Padding( @@ -157,7 +156,7 @@ class _CategorySelectorState extends ConsumerState icon, size: 24.0, color: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, ) : const SizedBox(), ), diff --git a/lib/pages/add_page/widgets/details_list_disabled_tile.dart b/lib/pages/add_page/widgets/details_list_disabled_tile.dart index ed419555..353d327e 100644 --- a/lib/pages/add_page/widgets/details_list_disabled_tile.dart +++ b/lib/pages/add_page/widgets/details_list_disabled_tile.dart @@ -1,21 +1,16 @@ import "package:flutter/material.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; -import "../../../constants/style.dart"; import "details_list_tile.dart"; class NonEditableDetailsListTile extends DetailsListTile { NonEditableDetailsListTile({ - required String title, - required IconData icon, - required String? value, - Key? key, + required super.title, + required super.icon, + required super.value, + super.key, }) : super( - title: title, - icon: icon, - value: value, - callback: () {}, // Override the callback to make it non-editable - key: key, + callback: () {}, ); @override @@ -33,7 +28,7 @@ class NonEditableDetailsListTile extends DetailsListTile { child: Icon( icon, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), title: Text( diff --git a/lib/pages/add_page/widgets/details_list_tile.dart b/lib/pages/add_page/widgets/details_list_tile.dart index 084a2558..f294cb51 100644 --- a/lib/pages/add_page/widgets/details_list_tile.dart +++ b/lib/pages/add_page/widgets/details_list_tile.dart @@ -9,8 +9,8 @@ class DetailsListTile extends ConsumerWidget { required this.icon, required this.value, required this.callback, - Key? key, - }) : super(key: key); + super.key, + }); final String title; final IconData icon; @@ -32,7 +32,7 @@ class DetailsListTile extends ConsumerWidget { child: Icon( icon, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), title: Text( @@ -47,8 +47,7 @@ class DetailsListTile extends ConsumerWidget { children: [ Text( value ?? '', - style: - Theme.of(context) + style: Theme.of(context) .textTheme .bodySmall! .copyWith(color: Theme.of(context).colorScheme.secondary), diff --git a/lib/pages/add_page/widgets/label_list_tile.dart b/lib/pages/add_page/widgets/label_list_tile.dart index b4be38f5..8e23424c 100644 --- a/lib/pages/add_page/widgets/label_list_tile.dart +++ b/lib/pages/add_page/widgets/label_list_tile.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import "../../../constants/style.dart"; - class LabelListTile extends StatelessWidget { const LabelListTile( this.labelController, { @@ -26,7 +24,7 @@ class LabelListTile extends StatelessWidget { child: Icon( Icons.description, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -42,8 +40,8 @@ class LabelListTile extends StatelessWidget { Expanded( child: TextField( controller: labelController, - decoration: const InputDecoration( - border: InputBorder.none, hintText: "Add a description"), + decoration: + const InputDecoration(border: InputBorder.none, hintText: "Add a description"), textAlign: TextAlign.end, style: Theme.of(context) .textTheme diff --git a/lib/pages/add_page/widgets/recurrence_list_tile.dart b/lib/pages/add_page/widgets/recurrence_list_tile.dart index 1d0f5934..276d3eea 100644 --- a/lib/pages/add_page/widgets/recurrence_list_tile.dart +++ b/lib/pages/add_page/widgets/recurrence_list_tile.dart @@ -41,7 +41,7 @@ class RecurrenceListTile extends ConsumerWidget with Functions { child: Icon( Icons.autorenew, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -88,7 +88,7 @@ class RecurrenceListTile extends ConsumerWidget with Functions { opacity: selectedTransaction == null || recurrencyEditingPermitted ? 1.0 : 0.5, child: TextButton( style: TextButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4)), @@ -134,7 +134,7 @@ class RecurrenceListTile extends ConsumerWidget with Functions { opacity: selectedTransaction == null || recurrencyEditingPermitted ? 1.0 : 0.5, child: TextButton( style: TextButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4)), diff --git a/lib/pages/add_page/widgets/recurrence_list_tile_edit.dart b/lib/pages/add_page/widgets/recurrence_list_tile_edit.dart index 8032603a..449982a8 100644 --- a/lib/pages/add_page/widgets/recurrence_list_tile_edit.dart +++ b/lib/pages/add_page/widgets/recurrence_list_tile_edit.dart @@ -35,7 +35,7 @@ class RecurrenceListTileEdit extends ConsumerWidget with Functions { child: Icon( Icons.autorenew, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -52,7 +52,7 @@ class RecurrenceListTileEdit extends ConsumerWidget with Functions { padding: const EdgeInsets.symmetric(horizontal: 16), child: TextButton( style: TextButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4)), @@ -93,7 +93,7 @@ class RecurrenceListTileEdit extends ConsumerWidget with Functions { padding: const EdgeInsets.all(16), child: TextButton( style: TextButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4)), diff --git a/lib/pages/add_page/widgets/type_tab.dart b/lib/pages/add_page/widgets/type_tab.dart index da79edf8..db5e9e2a 100644 --- a/lib/pages/add_page/widgets/type_tab.dart +++ b/lib/pages/add_page/widgets/type_tab.dart @@ -6,8 +6,8 @@ class TypeTab extends StatelessWidget { this.selectedType, this.title, this.color, { - Key? key, - }) : super(key: key); + super.key, + }); final bool selectedType; final String title; diff --git a/lib/pages/categories/add_category.dart b/lib/pages/categories/add_category.dart index 89072b2f..80bb2ef3 100644 --- a/lib/pages/categories/add_category.dart +++ b/lib/pages/categories/add_category.dart @@ -38,7 +38,7 @@ class _AddCategoryState extends ConsumerState with Functions { final categoryColor = ref.watch(categoryColorProvider); final showCategoryIcons = ref.watch(showCategoryIconsProvider); return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, appBar: AppBar(title: Text("${selectedCategory == null ? "New" : "Edit"} Category")), body: Stack( children: [ @@ -151,7 +151,7 @@ class _AddCategoryState extends ConsumerState with Functions { child: Icon( iconList[categoryIcon], size: 48, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -328,7 +328,7 @@ class _AddCategoryState extends ConsumerState with Functions { ) ], ), - padding: const EdgeInsets.only(left:24 ,right: 24, top: 16, bottom: 30), + padding: const EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 30), child: Container( decoration: BoxDecoration( boxShadow: [defaultShadow], @@ -336,7 +336,7 @@ class _AddCategoryState extends ConsumerState with Functions { ), child: TextButton( onPressed: () async { - if(nameController.text.isNotEmpty) { + if (nameController.text.isNotEmpty) { if (selectedCategory != null) { ref .read(categoriesProvider.notifier) @@ -363,7 +363,7 @@ class _AddCategoryState extends ConsumerState with Functions { style: Theme.of(context) .textTheme .bodyLarge! - .copyWith(color: Theme.of(context).colorScheme.background), + .copyWith(color: Theme.of(context).colorScheme.onPrimary), ), ), ), diff --git a/lib/pages/categories/category_list.dart b/lib/pages/categories/category_list.dart index 48cfe79a..ce68ac35 100644 --- a/lib/pages/categories/category_list.dart +++ b/lib/pages/categories/category_list.dart @@ -52,7 +52,7 @@ class _CategoryListState extends ConsumerState with Functions { child: Icon( Icons.list_alt, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), const SizedBox(width: 12.0), @@ -93,7 +93,7 @@ class _CategoryListState extends ConsumerState with Functions { ? Icon( icon, size: 30.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ) : const SizedBox(), ), diff --git a/lib/pages/general_options/general_settings.dart b/lib/pages/general_options/general_settings.dart index 353daaab..3c15be34 100644 --- a/lib/pages/general_options/general_settings.dart +++ b/lib/pages/general_options/general_settings.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:intl/intl.dart'; import '../../constants/style.dart'; import '../../model/currency.dart'; @@ -12,8 +11,7 @@ class GeneralSettingsPage extends ConsumerStatefulWidget { const GeneralSettingsPage({super.key}); @override - ConsumerState createState() => - _GeneralSettingsPageState(); + ConsumerState createState() => _GeneralSettingsPageState(); } class _GeneralSettingsPageState extends ConsumerState { @@ -58,8 +56,10 @@ class _GeneralSettingsPageState extends ConsumerState { Row( children: [ Text("Appearance", - style: Theme.of(context).textTheme.titleLarge!.copyWith( - color: Theme.of(context).colorScheme.primary)), + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary)), const Spacer(), CircleAvatar( radius: 30.0, @@ -69,21 +69,15 @@ class _GeneralSettingsPageState extends ConsumerState { onPressed: () { // Toggle dark mode using the provider if (appThemeState.isDarkModeEnabled) { - ref - .read(appThemeStateNotifier.notifier) - .setLightTheme(); + ref.read(appThemeStateNotifier.notifier).setLightTheme(); } else { - ref - .read(appThemeStateNotifier.notifier) - .setDarkTheme(); + ref.read(appThemeStateNotifier.notifier).setDarkTheme(); } }, icon: Icon( - appThemeState.isDarkModeEnabled - ? Icons.dark_mode - : Icons.light_mode, + appThemeState.isDarkModeEnabled ? Icons.dark_mode : Icons.light_mode, size: 25.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), )), ], @@ -92,13 +86,16 @@ class _GeneralSettingsPageState extends ConsumerState { Row( children: [ Text("Currency", - style: Theme.of(context).textTheme.titleLarge!.copyWith( - color: Theme.of(context).colorScheme.primary)), + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary)), const Spacer(), GestureDetector( onTap: () { setState(() { - CurrencySelectorDialog.selectCurrencyDialog(context, currencyState, currencyList); + CurrencySelectorDialog.selectCurrencyDialog( + context, currencyState, currencyList); }); }, child: CircleAvatar( @@ -108,8 +105,7 @@ class _GeneralSettingsPageState extends ConsumerState { child: Text( currencyState.selectedCurrency.symbol, style: TextStyle( - color: Theme.of(context).colorScheme.background, - fontSize: 25), + color: Theme.of(context).colorScheme.onPrimary, fontSize: 25), )))), ], ), diff --git a/lib/pages/general_options/widgets/currency_selector.dart b/lib/pages/general_options/widgets/currency_selector.dart index 838ec39d..ddd90854 100644 --- a/lib/pages/general_options/widgets/currency_selector.dart +++ b/lib/pages/general_options/widgets/currency_selector.dart @@ -5,73 +5,73 @@ import '../../../model/currency.dart'; import '../../../providers/currency_provider.dart'; class CurrencySelectorDialog { - static void selectCurrencyDialog(BuildContext context, CurrencyState state, - Future> currencies) { + static void selectCurrencyDialog( + BuildContext context, CurrencyState state, Future> currencies) { showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Select a currency', - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary)), - content: SizedBox( - height: 300, - width: 220, - child: SingleChildScrollView( - child: FutureBuilder( - future: currencies, - builder: (context, snapshot) { - if (snapshot.hasData && - snapshot.data != null && - snapshot.connectionState == ConnectionState.done) { - return ListView.builder( - itemCount: snapshot.data!.length, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int i) { - return GestureDetector( - onTap: () { - state.setSelectedCurrency( - snapshot.data![i]); - Navigator.pop(context); - }, - child: ListTile( - leading: CircleAvatar( - radius: 22, - backgroundColor: - state.selectedCurrency.code == - snapshot.data![i].code - ? blue5 - : grey1, - child: Text(snapshot.data![i].symbol, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .background, - fontSize: 20)), - ), - title: Text( - snapshot.data![i].name, - textAlign: TextAlign.center, - ), - )); - }); - } else if (snapshot.hasError) { - return Text( - 'Something went wrong: ${snapshot.error}'); - } else { - if (snapshot.connectionState == - ConnectionState.waiting) { - return Transform.scale( - scale: 0.5, - child: const CircularProgressIndicator(), - ); - } else { - return const Text("Search for a transaction"); - } - } - }), - )))); + context: context, + builder: (context) => AlertDialog( + title: Text( + 'Select a currency', + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + content: SizedBox( + height: 300, + width: 220, + child: SingleChildScrollView( + child: FutureBuilder( + future: currencies, + builder: (context, snapshot) { + if (snapshot.hasData && + snapshot.data != null && + snapshot.connectionState == ConnectionState.done) { + return ListView.builder( + itemCount: snapshot.data!.length, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext context, int i) { + return GestureDetector( + onTap: () { + state.setSelectedCurrency(snapshot.data![i]); + Navigator.pop(context); + }, + child: ListTile( + leading: CircleAvatar( + radius: 22, + backgroundColor: state.selectedCurrency.code == snapshot.data![i].code + ? blue5 + : grey1, + child: Text(snapshot.data![i].symbol, + style: TextStyle( + color: Theme.of(context).colorScheme.onPrimary, + fontSize: 20)), + ), + title: Text( + snapshot.data![i].name, + textAlign: TextAlign.center, + ), + ), + ); + }, + ); + } else if (snapshot.hasError) { + return Text('Something went wrong: ${snapshot.error}'); + } else { + if (snapshot.connectionState == ConnectionState.waiting) { + return Transform.scale( + scale: 0.5, + child: const CircularProgressIndicator(), + ); + } else { + return const Text("Search for a transaction"); + } + } + }), + ), + ), + ), + ); } } diff --git a/lib/pages/graphs_page/graphs_page.dart b/lib/pages/graphs_page/graphs_page.dart index d0c681e5..bbb2cd3b 100644 --- a/lib/pages/graphs_page/graphs_page.dart +++ b/lib/pages/graphs_page/graphs_page.dart @@ -69,8 +69,7 @@ class _GraphsPageState extends ConsumerState with Functions { .isNotEmpty ? numToCurrency( currentYearMonthlyTransactions - .last.y ?? - 0) + .last.y) : '0', style: Theme.of(context) .textTheme diff --git a/lib/pages/graphs_page/widgets/categories/categories_bar_chart.dart b/lib/pages/graphs_page/widgets/categories/categories_bar_chart.dart index bc6b06d2..e572fd12 100644 --- a/lib/pages/graphs_page/widgets/categories/categories_bar_chart.dart +++ b/lib/pages/graphs_page/widgets/categories/categories_bar_chart.dart @@ -141,7 +141,6 @@ class CategoriesBarChart extends ConsumerWidget { enabled: true, handleBuiltInTouches: true, touchTooltipData: BarTouchTooltipData( - tooltipBgColor: Colors.transparent, tooltipPadding: EdgeInsets.zero, tooltipMargin: 0, getTooltipItem: (group, groupIndex, rod, rodIndex) => diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index bc9ff21f..27511391 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -26,7 +26,7 @@ class _HomePageState extends ConsumerState with Functions { final accountList = ref.watch(accountsProvider); final lastTransactions = ref.watch(lastTransactionsProvider); final currencyState = ref.watch(currencyStateNotifier); - + return Container( color: Theme.of(context).colorScheme.tertiary, child: ListView( @@ -227,10 +227,10 @@ class _HomePageState extends ConsumerState with Functions { ), child: TextButton.icon( style: ButtonStyle( - maximumSize: MaterialStateProperty.all(const Size(130, 48)), - backgroundColor: MaterialStateProperty.all( + maximumSize: WidgetStateProperty.all(const Size(130, 48)), + backgroundColor: WidgetStateProperty.all( Theme.of(context).colorScheme.surface), - shape: MaterialStateProperty.all( + shape: WidgetStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -264,11 +264,9 @@ class _HomePageState extends ConsumerState with Functions { ), ), ); - } else if(accounts.isNotEmpty) { - BankAccount account = accounts[i]; - return AccountsSum(account: account); } - + BankAccount account = accounts[i]; + return AccountsSum(account: account); }, ), loading: () => const SizedBox(), @@ -291,7 +289,7 @@ class _HomePageState extends ConsumerState with Functions { error: (err, stack) => Text('Error: $err'), ), const SizedBox(height: 28), - BudgetsSection() + const BudgetsSection(), ], ), ), diff --git a/lib/pages/more_info_page/collaborators_page.dart b/lib/pages/more_info_page/collaborators_page.dart index b0909bc2..0b176363 100644 --- a/lib/pages/more_info_page/collaborators_page.dart +++ b/lib/pages/more_info_page/collaborators_page.dart @@ -75,12 +75,13 @@ var collaborators = const [ ] ]; + class _CollaboratorsPageState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, elevation: 0, centerTitle: true, leading: IconButton( @@ -102,16 +103,16 @@ class _CollaboratorsPageState extends ConsumerState { ), ), body: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Padding( - padding: EdgeInsets.all(8.0), + physics: const BouncingScrollPhysics(), + child: + Padding(padding: const EdgeInsets.all(8.0), child: Column( children: [ ListView.separated( itemCount: collaborators.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => Divider(), + separatorBuilder: (context, index) => const Divider(), itemBuilder: (context, i) { List option = collaborators[i]; return InkWell( @@ -126,37 +127,19 @@ class _CollaboratorsPageState extends ConsumerState { children: [ Text( option[0].toString(), - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith( - color: Theme.of(context) - .colorScheme - .primary), + style: Theme.of(context).textTheme.titleLarge!.copyWith(color: Theme.of(context).colorScheme.primary), textAlign: TextAlign.left, ), const SizedBox(height: 4), Text( option[1].toString(), - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .primary), + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Theme.of(context).colorScheme.primary), textAlign: TextAlign.left, ), const SizedBox(height: 4), Text( option[2].toString(), - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: Theme.of(context) - .colorScheme - .primary), + style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Theme.of(context).colorScheme.primary), textAlign: TextAlign.left, ), ], @@ -165,9 +148,11 @@ class _CollaboratorsPageState extends ConsumerState { ); }, ), + ], ), - )), + ) + ), ); } } diff --git a/lib/pages/more_info_page/privacy_policy.dart b/lib/pages/more_info_page/privacy_policy.dart index 2b8eae2e..4d7809ed 100644 --- a/lib/pages/more_info_page/privacy_policy.dart +++ b/lib/pages/more_info_page/privacy_policy.dart @@ -36,7 +36,7 @@ class _PrivacyPolicyPageState extends ConsumerState { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.onPrimary, elevation: 0, centerTitle: true, leading: IconButton( @@ -44,10 +44,7 @@ class _PrivacyPolicyPageState extends ConsumerState { Icons.arrow_back_ios_new, color: Color(0XFF7DA1C4), ), - onPressed: () { - Navigator.pop(context); - // Return to previous page - }, + onPressed: () => Navigator.pop(context), ), title: Text( 'Privacy Policy', @@ -58,85 +55,86 @@ class _PrivacyPolicyPageState extends ConsumerState { ), ), body: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Padding( - padding: EdgeInsets.all(16.0), - child: Column( - children: [ - Text( - 'Sossoldi is build as an open source app. This service is provided by us at no cost and it is intended for use as is.\nWe are not interested in collecting any personal information. We believe such information is yours and yours alone. We do not store or transmit your personal details, nor do we include any advertising or analytics software that talks to third parties.\n', + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Text( + 'Sossoldi is build as an open source app. This service is provided by us at no cost and it is intended for use as is.\nWe are not interested in collecting any personal information. We believe such information is yours and yours alone. We do not store or transmit your personal details, nor do we include any advertising or analytics software that talks to third parties.\n', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + Text( + 'What Information Do We Collect?\n', + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + Text( + "Sossoldi does not collect any personal information or connect to the internet. Any information that you add in the app exist solely on your device and no where else.\n", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + Text( + 'Changes to This Privacy Policy\n', + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + Text( + 'We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes./nThis policy is effective as of 2024-01-01\n', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + Text( + 'Contact us\n', + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + RichText( + text: TextSpan( + text: + 'If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us at ', style: Theme.of(context) .textTheme .bodyMedium! .copyWith(color: Theme.of(context).colorScheme.primary), - ), - Text( - 'What Information Do We Collect?\n', - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - Text( - "Sossoldi does not collect any personal information or connect to the internet. Any information that you add in the app exist solely on your device and no where else.\n", - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - Text( - 'Changes to This Privacy Policy\n', - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - Text( - 'We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes./nThis policy is effective as of 2024-01-01\n', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - Text( - 'Contact us\n', - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Theme.of(context).colorScheme.primary), - ), - RichText( - text: TextSpan( - text: - 'If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us at ', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Theme.of(context).colorScheme.primary), - children: [ - TextSpan( - text: 'help.sossoldi@gmail.com', - style: const TextStyle( - color: Colors.blue, - decoration: TextDecoration.underline, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - launchUrl(Uri( - scheme: 'mailto', - path: 'help.sossoldi@gmail.com', - queryParameters: { - 'subject': 'Request info', - }, - )); - }, + children: [ + TextSpan( + text: 'help.sossoldi@gmail.com', + style: const TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, ), - ], - ), - ) - ], - ), - )), + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrl(Uri( + scheme: 'mailto', + path: 'help.sossoldi@gmail.com', + queryParameters: { + 'subject': 'Request info', + }, + )); + }, + ), + ], + ), + ) + ], + ), + ), + ), ); } } diff --git a/lib/pages/notifications/notifications_service.dart b/lib/pages/notifications/notifications_service.dart deleted file mode 100644 index 668a19eb..00000000 --- a/lib/pages/notifications/notifications_service.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:permission_handler/permission_handler.dart'; - -final FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin(); - -const AndroidNotificationChannel channel = AndroidNotificationChannel( - 'sossoldi#reminder', // id del canale - 'Reminder', // nome del canale - importance: Importance.high, -); - -void initializeNotifications() async { - var initializationSettingsAndroid = const AndroidInitializationSettings('@mipmap/ic_launcher'); - var initializationSettingsIOS = const DarwinInitializationSettings(); - var initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS); - notificationsPlugin.initialize(initializationSettings); - await notificationsPlugin.resolvePlatformSpecificImplementation()?.createNotificationChannel(channel); -} - -void requestNotificationPermissions() async { - await Permission.notification.request(); -} diff --git a/lib/pages/notifications/notifications_settings.dart b/lib/pages/notifications/notifications_settings.dart index 4a5eba6d..7da5d284 100644 --- a/lib/pages/notifications/notifications_settings.dart +++ b/lib/pages/notifications/notifications_settings.dart @@ -4,31 +4,20 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../constants/style.dart'; import '../../providers/settings_provider.dart'; -import '../../utils/worker_manager.dart'; -import 'widgets/NotificationTypeTile.dart'; +import 'widgets/notification_type_tile.dart'; class NotificationsSettings extends ConsumerStatefulWidget { const NotificationsSettings({super.key}); @override - ConsumerState createState() => - _NotificationsSettingsState(); + ConsumerState createState() => _NotificationsSettingsState(); } class _NotificationsSettingsState extends ConsumerState { - - void setNotificationTypeCallback(NotificationReminderType type) { - setState(() { - ref.watch(transactionReminderCadenceProvider.notifier).state = type; - ref.read(settingsProvider.notifier).updateNotifications(); - scheduleTransactionReminder(type); - }); - } - @override Widget build(BuildContext context) { final isReminderEnabled = ref.watch(transactionReminderSwitchProvider); - final notificationSettings = ref.watch(settingsProvider); + ref.listen(settingsProvider, (_, __) {}); return Scaffold( appBar: AppBar( @@ -42,8 +31,7 @@ class _NotificationsSettingsState extends ConsumerState { child: Column( children: [ Padding( - padding: - const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0), + padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0), child: Row( children: [ Container( @@ -55,7 +43,7 @@ class _NotificationsSettingsState extends ConsumerState { child: Icon( Icons.notifications_active, size: 24.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), const SizedBox(width: 12.0), @@ -77,51 +65,56 @@ class _NotificationsSettingsState extends ConsumerState { color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(4), ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Column( children: [ - Expanded( - child: Text( - "Add transactions reminder", - style: Theme.of(context).textTheme.bodyMedium, - ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + "Add transactions reminder", + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + CupertinoSwitch( + value: isReminderEnabled, + onChanged: (value) { + ref.read(transactionReminderSwitchProvider.notifier).state = value; + ref + .read(settingsProvider.notifier) + .updateNotificationReminder(active: value); + }, + ), + ], ), - CupertinoSwitch( - value: isReminderEnabled, - onChanged: (value) { - ref - .read(transactionReminderSwitchProvider.notifier) - .state = value; - ref.read(settingsProvider.notifier).updateNotifications(); - toggleTransactionReminder(value); - }, + AnimatedCrossFade( + crossFadeState: + isReminderEnabled ? CrossFadeState.showSecond : CrossFadeState.showFirst, + duration: const Duration(milliseconds: 150), + firstChild: const SizedBox(), + secondChild: Column( + children: NotificationReminderType.values + .where((type) => type != NotificationReminderType.none) + .map((type) { + return NotificationTypeTile( + type: type, + setNotificationTypeCallback: () { + ref.watch(transactionReminderCadenceProvider.notifier).state = type; + ref.read(settingsProvider.notifier).updateNotificationReminder(); + }, + ); + }).toList(), + ), ), ], ), ), - AnimatedCrossFade( - crossFadeState: isReminderEnabled - ? CrossFadeState.showSecond - : CrossFadeState.showFirst, - duration: const Duration(milliseconds: 150), - firstChild: Container(), - secondChild: Column( - children: [ - NotificationTypeTile(type: NotificationReminderType.daily, setNotificationTypeCallback: () => setNotificationTypeCallback(NotificationReminderType.daily)), - NotificationTypeTile(type: NotificationReminderType.weekly, setNotificationTypeCallback: () => setNotificationTypeCallback(NotificationReminderType.weekly)), - NotificationTypeTile(type: NotificationReminderType.monthly, setNotificationTypeCallback: () => setNotificationTypeCallback(NotificationReminderType.monthly)) - ], - ), - ), Container( alignment: Alignment.centerLeft, padding: const EdgeInsets.only(left: 28, top: 24, bottom: 8), child: Text( "RECURRING TRANSACTIONS", - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith(color: grey1), + style: Theme.of(context).textTheme.labelLarge!.copyWith(color: grey1), ), ), Container( @@ -146,46 +139,39 @@ class _NotificationsSettingsState extends ConsumerState { CupertinoSwitch( value: ref.watch(transactionRecAddedSwitchProvider), onChanged: (value) { - ref - .read(transactionRecAddedSwitchProvider.notifier) - .state = value; - ref - .read(settingsProvider.notifier) - .updateNotifications(); - }, - ), - ], - ), - const SizedBox(height: 12), - Divider( - height: 1, - color: - Theme.of(context).colorScheme.primary.withOpacity(0.4), - ), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - "Recurring transaction reminder", - style: Theme.of(context).textTheme.bodyMedium, - ), - ), - CupertinoSwitch( - value: ref.watch(transactionRecReminderSwitchProvider), - onChanged: (value) { - ref - .read( - transactionRecReminderSwitchProvider.notifier) - .state = value; + ref.read(transactionRecAddedSwitchProvider.notifier).state = value; ref .read(settingsProvider.notifier) - .updateNotifications(); + .updateNotificationRecurring(active: value); }, ), ], ), + // TODO: Implement this feature + // const SizedBox(height: 12), + // Divider( + // height: 1, + // color: Theme.of(context).colorScheme.primary.withOpacity(0.4), + // ), + // const SizedBox(height: 12), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Expanded( + // child: Text( + // "Recurring transaction reminder", + // style: Theme.of(context).textTheme.bodyMedium, + // ), + // ), + // CupertinoSwitch( + // value: ref.watch(transactionRecReminderSwitchProvider), + // onChanged: (value) { + // ref.read(transactionRecReminderSwitchProvider.notifier).state = value; + // ref.read(settingsProvider.notifier).updateNotifications(active: value); + // }, + // ), + // ], + // ), ], ), ), @@ -194,10 +180,7 @@ class _NotificationsSettingsState extends ConsumerState { padding: const EdgeInsets.only(left: 28, top: 6), child: Text( "Remind me before a recurring transaction is added", - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith(color: grey1), + style: Theme.of(context).textTheme.labelMedium!.copyWith(color: grey1), ), ), ], diff --git a/lib/pages/notifications/widgets/NotificationTypeTile.dart b/lib/pages/notifications/widgets/NotificationTypeTile.dart deleted file mode 100644 index 2a25d558..00000000 --- a/lib/pages/notifications/widgets/NotificationTypeTile.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../../providers/settings_provider.dart'; - -class NotificationTypeTile extends ConsumerStatefulWidget { - final NotificationReminderType type; - final VoidCallback setNotificationTypeCallback; - - const NotificationTypeTile( - {Key? key, required this.type, required this.setNotificationTypeCallback}) - : super(key: key); - - @override - _NotificationTypeTileState createState() => _NotificationTypeTileState(); -} - -class _NotificationTypeTileState extends ConsumerState { - late SharedPreferences prefs; - bool isPrefInizialized = false; - - @override - void initState() { - super.initState(); - initPrefs(); - } - - Future initPrefs() async { - prefs = await SharedPreferences.getInstance(); - setState(() { - isPrefInizialized = true; - }); - } - - @override - Widget build(BuildContext context) { - if (!isPrefInizialized) return Container(); - - NotificationReminderType? notificationReminderType = - NotificationReminderType?.values?.firstWhere((e) => - e.toString().split('.').last == - prefs.getString('transaction-reminder-cadence')); - - final typeName = - "${widget.type.name[0].toUpperCase()}${widget.type.name.substring(1).toLowerCase()}"; - - return GestureDetector( - onTap: () { - widget.setNotificationTypeCallback.call(); - }, - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), - width: MediaQuery.of(context).size.width, - height: 40, - decoration: BoxDecoration( - border: Border.all( - color: notificationReminderType == widget.type - ? Colors.blue - : Colors.grey, - ), - borderRadius: BorderRadius.circular(4.0), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Text( - typeName, - style: TextStyle( - color: notificationReminderType == widget.type - ? Colors.blue - : Colors.black, - ), - ), - const Spacer(), - notificationReminderType == widget.type - ? const Icon( - Icons.check, - color: Colors.blue, - ) - : Container() - ], - ), - ), - ), - ); - } -} diff --git a/lib/pages/notifications/widgets/notification_type_tile.dart b/lib/pages/notifications/widgets/notification_type_tile.dart new file mode 100644 index 00000000..1fb4e5e3 --- /dev/null +++ b/lib/pages/notifications/widgets/notification_type_tile.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../providers/settings_provider.dart'; + +class NotificationTypeTile extends ConsumerWidget { + final NotificationReminderType type; + final VoidCallback setNotificationTypeCallback; + + const NotificationTypeTile({ + super.key, + required this.type, + required this.setNotificationTypeCallback, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final transactionReminderCadence = ref.watch(transactionReminderCadenceProvider); + + return GestureDetector( + onTap: setNotificationTypeCallback.call, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 6), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + border: Border.all( + color: transactionReminderCadence == type + ? Theme.of(context).colorScheme.secondary + : Colors.grey, + ), + borderRadius: BorderRadius.circular(4.0), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + children: [ + Text( + "${type.name[0].toUpperCase()}${type.name.substring(1)}", + style: TextStyle( + color: transactionReminderCadence == type + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.primary, + ), + ), + const Spacer(), + if (transactionReminderCadence == type) + Icon( + Icons.check, + color: Theme.of(context).colorScheme.secondary, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/onboarding_page/onboarding_page.dart b/lib/pages/onboarding_page/onboarding_page.dart index 9e9be360..4f6d0c3c 100644 --- a/lib/pages/onboarding_page/onboarding_page.dart +++ b/lib/pages/onboarding_page/onboarding_page.dart @@ -3,14 +3,13 @@ import '/pages/onboarding_page/widgets/budget_setup.dart'; import '/constants/style.dart'; class Onboarding extends StatefulWidget { - const Onboarding({Key? key}) : super(key: key); + const Onboarding({super.key}); @override State createState() => _OnboardingState(); } class _OnboardingState extends State { - @override Widget build(BuildContext context) { return Scaffold( @@ -24,21 +23,18 @@ class _OnboardingState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( - height: MediaQuery.sizeOf(context).height/9, + height: MediaQuery.sizeOf(context).height / 9, ), Text( 'Set up the app', - style: Theme.of(context) - .textTheme - .headlineLarge - ?.copyWith(color: blue1), + style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: blue1), ), const SizedBox( height: 80, ), Image.asset( 'assets/openVault.png', - height: MediaQuery.sizeOf(context).height/3.7, + height: MediaQuery.sizeOf(context).height / 3.7, ), const SizedBox( height: 74, @@ -46,12 +42,9 @@ class _OnboardingState extends State { Text( 'In a few steps you\'ll be ready to start keeping\ntrack of your personal finances (almost) like\nMr. Rip', textAlign: TextAlign.center, - style: - Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), ), - ], - ), Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), @@ -75,10 +68,7 @@ class _OnboardingState extends State { ), child: Text( 'START THE SET UP', - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith(color: white), + style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: white), ), ), ), diff --git a/lib/pages/onboarding_page/widgets/account_setup.dart b/lib/pages/onboarding_page/widgets/account_setup.dart index 4c56b8fc..db9ea840 100644 --- a/lib/pages/onboarding_page/widgets/account_setup.dart +++ b/lib/pages/onboarding_page/widgets/account_setup.dart @@ -9,7 +9,7 @@ import '/constants/style.dart'; final showAccountIconsProvider = StateProvider.autoDispose((ref) => false); class AccountSetup extends ConsumerStatefulWidget { - const AccountSetup({Key? key}) : super(key: key); + const AccountSetup({super.key}); @override ConsumerState createState() => _AccountSetupState(); @@ -19,7 +19,6 @@ class _AccountSetupState extends ConsumerState { TextEditingController accountNameController = TextEditingController(); TextEditingController amountController = TextEditingController(); - bool _validName = false; bool _validAmount = false; @@ -37,7 +36,6 @@ class _AccountSetupState extends ConsumerState { }); } - @override void dispose() { accountNameController.dispose(); @@ -66,22 +64,18 @@ class _AccountSetupState extends ConsumerState { Text( "Set the liquidity in your main\naccount", textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .headlineLarge - ?.copyWith(color: blue1), + style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: blue1), ), const SizedBox(height: 20), Text( "It will be used as a baseline to which you can add\nincome, expenses and calculate your wealth.\n\nYou’ll be able to add more accounts within the app.", textAlign: TextAlign.center, - style: - Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), ), const SizedBox(height: 10), Container( margin: const EdgeInsets.only(left: 25.0, right: 25.0), - padding: const EdgeInsets.only(left: 20.0, right: 20.0,top: 15, bottom: 15), + padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 15, bottom: 15), decoration: BoxDecoration( color: white, shape: BoxShape.rectangle, @@ -101,7 +95,10 @@ class _AccountSetupState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ Text("ACCOUNT NAME ", - style: Theme.of(context).textTheme.labelSmall?.copyWith(color: grey1)), + style: Theme.of(context) + .textTheme + .labelSmall + ?.copyWith(color: grey1)), const Icon(Icons.edit, size: 10) ], ), @@ -115,13 +112,16 @@ class _AccountSetupState extends ConsumerState { ], decoration: InputDecoration( hintText: "Main Account", - errorStyle: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 10, color: red), + errorStyle: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(fontSize: 10, color: red), hintStyle: Theme.of(context).textTheme.bodySmall, border: const UnderlineInputBorder( borderSide: BorderSide(color: grey2, width: 0.2), ), ), - onTapOutside: (_){ + onTapOutside: (_) { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); @@ -143,7 +143,8 @@ class _AccountSetupState extends ConsumerState { TextField( textAlign: TextAlign.center, controller: amountController, - keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), + keyboardType: + const TextInputType.numberWithOptions(decimal: true, signed: true), onChanged: validateAmount, inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}')), @@ -151,13 +152,16 @@ class _AccountSetupState extends ConsumerState { decoration: InputDecoration( hintText: "e.g 1300 €", suffixText: "€", - errorStyle: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 10, color: red), + errorStyle: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(fontSize: 10, color: red), hintStyle: Theme.of(context).textTheme.bodySmall, border: const UnderlineInputBorder( - borderSide:BorderSide(color: grey2, width: 0.2), + borderSide: BorderSide(color: grey2, width: 0.2), ), ), - onTapOutside: (_){ + onTapOutside: (_) { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); @@ -191,7 +195,7 @@ class _AccountSetupState extends ConsumerState { child: Icon( accountIconList[accountIcon], size: 36, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -207,7 +211,8 @@ class _AccountSetupState extends ConsumerState { itemBuilder: (context, index) { Color color = accountColorList[index]; return GestureDetector( - onTap: () => ref.read(accountColorProvider.notifier).state = index, + onTap: () => + ref.read(accountColorProvider.notifier).state = index, child: Container( height: accountColorList[accountColor] == color ? 38 : 32, width: accountColorList[accountColor] == color ? 38 : 32, @@ -216,9 +221,9 @@ class _AccountSetupState extends ConsumerState { color: color, border: accountColorList[accountColor] == color ? Border.all( - color: Theme.of(context).colorScheme.primary, - width: 3, - ) + color: Theme.of(context).colorScheme.primary, + width: 3, + ) : null, ), ), @@ -239,8 +244,7 @@ class _AccountSetupState extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 16), separatorBuilder: (context, index) => const SizedBox(width: 16), itemBuilder: (context, index) { - IconData accountIconData = - accountIconList.values.elementAt(index); + IconData accountIconData = accountIconList.values.elementAt(index); String accountIconName = accountIconList.keys.elementAt(index); return GestureDetector( onTap: () => ref.read(accountIconProvider.notifier).state = @@ -250,10 +254,11 @@ class _AccountSetupState extends ConsumerState { height: 38, margin: const EdgeInsets.all(2), decoration: BoxDecoration( - color: accountIconList[accountIcon] == accountIconData - ? Theme.of(context).colorScheme.secondary - : Theme.of(context).colorScheme.surface, - shape: BoxShape.circle,), + color: accountIconList[accountIcon] == accountIconData + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.surface, + shape: BoxShape.circle, + ), child: Icon( accountIconData, color: accountIconList[accountIcon] == accountIconData @@ -278,10 +283,7 @@ class _AccountSetupState extends ConsumerState { Column( children: [ Text('Or you can skip this step and start from 0', - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: blue1)), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1)), const SizedBox(height: 10), ElevatedButton( onPressed: () { @@ -303,12 +305,11 @@ class _AccountSetupState extends ConsumerState { .textTheme .bodyMedium ?.copyWith(color: blue1)), - const Icon(Icons.arrow_forward, - size: 15, color: blue1), + const Icon(Icons.arrow_forward, size: 15, color: blue1), ], ), SizedBox( - width: MediaQuery.sizeOf(context).width/3, + width: MediaQuery.sizeOf(context).width / 3, child: const Divider( color: blue1, thickness: 1, @@ -318,14 +319,15 @@ class _AccountSetupState extends ConsumerState { ), ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0,vertical: 15), + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 15), child: SizedBox( width: MediaQuery.sizeOf(context).width, height: 48, child: ElevatedButton( onPressed: () { - if(_validName && _validAmount){ - ref.watch(accountsProvider.notifier).addAccount(accountNameController.text, num.tryParse(amountController.text)); + if (_validName && _validAmount) { + ref.watch(accountsProvider.notifier).addAccount( + accountNameController.text, num.tryParse(amountController.text)); ref.watch(currencyStateNotifier.notifier).insertAll(); Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false); } diff --git a/lib/pages/onboarding_page/widgets/add_budget.dart b/lib/pages/onboarding_page/widgets/add_budget.dart index baa05760..e236493c 100644 --- a/lib/pages/onboarding_page/widgets/add_budget.dart +++ b/lib/pages/onboarding_page/widgets/add_budget.dart @@ -9,7 +9,7 @@ import '../../../providers/budgets_provider.dart'; class AddBudget extends ConsumerStatefulWidget { final CategoryTransaction category; - const AddBudget(this.category, {Key? key}) : super(key: key); + const AddBudget(this.category, {super.key}); @override ConsumerState createState() => _AddBudgetState(); @@ -24,17 +24,19 @@ class _AddBudgetState extends ConsumerState with Functions { super.didChangeDependencies(); // Initialize the text controller with the current budget amount budgetsList = ref.watch(budgetsProvider).value; - const Budget defaultBudget = Budget(idCategory: 99999, name: '', amountLimit: 9999, active: false); + const Budget defaultBudget = + Budget(idCategory: 99999, name: '', amountLimit: 9999, active: false); - final Budget? budget = budgetsList?.firstWhere((element) => element.idCategory == widget.category.id, orElse: () => defaultBudget); + final Budget? budget = budgetsList?.firstWhere( + (element) => element.idCategory == widget.category.id, + orElse: () => defaultBudget); if (budget != null) { amountController.text = budget.amountLimit.toString(); } - if(budget == defaultBudget){ + if (budget == defaultBudget) { amountController.text = ""; } - } @override @@ -62,14 +64,16 @@ class _AddBudgetState extends ConsumerState with Functions { ), ElevatedButton( onPressed: () async { - await ref.watch(budgetsProvider.notifier).addBudget( - Budget( + await ref + .watch(budgetsProvider.notifier) + .addBudget(Budget( name: widget.category.name, createdAt: DateTime.now(), idCategory: widget.category.id!, amountLimit: num.tryParse(amountController.text) ?? 0, active: true, - )).whenComplete(() => Navigator.pop(context)); + )) + .whenComplete(() => Navigator.pop(context)); }, style: ElevatedButton.styleFrom( backgroundColor: blue5, diff --git a/lib/pages/onboarding_page/widgets/budget_setup.dart b/lib/pages/onboarding_page/widgets/budget_setup.dart index e6aa0ded..fc91fad2 100644 --- a/lib/pages/onboarding_page/widgets/budget_setup.dart +++ b/lib/pages/onboarding_page/widgets/budget_setup.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -15,7 +13,7 @@ import 'add_category_button.dart'; import 'category_button.dart'; class BudgetSetup extends ConsumerStatefulWidget { - const BudgetSetup({Key? key}) : super(key: key); + const BudgetSetup({super.key}); @override ConsumerState createState() => _BudgetSetupState(); @@ -30,8 +28,7 @@ class _BudgetSetupState extends ConsumerState { @override Widget build(BuildContext context) { budgetsList = ref.watch(budgetsProvider).value; - totalBudget = budgetsList?.fold( - 0, (total, budget) => total + budget.amountLimit) ?? 0; + totalBudget = budgetsList?.fold(0, (total, budget) => total + budget.amountLimit) ?? 0; final categoriesGrid = ref.watch(categoriesProvider); return Scaffold( backgroundColor: blue7, @@ -40,25 +37,18 @@ class _BudgetSetupState extends ConsumerState { padding: const EdgeInsets.only(left: 16.0, right: 16), child: Column( children: [ - Text("STEP 1 OF 2", - style: Theme.of(context).textTheme.labelSmall), + Text("STEP 1 OF 2", style: Theme.of(context).textTheme.labelSmall), const SizedBox(height: 20), Text( "Set up your monthly\nbudgets", textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .headlineLarge - ?.copyWith(color: blue1), + style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: blue1), ), const SizedBox(height: 30), Text( "Choose which categories you want to set a budget for", textAlign: TextAlign.center, - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: blue1), + style: Theme.of(context).textTheme.bodySmall?.copyWith(color: blue1), ), const SizedBox(height: 16), Expanded( @@ -80,23 +70,21 @@ class _BudgetSetupState extends ConsumerState { itemBuilder: (context, i) { if (i < categories.length) { return GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (context) => - AddBudget(categories.elementAt(i)), - ); - }, - child: CategoryButton( - categoryColor: categoryColorList[categories.elementAt(i).color], - categoryName: categories.elementAt(i).name, - budget: budgetsList?.firstWhereOrNull((budget) => budget.idCategory == categories.elementAt(i).id), - ) - ); + onTap: () { + showDialog( + context: context, + builder: (context) => AddBudget(categories.elementAt(i)), + ); + }, + child: CategoryButton( + categoryColor: categoryColorList[categories.elementAt(i).color], + categoryName: categories.elementAt(i).name, + budget: budgetsList?.firstWhereOrNull( + (budget) => budget.idCategory == categories.elementAt(i).id), + )); } else { return GestureDetector( - onTap: () => Navigator.of(context) - .pushNamed('/add-category'), + onTap: () => Navigator.of(context).pushNamed('/add-category'), child: const AddCategoryButton(), ); } @@ -124,18 +112,12 @@ class _BudgetSetupState extends ConsumerState { children: [ TextSpan( text: totalBudget.toString(), - style: - Theme.of(context).textTheme.displayMedium, + style: Theme.of(context).textTheme.displayMedium, ), TextSpan( text: "€", - style: Theme.of(context) - .textTheme - .bodyMedium - ?.apply( - fontFeatures: [ - const FontFeature.subscripts() - ], + style: Theme.of(context).textTheme.bodyMedium?.apply( + fontFeatures: [const FontFeature.subscripts()], ), ), ], @@ -149,9 +131,7 @@ class _BudgetSetupState extends ConsumerState { onPressed: () { Navigator.push( context, - MaterialPageRoute( - builder: (context) => - const AccountSetup()), + MaterialPageRoute(builder: (context) => const AccountSetup()), ); }, style: ElevatedButton.styleFrom( @@ -174,8 +154,7 @@ class _BudgetSetupState extends ConsumerState { onPressed: () { Navigator.push( context, - MaterialPageRoute( - builder: (context) => const AccountSetup()), + MaterialPageRoute(builder: (context) => const AccountSetup()), ); }, style: ElevatedButton.styleFrom( @@ -193,8 +172,7 @@ class _BudgetSetupState extends ConsumerState { .textTheme .bodyMedium ?.copyWith(color: blue1)), - const Icon(Icons.arrow_forward, - size: 15, color: blue1), + const Icon(Icons.arrow_forward, size: 15, color: blue1), ], ), SizedBox( @@ -215,5 +193,3 @@ class _BudgetSetupState extends ConsumerState { ); } } - - diff --git a/lib/pages/planning_page/manage_budget_page.dart b/lib/pages/planning_page/manage_budget_page.dart index a10da734..0a264b30 100644 --- a/lib/pages/planning_page/manage_budget_page.dart +++ b/lib/pages/planning_page/manage_budget_page.dart @@ -93,16 +93,17 @@ class _ManageBudgetPageState extends ConsumerState { }, child: BudgetCategorySelector( categories: categories, - categoriesAlreadyUsed: categories.where((element) => budgets.map((e) => e.name).contains(element.name)).map((e) => e.name).toList(), + categoriesAlreadyUsed: categories + .where((element) => budgets.map((e) => e.name).contains(element.name)) + .map((e) => e.name) + .toList(), budget: budgets[index], initSelectedCategory: categories - .where((element) => - element.id == budgets[index].idCategory) + .where((element) => element.id == budgets[index].idCategory) .isEmpty ? categories[0] : categories - .where((element) => - element.id == budgets[index].idCategory) + .where((element) => element.id == budgets[index].idCategory) .first, onBudgetChanged: (updatedBudget) { updateBudget(updatedBudget, index); @@ -164,7 +165,10 @@ class _ManageBudgetPageState extends ConsumerState { ), child: Text( "SAVE BUDGET", - style: Theme.of(context).textTheme.bodyLarge!.copyWith(color: Theme.of(context).colorScheme.background), + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith(color: Theme.of(context).colorScheme.onPrimary), ), ), ), diff --git a/lib/pages/planning_page/planning_page.dart b/lib/pages/planning_page/planning_page.dart index e8f6611a..9d83c419 100644 --- a/lib/pages/planning_page/planning_page.dart +++ b/lib/pages/planning_page/planning_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'manage_budget_page.dart'; import 'widget/budget_card.dart'; -import 'widget/recurring_payments_list.dart'; class PlanningPage extends StatefulWidget { const PlanningPage({super.key}); @@ -18,7 +17,6 @@ class _PlanningPageState extends State { final key = GlobalKey<_PlanningPageState>(); _key.currentState?.dispose(); _key.currentState?.reassemble(); - _key.currentState?._key = key; }); } @@ -27,8 +25,9 @@ class _PlanningPageState extends State { Widget build(BuildContext context) { return Container( key: _key, - padding: const EdgeInsetsDirectional.symmetric(horizontal: 10), + color: Colors.white, child: ListView( + padding: const EdgeInsetsDirectional.all(10), children: [ Row( children: [ @@ -69,7 +68,6 @@ class _PlanningPageState extends State { Text("Recurring payments", style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: 10), - const RecurringPaymentSection() ])); } } diff --git a/lib/pages/planning_page/widget/budget_card.dart b/lib/pages/planning_page/widget/budget_card.dart index 8b777212..48188485 100644 --- a/lib/pages/planning_page/widget/budget_card.dart +++ b/lib/pages/planning_page/widget/budget_card.dart @@ -5,11 +5,9 @@ import '../../../constants/constants.dart'; import '../../../model/budget.dart'; import '../../../model/transaction.dart'; import '../../../providers/budgets_provider.dart'; - import '../../../providers/currency_provider.dart'; import '../../../providers/transactions_provider.dart'; import '../manage_budget_page.dart'; - import 'budget_pie_chart.dart'; class BudgetCard extends ConsumerStatefulWidget { @@ -78,7 +76,7 @@ class _BudgetCardState extends ConsumerState { const Spacer(), spent >= (budget.amountLimit * 0.9) ? const Icon(Icons.error_outline, color: Colors.red) : Container(), Text( - "${spent}${currencyState.selectedCurrency.symbol}/${budget.amountLimit}${currencyState.selectedCurrency.symbol}", + "$spent${currencyState.selectedCurrency.symbol}/${budget.amountLimit}${currencyState.selectedCurrency.symbol}", style: const TextStyle( fontWeight: FontWeight.normal), ), diff --git a/lib/pages/planning_page/widget/budget_category_selector.dart b/lib/pages/planning_page/widget/budget_category_selector.dart index b9cbb613..c7e5f31e 100644 --- a/lib/pages/planning_page/widget/budget_category_selector.dart +++ b/lib/pages/planning_page/widget/budget_category_selector.dart @@ -13,7 +13,7 @@ class BudgetCategorySelector extends ConsumerStatefulWidget { final CategoryTransaction initSelectedCategory; final Function(Budget) onBudgetChanged; - BudgetCategorySelector( + const BudgetCategorySelector( {super.key, required this.categories, required this.budget, @@ -22,8 +22,7 @@ class BudgetCategorySelector extends ConsumerStatefulWidget { required this.categoriesAlreadyUsed}); @override - ConsumerState createState() => - _BudgetCategorySelector(); + ConsumerState createState() => _BudgetCategorySelector(); } class _BudgetCategorySelector extends ConsumerState { @@ -35,8 +34,7 @@ class _BudgetCategorySelector extends ConsumerState { idCategory: selectedCategory.id!, name: selectedCategory.name, active: true, - amountLimit: _controller.text.isNotEmpty ? double.parse(_controller.text) : 0 - ); + amountLimit: _controller.text.isNotEmpty ? double.parse(_controller.text) : 0); widget.onBudgetChanged(updatedBudget); } @@ -62,20 +60,25 @@ class _BudgetCategorySelector extends ConsumerState { child: Container( padding: const EdgeInsets.all(5), decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8)), + color: Colors.white, borderRadius: BorderRadius.circular(8)), child: DropdownButton( value: selectedCategory, underline: const SizedBox(), isExpanded: true, items: widget.categories - .where((e) => e.name == selectedCategory.name || !widget.categoriesAlreadyUsed.contains(e.name)) + .where((e) => + e.name == selectedCategory.name || + !widget.categoriesAlreadyUsed.contains(e.name)) .map((CategoryTransaction category) { IconData? icon = iconList[category.symbol]; return DropdownMenuItem( value: category, child: Row( - children: [Icon(icon), const SizedBox(width: 15), Text(category.name)], + children: [ + Icon(icon), + const SizedBox(width: 15), + Text(category.name) + ], )); }).toList(), onChanged: (CategoryTransaction? newValue) { diff --git a/lib/pages/planning_page/widget/budget_pie_chart.dart b/lib/pages/planning_page/widget/budget_pie_chart.dart index c3459c7a..71668c14 100644 --- a/lib/pages/planning_page/widget/budget_pie_chart.dart +++ b/lib/pages/planning_page/widget/budget_pie_chart.dart @@ -7,7 +7,7 @@ import '../../../model/budget.dart'; import '../../../providers/currency_provider.dart'; class BudgetPieChart extends ConsumerStatefulWidget { - BudgetPieChart({super.key, required this.budgets}); + const BudgetPieChart({super.key, required this.budgets}); final List budgets; @@ -38,7 +38,8 @@ class BudgetPieChartState extends ConsumerState { ), Column( children: [ - Text("${totalBudget.round()}${currencyState.selectedCurrency.symbol}", style: const TextStyle(fontSize: 25)), + Text("${totalBudget.round()}${currencyState.selectedCurrency.symbol}", + style: const TextStyle(fontSize: 25)), const SizedBox(height: 5), const Text("PLANNED", style: TextStyle(fontWeight: FontWeight.normal)) ], diff --git a/lib/pages/planning_page/widget/edit_recurring_transaction.dart b/lib/pages/planning_page/widget/edit_recurring_transaction.dart index 79fd13a6..a325c03d 100644 --- a/lib/pages/planning_page/widget/edit_recurring_transaction.dart +++ b/lib/pages/planning_page/widget/edit_recurring_transaction.dart @@ -1,6 +1,3 @@ -import 'dart:io' show Platform; - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -186,7 +183,7 @@ class _EditRecurringTransactionState child: Text( "UPDATE TRANSACTION", style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Theme.of(context).colorScheme.background), + color: Theme.of(context).colorScheme.onPrimary), ), ), ), diff --git a/lib/pages/planning_page/widget/older_recurring_payments.dart b/lib/pages/planning_page/widget/older_recurring_payments.dart index d98fa84e..150c7e34 100644 --- a/lib/pages/planning_page/widget/older_recurring_payments.dart +++ b/lib/pages/planning_page/widget/older_recurring_payments.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:sossoldi/model/transaction.dart'; +import '../../../model/transaction.dart'; import 'package:intl/intl.dart'; import '../../../model/recurring_transaction.dart'; diff --git a/lib/pages/planning_page/widget/recurring_payment_card.dart b/lib/pages/planning_page/widget/recurring_payment_card.dart index 2bd932c1..e71ad5a8 100644 --- a/lib/pages/planning_page/widget/recurring_payment_card.dart +++ b/lib/pages/planning_page/widget/recurring_payment_card.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:sossoldi/constants/constants.dart'; -import 'package:sossoldi/model/recurring_transaction.dart'; -import 'package:sossoldi/pages/planning_page/widget/older_recurring_payments.dart'; -import 'package:sossoldi/providers/accounts_provider.dart'; -import 'package:sossoldi/providers/currency_provider.dart'; +import '../../../constants/constants.dart'; +import '../../../model/recurring_transaction.dart'; +import 'older_recurring_payments.dart'; +import '../../../providers/accounts_provider.dart'; +import '../../../providers/currency_provider.dart'; import '../../../constants/functions.dart'; import '../../../constants/style.dart'; diff --git a/lib/pages/planning_page/widget/recurring_payments_list.dart b/lib/pages/planning_page/widget/recurring_payments_list.dart index 49eafa44..999f98fb 100644 --- a/lib/pages/planning_page/widget/recurring_payments_list.dart +++ b/lib/pages/planning_page/widget/recurring_payments_list.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:sossoldi/pages/planning_page/widget/recurring_payment_card.dart'; -import 'package:sossoldi/providers/transactions_provider.dart'; +import 'recurring_payment_card.dart'; +import '../../../providers/transactions_provider.dart'; import '../../../model/recurring_transaction.dart'; import '../../../model/transaction.dart'; diff --git a/lib/pages/search_page/search_page.dart b/lib/pages/search_page/search_page.dart index b18e55c4..1001fcef 100644 --- a/lib/pages/search_page/search_page.dart +++ b/lib/pages/search_page/search_page.dart @@ -18,10 +18,9 @@ class _SearchPage extends ConsumerState { String? labelFilter; void _updateFutureTransactions() { - Map filterAccountList = Map.fromIterable( - ref.read(filterAccountProvider).entries, - key: (element) => element.key, - value: (element) => element.value); + Map filterAccountList = { + for (var element in ref.read(filterAccountProvider).entries) element.key: element.value + }; setState(() { futureTransactions = TransactionMethods().selectAll( limit: 100, @@ -38,9 +37,7 @@ class _SearchPage extends ConsumerState { @override void initState() { super.initState(); - TransactionMethods() - .getAllLabels() - .then((List value) => suggetions.addAll(value)); + TransactionMethods().getAllLabels().then((List value) => suggetions.addAll(value)); } @override @@ -72,8 +69,7 @@ class _SearchPage extends ConsumerState { return const Iterable.empty(); } return suggetions.where((String option) { - return option - .contains(textEditingValue.text.toLowerCase()); + return option.contains(textEditingValue.text.toLowerCase()); }); }, onSelected: (option) { @@ -81,9 +77,7 @@ class _SearchPage extends ConsumerState { _updateFutureTransactions(); }, )), - Container( - alignment: Alignment.centerLeft, - child:const Text("SEARCH FOR:")), + Container(alignment: Alignment.centerLeft, child: const Text("SEARCH FOR:")), Row(children: [ Expanded( child: SingleChildScrollView( @@ -93,7 +87,10 @@ class _SearchPage extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 10), child: FilterChip( showCheckmark: false, - label: Text("Income", style: TextStyle(color: filterType["IN"]! ? Colors.white : Colors.blue.shade700)), + label: Text("Income", + style: TextStyle( + color: + filterType["IN"]! ? Colors.white : Colors.blue.shade700)), selected: filterType["IN"] ?? false, backgroundColor: Colors.white, selectedColor: Colors.blue.shade700, @@ -107,9 +104,7 @@ class _SearchPage extends ConsumerState { onSelected: (_) { ref.read(typeFilterProvider.notifier).state = { ...filterType, - "IN": filterType["IN"] != null - ? !filterType["IN"]! - : false + "IN": filterType["IN"] != null ? !filterType["IN"]! : false }; _updateFutureTransactions(); }, @@ -119,7 +114,11 @@ class _SearchPage extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 10), child: FilterChip( showCheckmark: false, - label: Text("Outcome", style: TextStyle(color: filterType["OUT"]! ? Colors.white : Colors.blue.shade700)), + label: Text("Outcome", + style: TextStyle( + color: filterType["OUT"]! + ? Colors.white + : Colors.blue.shade700)), selected: filterType["OUT"] ?? false, backgroundColor: Colors.white, selectedColor: Colors.blue.shade700, @@ -133,9 +132,7 @@ class _SearchPage extends ConsumerState { onSelected: (_) { ref.read(typeFilterProvider.notifier).state = { ...filterType, - "OUT": filterType["OUT"] != null - ? !filterType["OUT"]! - : false + "OUT": filterType["OUT"] != null ? !filterType["OUT"]! : false }; _updateFutureTransactions(); }, @@ -145,7 +142,10 @@ class _SearchPage extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 10), child: FilterChip( showCheckmark: false, - label: Text("Transfer", style: TextStyle(color: filterType["TR"]! ? Colors.white : Colors.blue.shade700)), + label: Text("Transfer", + style: TextStyle( + color: + filterType["TR"]! ? Colors.white : Colors.blue.shade700)), selected: filterType["TR"] ?? false, backgroundColor: Colors.white, selectedColor: Colors.blue.shade700, @@ -159,9 +159,7 @@ class _SearchPage extends ConsumerState { onSelected: (_) { ref.read(typeFilterProvider.notifier).state = { ...filterType, - "TR": filterType["TR"] != null - ? !filterType["TR"]! - : false + "TR": filterType["TR"] != null ? !filterType["TR"]! : false }; _updateFutureTransactions(); }, @@ -170,10 +168,7 @@ class _SearchPage extends ConsumerState { ])), ) ]), - Container( - alignment: Alignment.centerLeft, - child: - const Text("SEARCH IN:")), + Container(alignment: Alignment.centerLeft, child: const Text("SEARCH IN:")), Row( children: [ Expanded( @@ -184,37 +179,30 @@ class _SearchPage extends ConsumerState { return Row( children: accounts.map((account) { return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10), + padding: const EdgeInsets.symmetric(horizontal: 10), child: FilterChip( - label: Text(account.name, style: TextStyle(color: filterAccountList[account.id]! ? Colors.white : Colors.blue.shade700)), + label: Text(account.name, + style: TextStyle( + color: filterAccountList[account.id]! + ? Colors.white + : Colors.blue.shade700)), showCheckmark: false, - selected: - filterAccountList[account.id] ?? - false, + selected: filterAccountList[account.id] ?? false, backgroundColor: Colors.white, selectedColor: Colors.blue.shade700, shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(50), + borderRadius: BorderRadius.circular(50), side: BorderSide( color: Colors.blue.shade700, width: 2.0, ), ), onSelected: (_) { - ref - .read(filterAccountProvider - .notifier) - .state = { + ref.read(filterAccountProvider.notifier).state = { ...ref.read(filterAccountProvider), account.id!: - ref.read(filterAccountProvider)[ - account.id] != - null - ? !ref.read( - filterAccountProvider)[ - account.id]! + ref.read(filterAccountProvider)[account.id] != null + ? !ref.read(filterAccountProvider)[account.id]! : false }; _updateFutureTransactions(); @@ -236,11 +224,9 @@ class _SearchPage extends ConsumerState { snapshot.connectionState == ConnectionState.done) { return TransactionsList(transactions: snapshot.data!); } else if (snapshot.hasError) { - return Text( - 'Something went wrong: ${snapshot.error}'); + return Text('Something went wrong: ${snapshot.error}'); } else { - if (snapshot.connectionState == - ConnectionState.waiting) { + if (snapshot.connectionState == ConnectionState.waiting) { return Transform.scale( scale: 0.5, child: const CircularProgressIndicator(), diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index f796328a..e37a6aff 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -143,7 +143,7 @@ class _SettingsPageState extends ConsumerState { child: Icon( Icons.settings, size: 28.0, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), ), const SizedBox(width: 12.0), diff --git a/lib/pages/structure.dart b/lib/pages/structure.dart index 1d5469b4..0761002f 100644 --- a/lib/pages/structure.dart +++ b/lib/pages/structure.dart @@ -43,7 +43,7 @@ class _StructureState extends ConsumerState { resizeToAvoidBottomInset: false, appBar: AppBar( backgroundColor: - selectedIndex == 0 ? Theme.of(context).colorScheme.tertiary : Theme.of(context).colorScheme.background, + selectedIndex == 0 ? Theme.of(context).colorScheme.tertiary : null, title: Text( _pagesTitle.elementAt(selectedIndex), ), @@ -59,7 +59,7 @@ class _StructureState extends ConsumerState { ), child: Icon( Icons.search, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -76,7 +76,7 @@ class _StructureState extends ConsumerState { ), child: Icon( Icons.settings, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), ), ), @@ -118,7 +118,7 @@ class _StructureState extends ConsumerState { child: Icon( Icons.add_rounded, size: 55, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, ), onPressed: () { ref.read(transactionsProvider.notifier).reset(); diff --git a/lib/pages/transactions_page/widgets/category_list_tile.dart b/lib/pages/transactions_page/widgets/category_list_tile.dart index 31a0953a..ddf8a7a7 100644 --- a/lib/pages/transactions_page/widgets/category_list_tile.dart +++ b/lib/pages/transactions_page/widgets/category_list_tile.dart @@ -8,7 +8,6 @@ import '../../../model/category_transaction.dart'; import '../../../model/transaction.dart'; import '../../../providers/categories_provider.dart'; import '../../../providers/currency_provider.dart'; -import 'categories_tab.dart'; class CategoryListTile extends ConsumerWidget { const CategoryListTile({ diff --git a/lib/pages/transactions_page/widgets/custom_sliver_delegate.dart b/lib/pages/transactions_page/widgets/custom_sliver_delegate.dart index 81c92d4c..9f7143e1 100644 --- a/lib/pages/transactions_page/widgets/custom_sliver_delegate.dart +++ b/lib/pages/transactions_page/widgets/custom_sliver_delegate.dart @@ -40,7 +40,7 @@ class CustomSliverDelegate extends SliverPersistentHeaderDelegate { return Container( padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.onPrimary, border: const Border( bottom: BorderSide(width: 1.0, color: grey2), ), diff --git a/lib/providers/budgets_provider.dart b/lib/providers/budgets_provider.dart index 999ccdd4..23a02f48 100644 --- a/lib/providers/budgets_provider.dart +++ b/lib/providers/budgets_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../model/budget.dart'; class AsyncBudgetsNotifier extends AsyncNotifier> { diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index bdfbbefd..8baf37ee 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -1,6 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../utils/notifications_service.dart'; + enum NotificationReminderType { none, daily, @@ -8,12 +10,13 @@ enum NotificationReminderType { monthly, } -final transactionReminderSwitchProvider = StateProvider((ref) => false); -final transactionReminderCadenceProvider = StateProvider((ref) => NotificationReminderType.none); -final transactionRecReminderSwitchProvider = StateProvider((ref) => false); -final transactionRecAddedSwitchProvider = StateProvider((ref) => false); +final transactionReminderSwitchProvider = StateProvider.autoDispose((ref) => false); +final transactionReminderCadenceProvider = + StateProvider.autoDispose((ref) => NotificationReminderType.none); +final transactionRecReminderSwitchProvider = StateProvider.autoDispose((ref) => false); +final transactionRecAddedSwitchProvider = StateProvider.autoDispose((ref) => false); -class AsyncSettingsNotifier extends AsyncNotifier { +class AsyncSettingsNotifier extends AutoDisposeAsyncNotifier { @override Future build() async { return _getSettings(); @@ -21,19 +24,53 @@ class AsyncSettingsNotifier extends AsyncNotifier { Future _getSettings() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); - ref.read(transactionReminderSwitchProvider.notifier).state = prefs.getBool('transaction-reminder') ?? false; - ref.read(transactionReminderCadenceProvider.notifier).state = prefs.getString('transaction-reminder-cadence') as NotificationReminderType; - ref.read(transactionRecReminderSwitchProvider.notifier).state = prefs.getBool('transaction-rec-reminder') ?? false; - ref.read(transactionRecAddedSwitchProvider.notifier).state = prefs.getBool('transaction-rec-added') ?? false; + ref.read(transactionReminderSwitchProvider.notifier).state = + prefs.getBool('transaction-reminder') ?? false; + ref.read(transactionReminderCadenceProvider.notifier).state = NotificationReminderType.values + .firstWhere((value) => value.name == prefs.getString('transaction-reminder-cadence')); + ref.read(transactionRecReminderSwitchProvider.notifier).state = + prefs.getBool('transaction-rec-reminder') ?? false; + ref.read(transactionRecAddedSwitchProvider.notifier).state = + prefs.getBool('transaction-rec-added') ?? false; + } + + Future updateNotificationReminder({bool active = true}) async { + state = const AsyncValue.loading(); + state = await AsyncValue.guard(() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + if (active) { + if (ref.read(transactionReminderCadenceProvider) == NotificationReminderType.none) { + ref.read(transactionReminderCadenceProvider.notifier).state = + NotificationReminderType.daily; + } + await prefs.setBool('transaction-reminder', true); + await prefs.setString( + 'transaction-reminder-cadence', + ref.read(transactionReminderCadenceProvider).name, + ); + await NotificationService.scheduleNotification( + title: "Remember to log new expenses!", + body: + "Sossoldi is waiting for your latest transactions. Don't lose sight of your financial movements, and input your most recent expenses.", + recurrence: ref.read(transactionReminderCadenceProvider), + ); + } else { + ref.invalidate(transactionReminderCadenceProvider); + await prefs.remove('transaction-reminder'); + await prefs.remove('transaction-reminder-cadence'); + await NotificationService.cancelNotification(); + } + + return _getSettings(); + }); } - Future updateNotifications() async { + Future updateNotificationRecurring({bool active = true}) async { state = const AsyncValue.loading(); state = await AsyncValue.guard(() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.setBool('transaction-reminder', ref.read(transactionReminderSwitchProvider)); - await prefs.setString('transaction-reminder-cadence', ref.read(transactionReminderCadenceProvider).name); - await prefs.setBool('transaction-rec-reminder', ref.read(transactionRecReminderSwitchProvider)); + await prefs.setBool( + 'transaction-rec-reminder', ref.read(transactionRecReminderSwitchProvider)); await prefs.setBool('transaction-rec-added', ref.read(transactionRecAddedSwitchProvider)); return _getSettings(); @@ -41,6 +78,6 @@ class AsyncSettingsNotifier extends AsyncNotifier { } } -final settingsProvider = AsyncNotifierProvider(() { +final settingsProvider = AutoDisposeAsyncNotifierProvider(() { return AsyncSettingsNotifier(); }); diff --git a/lib/providers/transactions_provider.dart b/lib/providers/transactions_provider.dart index 21ae2670..1e9f4a59 100644 --- a/lib/providers/transactions_provider.dart +++ b/lib/providers/transactions_provider.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../model/bank_account.dart'; diff --git a/lib/utils/app_theme.dart b/lib/utils/app_theme.dart index cf13074b..d01e154c 100644 --- a/lib/utils/app_theme.dart +++ b/lib/utils/app_theme.dart @@ -8,7 +8,7 @@ class AppTheme { scaffoldBackgroundColor: white, useMaterial3: false, appBarTheme: const AppBarTheme( - color: grey3, + color: white, elevation: 0, centerTitle: true, iconTheme: IconThemeData(color: blue5), @@ -205,12 +205,10 @@ ColorScheme customColorScheme = const ColorScheme( secondary: blue5, tertiary: blue7, surface: grey3, - background: white, error: red, onPrimary: white, onSecondary: white, onSurface: blue1, - onBackground: blue1, onError: black, brightness: Brightness.light, ); @@ -221,12 +219,10 @@ ColorScheme darkCustomColorScheme = const ColorScheme( secondary: darkBlue5, tertiary: darkBlue7, surface: darkBlue7, //darkBlue3 - background: darkWhite, error: darkRed, onPrimary: darkWhite, onSecondary: darkWhite, onSurface: darkBlue1, - onBackground: darkBlue1, onError: darkBlack, brightness: Brightness.dark, ); diff --git a/lib/utils/notifications_service.dart b/lib/utils/notifications_service.dart new file mode 100644 index 00000000..5795382b --- /dev/null +++ b/lib/utils/notifications_service.dart @@ -0,0 +1,122 @@ +import 'dart:io'; + +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:timezone/timezone.dart' as tz; + +import '../providers/settings_provider.dart'; + +class NotificationService { + static final FlutterLocalNotificationsPlugin notificationsPlugin = + FlutterLocalNotificationsPlugin(); + + static const AndroidNotificationChannel channel = AndroidNotificationChannel( + 'sossoldi#reminder', // id del canale + 'Reminder', // nome del canale + importance: Importance.high, + ); + + Future initializeNotifications() async { + var initializeSettingsAndroid = const AndroidInitializationSettings('@mipmap/ic_launcher'); + final initializeSettingsIOS = DarwinInitializationSettings( + requestAlertPermission: true, + requestBadgePermission: true, + requestSoundPermission: true, + ); + var initializationSettings = InitializationSettings( + android: initializeSettingsAndroid, + iOS: initializeSettingsIOS, + ); + await notificationsPlugin.initialize(initializationSettings); + await notificationsPlugin + .resolvePlatformSpecificImplementation() + ?.createNotificationChannel(channel); + } + + Future requestNotificationPermissions() async { + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + if (Platform.isIOS) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation() + ?.requestPermissions( + alert: true, + badge: true, + sound: true, + ); + } else if (Platform.isAndroid) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation() + ?.requestNotificationsPermission(); + } + } + + static Future scheduleNotification({ + required String title, + required String body, + int id = 0, + NotificationReminderType recurrence = NotificationReminderType.daily, + }) async { + NotificationDetails notificationDetails = const NotificationDetails( + android: AndroidNotificationDetails( + 'sossoldi#reminder', + 'reminder', + importance: Importance.high, + priority: Priority.high, + ), + iOS: DarwinNotificationDetails(), + ); + + // Get today's date + final DateTime now = DateTime.now(); + DateTime scheduledDate; + DateTimeComponents matchDateTimeComponents = DateTimeComponents.time; + + if (recurrence == NotificationReminderType.daily) { + // Check if current time is past 21:00 + if (now.hour < 21) { + // Schedule for today at 21:00 + scheduledDate = DateTime(now.year, now.month, now.day, 21, 0); + } else { + // Schedule for tomorrow at 21:00 + scheduledDate = DateTime(now.year, now.month, now.day + 1, 21, 0); + } + } else if (recurrence == NotificationReminderType.weekly) { + // Find the nearest Sunday + int daysUntilSunday = (DateTime.sunday - now.weekday) % 7; + if (daysUntilSunday == 0 && now.hour >= 21) { + // If today is Sunday and it's past 21:00, schedule for next Sunday + daysUntilSunday = 7; + } + scheduledDate = DateTime(now.year, now.month, now.day + daysUntilSunday, 21, 0); + matchDateTimeComponents = DateTimeComponents.dayOfWeekAndTime; + } else { + // Find the nearest first of the next month + if (now.day == 1 && now.hour < 21) { + // If today is the first and it's before 21:00, schedule for today + scheduledDate = DateTime(now.year, now.month, now.day, 21, 0); + } else { + // Schedule for the first of the next month + scheduledDate = DateTime(now.year, now.month + 1, 1, 21, 0); + } + matchDateTimeComponents = DateTimeComponents.dayOfMonthAndTime; + } + + // ? Uncomment the following line to test the notification after 10 seconds + // scheduledDate = DateTime.now().add(const Duration(seconds: 10)); + + await notificationsPlugin.zonedSchedule( + id, + title, + body, + tz.TZDateTime.from(scheduledDate, tz.local), + notificationDetails, + androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, + uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, + matchDateTimeComponents: matchDateTimeComponents, + ); + } + + static Future cancelNotification({int id = 0}) async { + await notificationsPlugin.cancel(id); + } +} diff --git a/lib/utils/worker_manager.dart b/lib/utils/worker_manager.dart index e5caeda0..b27a236f 100644 --- a/lib/utils/worker_manager.dart +++ b/lib/utils/worker_manager.dart @@ -1,7 +1,6 @@ import "package:flutter_local_notifications/flutter_local_notifications.dart"; import "package:workmanager/workmanager.dart"; -import "../pages/notifications/notifications_service.dart"; import "../providers/settings_provider.dart"; //tasks @@ -10,36 +9,43 @@ const taskShowNotification = "showReminder"; @pragma('vm:entry-point') // Mandatory if the App is obfuscated or using Flutter 3.1+ void callbackDispatcher() async { Workmanager().executeTask((task, inputData) async { + final FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin(); switch (task) { case taskShowNotification: await notificationsPlugin.show( - 0, - "Remember to log new expenses!", - "Sossoldi is waiting for your latest transactions. Don't lose sight of your financial movements, and input your most recent expenses.", - const NotificationDetails( - android: AndroidNotificationDetails( - 'sossoldi#reminder', 'reminder', - importance: Importance.max, priority: Priority.max), - iOS: DarwinNotificationDetails( - presentAlert: true, - presentBadge: true, - presentSound: true, - ), - )); + 0, + "Remember to log new expenses!", + "Sossoldi is waiting for your latest transactions. Don't lose sight of your financial movements, and input your most recent expenses.", + const NotificationDetails( + android: AndroidNotificationDetails('sossoldi#reminder', 'reminder', + importance: Importance.max, priority: Priority.max), + iOS: DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ), + ), + ); } return Future.value(true); }); } void toggleTransactionReminder(bool toActive) async { - if(!toActive){ + if (!toActive) { await Workmanager().cancelByUniqueName("sossoldi#reminder"); } } void scheduleTransactionReminder(NotificationReminderType type) async { await Workmanager().cancelByUniqueName("sossoldi#reminder"); - await Workmanager().registerPeriodicTask("sossoldi#reminder", taskShowNotification, frequency: Duration(days: type == NotificationReminderType.daily ? 1 : type == NotificationReminderType.weekly ? 7 : 30)); + await Workmanager().registerPeriodicTask("sossoldi#reminder", taskShowNotification, + frequency: Duration( + days: type == NotificationReminderType.daily + ? 1 + : type == NotificationReminderType.weekly + ? 7 + : 30)); } void scheduleAlertRecursiveTransaction() { diff --git a/pubspec.lock b/pubspec.lock index 944b5045..c2a83805 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "72.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" + version: "67.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.4.1" ansicolor: dependency: transitive description: @@ -42,10 +37,10 @@ packages: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" async: dependency: transitive description: @@ -62,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" characters: dependency: transitive description: @@ -78,14 +81,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - circular_menu: - dependency: "direct main" - description: - name: circular_menu - sha256: "253e5e7aaf107e84251b0c51fb66ae17f6caaebf973eb30049f02b999646373a" - url: "https://pub.dev" - source: hosted - version: "2.0.1" cli_util: dependency: transitive description: @@ -103,7 +98,7 @@ packages: source: hosted version: "1.1.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a @@ -122,10 +117,10 @@ packages: dependency: transitive description: name: coverage - sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5 + sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" url: "https://pub.dev" source: hosted - version: "1.9.2" + version: "1.8.0" crypto: dependency: transitive description: @@ -158,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.10" + dependency_validator: + dependency: "direct dev" + description: + name: dependency_validator + sha256: "81b5dc4cc34a1c05d2fa24aa8d658cb8f048ca23e63d5aaec420200190f1c4b0" + url: "https://pub.dev" + source: hosted + version: "4.1.1" equatable: dependency: transitive description: @@ -178,10 +181,10 @@ packages: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.2" file: dependency: transitive description: @@ -194,10 +197,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: "6b9eb2b3017241d05c482c01f668dd05cc909ec9a0114fdd49acd958ff2432fa" + sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef" url: "https://pub.dev" source: hosted - version: "0.64.0" + version: "0.69.0" flutter: dependency: "direct main" description: flutter @@ -207,66 +210,58 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" flutter_local_notifications: dependency: "direct main" description: name: flutter_local_notifications - sha256: "49eeef364fddb71515bc78d5a8c51435a68bccd6e4d68e25a942c5e47761ae71" + sha256: "725145682706fb0e5a30f93e5cb64f3df7ed7743de749bd555b22bf75ee718c0" url: "https://pub.dev" source: hosted - version: "17.2.3" + version: "18.0.0" flutter_local_notifications_linux: dependency: transitive description: name: flutter_local_notifications_linux - sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af + sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "5.0.0" flutter_local_notifications_platform_interface: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" + sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52" url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "8.0.0" flutter_native_splash: dependency: "direct main" description: name: flutter_native_splash - sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840 + sha256: ee5c9bd2b74ea8676442fd4ab876b5d41681df49276488854d6c81a5377c0ef1 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" flutter_riverpod: dependency: "direct main" description: name: flutter_riverpod - sha256: "711d916456563f715bde1e139d7cfdca009f8264befab3ac9f8ded8b6ec26405" + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" url: "https://pub.dev" source: hosted - version: "2.5.3" - flutter_staggered_grid_view: - dependency: "direct main" - description: - name: flutter_staggered_grid_view - sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" - url: "https://pub.dev" - source: hosted - version: "0.7.0" + version: "2.6.1" flutter_test: dependency: "direct dev" description: flutter @@ -321,18 +316,18 @@ packages: dependency: transitive description: name: image - sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.3.0" intl: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -385,10 +380,10 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.0.0" logging: dependency: transitive description: @@ -397,14 +392,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" matcher: dependency: transitive description: @@ -433,10 +420,10 @@ packages: dependency: transitive description: name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "1.0.5" node_preamble: dependency: transitive description: @@ -454,7 +441,7 @@ packages: source: hosted version: "2.1.0" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" @@ -497,18 +484,18 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6" + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" url: "https://pub.dev" source: hosted - version: "11.2.0" + version: "11.3.1" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: "76e4ab092c1b240d31177bb64d2b0bea43f43d0e23541ec866151b9f7b2490fa" + sha256: b29a799ca03be9f999aa6c39f7de5209482d638e6f857f6b93b0875c618b7e54 url: "https://pub.dev" source: hosted - version: "12.0.12" + version: "12.0.7" permission_handler_apple: dependency: transitive description: @@ -581,22 +568,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" riverpod: dependency: transitive description: name: riverpod - sha256: c86fedfb45dd1da98ee6493dd9374325cdf494e7d523ebfb0c387eecc5f7b5c9 + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.6.1" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" shared_preferences_android: dependency: transitive description: @@ -710,10 +705,10 @@ packages: dependency: "direct main" description: name: sqflite - sha256: "79a297dc3cc137e758c6a4baf83342b039e5a6d2436fcdf3f96a00adaaf2ad62" + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" sqflite_android: dependency: transitive description: @@ -734,18 +729,18 @@ packages: dependency: "direct main" description: name: sqflite_common_ffi - sha256: a6057d4c87e9260ba1ec436ebac24760a110589b9c0a859e128842eb69a7ef04 + sha256: d316908f1537725427ff2827a5c5f3b2c1bc311caed985fe3c9b10939c9e11ca url: "https://pub.dev" source: hosted - version: "2.3.3+1" + version: "2.3.4" sqflite_darwin: dependency: transitive description: name: sqflite_darwin - sha256: "769733dddf94622d5541c73e4ddc6aa7b252d865285914b6fcd54a63c4b4f027" + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" url: "https://pub.dev" source: hosted - version: "2.4.1-1" + version: "2.4.1" sqflite_platform_interface: dependency: transitive description: @@ -758,10 +753,10 @@ packages: dependency: transitive description: name: sqlite3 - sha256: "45f168ae2213201b54e09429ed0c593dc2c88c924a1488d6f9c523a255d567cb" + sha256: "6d17989c0b06a5870b2190d391925186f944cb943e5262d0d3f778fcfca3bc6e" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.4" sqlite3_flutter_libs: dependency: "direct main" description: @@ -806,10 +801,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" url: "https://pub.dev" source: hosted - version: "3.3.0+3" + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -843,7 +838,7 @@ packages: source: hosted version: "0.6.4" timezone: - dependency: transitive + dependency: "direct main" description: name: timezone sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" @@ -878,34 +873,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "8fc3bae0b68c02c47c5c86fa8bfa74471d42687b0eded01b78de87872db745e2" + sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf url: "https://pub.dev" source: hosted - version: "6.3.12" + version: "6.3.3" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.0" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.1.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: @@ -918,18 +913,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.1" vector_math: dependency: transitive description: @@ -958,26 +953,18 @@ packages: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" + version: "0.5.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -998,10 +985,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.0.4" xml: dependency: transitive description: @@ -1019,5 +1006,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.5.0 <3.24.3" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index eb3c7c1c..c5249242 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,7 @@ name: sossoldi -description: A new Flutter project. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +description: A wealth management / personal finance / net worth tracking app. + +publish_to: 'none' # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -19,77 +18,41 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.1.5 <3.24.3' + sdk: '>=3.3.3 <4.0.0' -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - - # Support for various charts - fl_chart: ^0.64.0 - - # State manager - flutter_riverpod: ^2.1.3 - - # Database storage - sqflite: ^2.2.2 - sqflite_common_ffi: ^2.2.0+1 - - # iOS, Android and MacOS + collection: ^1.18.0 + cupertino_icons: ^1.0.8 + fl_chart: ^0.69.0 + flutter_riverpod: ^2.6.1 + flutter_native_splash: ^2.4.2 + flutter_local_notifications: ^18.0.0 + intl: ^0.19.0 + path: ^1.9.0 + percent_indicator: ^4.2.3 + permission_handler: ^11.3.1 + shared_preferences: ^2.3.3 + sqflite: ^2.4.1 + sqflite_common_ffi: ^2.3.4 sqlite3_flutter_libs: - - # mailto - url_launcher: ^6.0.6 - - # Format DateTime - intl: ^0.18.1 - - # Display todos in grid - flutter_staggered_grid_view: ^0.7.0 - - percent_indicator: ^4.2.2 - circular_menu: ^2.0.1 - flutter_native_splash: ^2.2.18 - shared_preferences: ^2.2.2 - flutter_local_notifications: 17.2.3 - permission_handler: 11.2.0 - workmanager: 0.5.2 + timezone: ^0.9.4 + url_launcher: ^6.3.1 + workmanager: ^0.5.2 dev_dependencies: flutter_test: sdk: flutter - flutter_launcher_icons: ^0.13.1 - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^3.0.1 - - # Flutter test - test: ^1.5.1 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec + dependency_validator: ^4.1.1 + flutter_launcher_icons: ^0.14.1 + flutter_lints: ^5.0.0 + test: ^1.25.2 -# The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true fonts: @@ -97,36 +60,9 @@ flutter: fonts: - asset: fonts/SFProText.ttf - # To add assets to your application, add an assets section, like this: assets: - assets/ - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages - flutter_native_splash: web: false color: "#ffffff" diff --git a/test/model/bank_account_test.dart b/test/model/bank_account_test.dart index cd78c4db..5ad5a46a 100644 --- a/test/model/bank_account_test.dart +++ b/test/model/bank_account_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; import 'package:sossoldi/database/sossoldi_database.dart'; @@ -83,7 +81,7 @@ void main() { assert((b.mainAccount ? 1 : 0) == json[BankAccountFields.mainAccount]); }); - group("Bank Account Methods", () { + group("Bank Account Methods", () { late SossoldiDatabase sossoldiDatabase; late sqflite.Database db; @@ -127,7 +125,7 @@ void main() { final today = DateTime.now(); final fistOfCurrentMonth = DateTime(today.year, today.month, 1); - // Add a transaction of last month + // Add a transaction of last month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)), idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)), idBankAccount: 71, type: 'TRSF', idBankTransfert: 70)); @@ -140,7 +138,7 @@ void main() { // 2 demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 200, type: 'IN')); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), idBankAccount: 71)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 50.5, idBankAccount: 70, type: 'TRSF', idBankTransfert: 71)); // 3 demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); @@ -149,7 +147,7 @@ void main() { // Add recurring transactions. These must be count as number of time they occout * amount - + await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); transactions = await db.rawQuery("SELECT * FROM `transaction`"); @@ -159,9 +157,9 @@ void main() { expect(result.length, 3); var initialAccountAmount = 1235.10; // taken from fillDemoData - expect(result[0].id, 70); + expect(result[0].id, 70); expect(result[0].total! - initialAccountAmount, 49.5); - + initialAccountAmount = 3823.56; // taken from fillDemoData expect(result[1].id, 71); expect(result[1].total! - initialAccountAmount, -449.5); @@ -193,7 +191,7 @@ void main() { final today = DateTime.now(); final fistOfCurrentMonth = DateTime(today.year, today.month, 1); - // Add a transaction of last month + // Add a transaction of last month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)), idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)), idBankAccount: 71, type: 'TRSF', idBankTransfert: 70)); @@ -201,19 +199,19 @@ void main() { // Add transactions of current month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 200, type: 'IN')); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), idBankAccount: 71)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 50.5, idBankAccount: 70, type: 'TRSF', idBankTransfert: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), idBankAccount: 71)); - // Add a transaction of next month + // Add a transaction of next month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 32)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 32)), idBankAccount: 71)); - + await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); transactions = await db.rawQuery("SELECT * FROM `transaction`"); @@ -227,7 +225,7 @@ void main() { final DateFormat formatter = DateFormat('yyyy-MM-dd'); var initialAccountAmount = 1235.10; // taken from fillDemoData - + expect(result[0]['day'], formatter.format(fistOfCurrentMonth)); expect(result[0]['balance'] - initialAccountAmount, -200); expect(result[1]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 1)))); @@ -240,9 +238,9 @@ void main() { dateRangeStart: DateTime(DateTime.now().year, DateTime.now().month, 1), // beginnig of current month dateRangeEnd: DateTime(DateTime.now().year, DateTime.now().month + 1, 1)); // beginnig of next month; expect(result.length, 3); - + initialAccountAmount = 3823.56; // taken from fillDemoData - + expect(result[0]['day'], formatter.format(fistOfCurrentMonth)); expect(result[0]['balance'] - initialAccountAmount, -300); expect(result[1]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 1)))); @@ -252,6 +250,6 @@ void main() { }); }); - + } diff --git a/test/model/transaction_test.dart b/test/model/transaction_test.dart index d7ea30bc..87175054 100644 --- a/test/model/transaction_test.dart +++ b/test/model/transaction_test.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; import 'package:sossoldi/database/sossoldi_database.dart'; @@ -107,7 +105,7 @@ void main() { assert(t.idRecurringTransaction == json[TransactionFields.idRecurringTransaction]); }); - group("Transaction Methods", () { + group("Transaction Methods", () { late SossoldiDatabase sossoldiDatabase; late sqflite.Database db; @@ -126,7 +124,7 @@ void main() { tearDownAll(() { sossoldiDatabase.close(); - }); + }); test("lastMonthDailyTransactions", () async { await sossoldiDatabase.fillDemoData(countOfGeneratedTransaction: 2000); @@ -147,18 +145,18 @@ void main() { final today = DateTime.now(); final fistOfLastMonth = DateTime(today.year, today.month - 1, 1); - // Add a transaction of two month ago + // Add a transaction of two month ago demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.subtract(const Duration(days: 10)))); // Add transactions of last month demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth)); - demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth)); demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.add(const Duration(days: 1)), amount: 200, type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.add(const Duration(days: 2)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.add(const Duration(days: 2)), type: 'IN')); - // Add a transaction of current month + // Add a transaction of current month demoTransactions.add(createInsertSqlTransaction(date: fistOfLastMonth.add(const Duration(days: 32)))); await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); @@ -167,17 +165,17 @@ void main() { expect(result.length, 3); final DateFormat formatter = DateFormat('yyyy-MM-dd'); - + expect(result[0]['day'], formatter.format(fistOfLastMonth)); - expect(result[0]['income'], 0); + expect(result[0]['income'], 0); expect(result[0]['expense'], 200); expect(result[1]['day'], formatter.format(fistOfLastMonth.add(const Duration(days: 1)))); - expect(result[1]['income'], 200); + expect(result[1]['income'], 200); expect(result[1]['expense'], 100); expect(result[2]['day'], formatter.format(fistOfLastMonth.add(const Duration(days: 2)))); - expect(result[2]['income'], 200); + expect(result[2]['income'], 200); expect(result[2]['expense'], 0); }); @@ -200,37 +198,37 @@ void main() { final today = DateTime.now(); final fistOfCurrentMonth = DateTime(today.year, today.month, 1); - // Add a transaction of last month + // Add a transaction of last month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)))); // Add transactions of current month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 200, type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); - // Add a transaction of next month + // Add a transaction of next month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 32)))); - + await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); var result = await TransactionMethods().currentMonthDailyTransactions(); expect(result.length, 3); final DateFormat formatter = DateFormat('yyyy-MM-dd'); - + expect(result[0]['day'], formatter.format(fistOfCurrentMonth)); - expect(result[0]['income'], 0); + expect(result[0]['income'], 0); expect(result[0]['expense'], 200); expect(result[1]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 1)))); - expect(result[1]['income'], 200); + expect(result[1]['income'], 200); expect(result[1]['expense'], 100); expect(result[2]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 2)))); - expect(result[2]['income'], 200); + expect(result[2]['income'], 200); expect(result[2]['expense'], 0); }); @@ -253,14 +251,14 @@ void main() { final today = DateTime.now(); final fistOfCurrentMonth = DateTime(today.year, today.month, 1); - // Add a transaction of last month + // Add a transaction of last month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.subtract(const Duration(days: 10)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); // Add transactions of current month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth)); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 1)), amount: 200, type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); @@ -268,27 +266,27 @@ void main() { demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 2)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); - // Add a transaction of next month + // Add a transaction of next month demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth.add(const Duration(days: 32)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentMonth, idBankAccount: 71)); - + await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); var result = await TransactionMethods().currentMonthDailyTransactions(accountId: 70); expect(result.length, 3); final DateFormat formatter = DateFormat('yyyy-MM-dd'); - + expect(result[0]['day'], formatter.format(fistOfCurrentMonth)); - expect(result[0]['income'], 0); + expect(result[0]['income'], 0); expect(result[0]['expense'], 200); expect(result[1]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 1)))); - expect(result[1]['income'], 200); + expect(result[1]['income'], 200); expect(result[1]['expense'], 100); expect(result[2]['day'], formatter.format(fistOfCurrentMonth.add(const Duration(days: 2)))); - expect(result[2]['income'], 200); + expect(result[2]['income'], 200); expect(result[2]['expense'], 0); }); @@ -311,12 +309,12 @@ void main() { final today = DateTime.now(); final fistOfCurrentYear = DateTime(today.year, 1, 1); - // Add a transaction of last year + // Add a transaction of last year demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.subtract(const Duration(days: 10)))); // Add transactions of current year jan demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear)); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear)); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear)); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 1)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 1)), amount: 200, type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 2)), type: 'IN')); @@ -324,33 +322,33 @@ void main() { // Add transactions of current year dec demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 300)))); - demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 300)))); + demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 300)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 301)))); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 301)), amount: 500, type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 302)), type: 'IN')); demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 302)), type: 'IN')); - // Add a transaction of next year + // Add a transaction of next year demoTransactions.add(createInsertSqlTransaction(date: fistOfCurrentYear.add(const Duration(days: 400)))); - + await db.execute("$insertDemoTransactionsQuery ${demoTransactions.join(",")};"); var result = await TransactionMethods().currentYearMontlyTransactions(); expect(result.length, 2); final DateFormat formatter = DateFormat('yyyy-MM'); - + expect(result[0]['month'], formatter.format(fistOfCurrentYear)); - expect(result[0]['income'], 400); + expect(result[0]['income'], 400); expect(result[0]['expense'], 300); expect(result[1]['month'], formatter.format(fistOfCurrentYear.add(const Duration(days: 300)))); - expect(result[1]['income'], 700); + expect(result[1]['income'], 700); expect(result[1]['expense'], 300); }); - + }); - + } diff --git a/test/widget/accounts_sum_test.dart b/test/widget/accounts_sum_test.dart index 7da3ff97..d129914d 100644 --- a/test/widget/accounts_sum_test.dart +++ b/test/widget/accounts_sum_test.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:flutter/material.dart'; import "dart:math"; @@ -45,7 +44,7 @@ void main() { } else { final accountSum = snapshot.data ?? 0; // TODO need to test total amount with some transactions too - expect(find.text("${accountSum.toStringAsFixed(2).replaceAll('.', ',')}", findRichText: true), findsOneWidget); + expect(find.text(accountSum.toStringAsFixed(2).replaceAll('.', ','), findRichText: true), findsOneWidget); return const Text('Ok!'); } } From 7ee4d6f890d382b7195927a32fa23cee5b274eb5 Mon Sep 17 00:00:00 2001 From: Luca Antonelli Date: Thu, 21 Nov 2024 22:16:02 +0100 Subject: [PATCH 2/3] Update package name - Update project package name from com.example.sossoldi to com.ripsters.sossoldi --- android/app/build.gradle | 4 ++-- android/app/src/debug/AndroidManifest.xml | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- .../main/kotlin/com/example/sossoldi/MainActivity.kt | 2 +- android/app/src/profile/AndroidManifest.xml | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ linux/CMakeLists.txt | 2 +- macos/Runner.xcodeproj/project.pbxproj | 6 +++--- macos/Runner/Configs/AppInfo.xcconfig | 4 ++-- windows/runner/Runner.rc | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 0a572549..38c127f6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,7 +5,7 @@ plugins { } android { - namespace "com.example.sossoldi" + namespace "com.ripsters.sossoldi" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -19,7 +19,7 @@ android { } defaultConfig { - applicationId = "com.example.sossoldi" + applicationId = "com.ripsters.sossoldi" minSdkVersion = flutter.minSdkVersion targetSdkVersion = flutter.targetSdkVersion versionCode = flutter.versionCode diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 8498b877..74d0873c 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.ripsters.sossoldi"> diff --git a/android/app/src/main/kotlin/com/example/sossoldi/MainActivity.kt b/android/app/src/main/kotlin/com/example/sossoldi/MainActivity.kt index 3568fe5c..d97ba2db 100644 --- a/android/app/src/main/kotlin/com/example/sossoldi/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/sossoldi/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.sossoldi +package com.ripsters.sossoldi import io.flutter.embedding.android.FlutterActivity diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 8498b877..74d0873c 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.ripsters.sossoldi">