From f2b405f15293f760a9f5d7759c98a6081db6ef20 Mon Sep 17 00:00:00 2001 From: RaHannes <128587611+RaHannes@users.noreply.github.com> Date: Wed, 5 Jul 2023 02:08:36 +0200 Subject: [PATCH] Language, Design --- trackeroo/lib/app_scaffold.dart | 45 +- .../frontend/utils/transaction_listtile.dart | 205 ++++---- .../lib/frontend/views/categories_view.dart | 38 +- .../lib/frontend/views/details_view.dart | 471 ++++++++++-------- .../frontend/views/edit_category_view.dart | 289 ++++++----- .../frontend/views/edit_settings_view.dart | 96 +++- .../frontend/views/edit_transaction_view.dart | 399 ++++++++------- trackeroo/lib/frontend/views/home_view.dart | 429 ++++++++-------- .../lib/frontend/views/onboarding_view.dart | 121 ++--- .../lib/frontend/views/settings_views.dart | 112 +++-- trackeroo/lib/logic/models/local_String.dart | 92 +++- 11 files changed, 1263 insertions(+), 1034 deletions(-) diff --git a/trackeroo/lib/app_scaffold.dart b/trackeroo/lib/app_scaffold.dart index 6c111b2..8938fd6 100644 --- a/trackeroo/lib/app_scaffold.dart +++ b/trackeroo/lib/app_scaffold.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:trackeroo/frontend/views/edit_category_view.dart'; import 'package:trackeroo/frontend/views/edit_transaction_view.dart'; import 'package:trackeroo/frontend/views/home_view.dart'; @@ -60,37 +61,39 @@ class _AppScaffoldState extends State<AppScaffold> { height: 70, selectedIndex: index, onDestinationSelected: (index) => setState(() => this.index = index), - destinations: const [ - NavigationDestination( + destinations: [ + const NavigationDestination( icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home_rounded), label: 'Home'), - NavigationDestination( + const NavigationDestination( icon: Icon(Icons.bar_chart), selectedIcon: Icon(Icons.bar_chart), label: 'Details'), NavigationDestination( - icon: Icon(Icons.category_outlined), - selectedIcon: Icon(Icons.category_rounded), - label: 'Category') + icon: const Icon(Icons.category_outlined), + selectedIcon: const Icon(Icons.category_rounded), + label: 'Categories'.tr) ], ), ), - floatingActionButton: - locator.get<TransactionsController>().transactionsList.isNotEmpty - ? FloatingActionButton( - onPressed: () => fabOnPressed(), - child: const Icon(Icons.add_rounded), - ) - : FloatingActionButton.extended( - onPressed: () => fabOnPressed(), - label: Row( - children: [ - const Icon(Icons.add_rounded), - const SizedBox(width: 10.0), - Text(index == 2 ? 'add Category' : 'add Transaction') - ], - )), + floatingActionButton: locator + .get<TransactionsController>() + .transactionsList + .isNotEmpty + ? FloatingActionButton( + onPressed: () => fabOnPressed(), + child: const Icon(Icons.add_rounded), + ) + : FloatingActionButton.extended( + onPressed: () => fabOnPressed(), + label: Row( + children: [ + const Icon(Icons.add_rounded), + const SizedBox(width: 10.0), + Text(index == 2 ? 'add Category'.tr : 'add Transaction'.tr) + ], + )), ); } diff --git a/trackeroo/lib/frontend/utils/transaction_listtile.dart b/trackeroo/lib/frontend/utils/transaction_listtile.dart index 82950cf..cb72ddd 100644 --- a/trackeroo/lib/frontend/utils/transaction_listtile.dart +++ b/trackeroo/lib/frontend/utils/transaction_listtile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:trackeroo/frontend/views/edit_transaction_view.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/transaction.dart'; @@ -16,11 +17,27 @@ class TransactionListtile extends StatefulWidget { } class _TransactionListtileState extends State<TransactionListtile> { - final monthsGer = const ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + final monthsGer = const [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]; @override Widget build(BuildContext context) { - Category category = locator.get<CategoriesController>().catBox.get(widget.transaction.categoryId)!; + Category category = locator + .get<CategoriesController>() + .catBox + .get(widget.transaction.categoryId)!; return Padding( padding: const EdgeInsets.only(bottom: 5.0), child: ClipRRect( @@ -30,7 +47,8 @@ class _TransactionListtileState extends State<TransactionListtile> { direction: DismissDirection.startToEnd, onDismissed: (_) => deleteTransaction(context), background: Container( - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 12.0), + padding: + const EdgeInsets.symmetric(vertical: 10.0, horizontal: 12.0), color: Theme.of(context).colorScheme.errorContainer, alignment: Alignment.centerLeft, child: Icon( @@ -47,7 +65,8 @@ class _TransactionListtileState extends State<TransactionListtile> { }, ), child: Container( - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 11.0), + padding: + const EdgeInsets.symmetric(vertical: 10.0, horizontal: 11.0), color: Theme.of(context).colorScheme.secondaryContainer, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -58,10 +77,11 @@ class _TransactionListtileState extends State<TransactionListtile> { width: 50.0, height: 50.0, decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - color: Theme.of(context).colorScheme.surface - ), - child: Icon(IconData(category.iconCodePoint, fontFamily: category.iconFontFamily)), + borderRadius: + const BorderRadius.all(Radius.circular(8.0)), + color: Theme.of(context).colorScheme.surface), + child: Icon(IconData(category.iconCodePoint, + fontFamily: category.iconFontFamily)), ), const SizedBox(width: 17.0), Column( @@ -72,14 +92,11 @@ class _TransactionListtileState extends State<TransactionListtile> { child: Text( widget.transaction.title, style: const TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold - ), + fontSize: 18.0, fontWeight: FontWeight.bold), ), ), Text( - "${widget.transaction.createdAt.day}.${monthsGer[widget.transaction.createdAt.month - 1]} ${widget.transaction.createdAt.year} · ${widget.transaction.createdAt.hour < 10 ? 0 : ''}${widget.transaction.createdAt.hour}:${widget.transaction.createdAt.minute < 10 ? 0 : ''}${widget.transaction.createdAt.minute}" - ) + "${widget.transaction.createdAt.day}.${monthsGer[widget.transaction.createdAt.month - 1]} ${widget.transaction.createdAt.year} · ${widget.transaction.createdAt.hour < 10 ? 0 : ''}${widget.transaction.createdAt.hour}:${widget.transaction.createdAt.minute < 10 ? 0 : ''}${widget.transaction.createdAt.minute}") ], ), ], @@ -87,8 +104,9 @@ class _TransactionListtileState extends State<TransactionListtile> { Text( '${widget.transaction.amount.toStringAsFixed(2)} €', style: TextStyle( - color: widget.transaction.amount.isNegative ? Colors.red[700] : Colors.green[700] - ), + color: widget.transaction.amount.isNegative + ? Colors.red[700] + : Colors.green[700]), ), ], ), @@ -99,7 +117,8 @@ class _TransactionListtileState extends State<TransactionListtile> { ); } - Widget buildModalContent(Transaction transaction, Category category, BuildContext context) { + Widget buildModalContent( + Transaction transaction, Category category, BuildContext context) { return SizedBox( width: double.infinity, child: SafeArea( @@ -111,24 +130,18 @@ class _TransactionListtileState extends State<TransactionListtile> { Text( transaction.title, style: const TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold - ), + fontSize: 18.0, fontWeight: FontWeight.bold), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '${transaction.createdAt.day}.${transaction.createdAt.month}.${transaction.createdAt.year} ', - style: const TextStyle( - fontSize: 15.0 - ), + style: const TextStyle(fontSize: 15.0), ), Text( '${transaction.createdAt.hour < 10 ? 0 : ''}${transaction.createdAt.hour}:${transaction.createdAt.minute < 10 ? 0 : ''}${transaction.createdAt.minute}', - style: const TextStyle( - fontSize: 15.0 - ), + style: const TextStyle(fontSize: 15.0), ) ], ), @@ -136,69 +149,72 @@ class _TransactionListtileState extends State<TransactionListtile> { Text( '${transaction.amount.toStringAsFixed(2)} €', style: const TextStyle( - fontSize: 40.0, - fontWeight: FontWeight.w300 - ), + fontSize: 40.0, fontWeight: FontWeight.w300), ), const SizedBox(height: 20.0), - category.id != 'no_category' ? Container( - padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 12.0), - decoration: BoxDecoration( - color: Color(category.colorValue), - borderRadius: const BorderRadius.all(Radius.circular(8.0)) - ), - child: Row( - children: [ - Icon(IconData(category.iconCodePoint, fontFamily: category.iconFontFamily)), - const SizedBox(width: 20.0), - Text(category.title) - ], - ), - ) : const SizedBox(), + category.id != 'no_category' + ? Container( + padding: const EdgeInsets.symmetric( + horizontal: 15.0, vertical: 12.0), + decoration: BoxDecoration( + color: Color(category.colorValue), + borderRadius: + const BorderRadius.all(Radius.circular(8.0))), + child: Row( + children: [ + Icon(IconData(category.iconCodePoint, + fontFamily: category.iconFontFamily)), + const SizedBox(width: 20.0), + Text(category.title) + ], + ), + ) + : const SizedBox(), const SizedBox(height: 20.0), - const Expanded(child: SizedBox()), // to be removed when more content is added + const Expanded( + child: + SizedBox()), // to be removed when more content is added Row( children: [ Expanded( child: FilledButton.tonal( - onPressed: () { - deleteTransaction(context); - Navigator.of(context).pop(); - }, - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.delete_rounded, - size: 16.0, - ), - SizedBox(width: 10.0), - Text('Delete'), - ], - ) - ), + onPressed: () { + deleteTransaction(context); + Navigator.of(context).pop(); + }, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.delete_rounded, + size: 16.0, + ), + SizedBox(width: 10.0), + Text('Delete'), + ], + )), ), const SizedBox(width: 10.0), Expanded( child: FilledButton.tonal( - onPressed: () => { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => EditTransactionView(transaction: transaction)) - ) - }, - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.edit, - size: 16.0, - ), - SizedBox(width: 10.0), - Text('Edit'), - ], - ) - ), + onPressed: () => { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EditTransactionView( + transaction: transaction))) + }, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.edit, + size: 16.0, + ), + SizedBox(width: 10.0), + Text('Edit'), + ], + )), ) ], ) @@ -211,26 +227,25 @@ class _TransactionListtileState extends State<TransactionListtile> { void deleteTransaction(BuildContext context) { setState(() { - locator.get<TransactionsController>().deleteTransaction(widget.transaction); + locator + .get<TransactionsController>() + .deleteTransaction(widget.transaction); }); ScaffoldMessenger.of(context).removeCurrentSnackBar(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Transaction deleted', - style: TextStyle( - color: Theme.of(context).colorScheme.onSecondary - ), - ), - backgroundColor: Theme.of(context).colorScheme.secondary, - behavior: SnackBarBehavior.floating, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), - action: SnackBarAction( - label: 'Undo', + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Transaction deleted'.tr, + style: TextStyle(color: Theme.of(context).colorScheme.onSecondary), + ), + backgroundColor: Theme.of(context).colorScheme.secondary, + behavior: SnackBarBehavior.floating, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0))), + action: SnackBarAction( + label: 'Undo'.tr, textColor: Theme.of(context).colorScheme.onSecondary, - onPressed: () => locator.get<TransactionsController>().undoLastDeletion() - ), - ) - ); + onPressed: () => + locator.get<TransactionsController>().undoLastDeletion()), + )); } } diff --git a/trackeroo/lib/frontend/views/categories_view.dart b/trackeroo/lib/frontend/views/categories_view.dart index f892526..3f26e1c 100644 --- a/trackeroo/lib/frontend/views/categories_view.dart +++ b/trackeroo/lib/frontend/views/categories_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/frontend/utils/category_listtile.dart'; import 'package:trackeroo/logic/models/category.dart'; @@ -16,26 +17,29 @@ class CategoriesView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ - const Text( - 'Categories', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), + Text( + 'Categories'.tr, + style: + const TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold), ), const SizedBox(height: 10.0), ValueListenableBuilder( - valueListenable: locator.get<CategoriesController>().catBox.listenable(), - builder: (context, Box<Category> box, child) { - locator.get<CategoriesController>().categories = box.toMap(); - return ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: box.length, - itemBuilder: (context, index) => CategoryListtile(category: locator.get<CategoriesController>().categories.values.elementAt(index)), - ); - } - ), + valueListenable: + locator.get<CategoriesController>().catBox.listenable(), + builder: (context, Box<Category> box, child) { + locator.get<CategoriesController>().categories = box.toMap(); + return ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: box.length, + itemBuilder: (context, index) => CategoryListtile( + category: locator + .get<CategoriesController>() + .categories + .values + .elementAt(index)), + ); + }), const SizedBox(height: 65.0) ], ), diff --git a/trackeroo/lib/frontend/views/details_view.dart b/trackeroo/lib/frontend/views/details_view.dart index 0f3250b..000e11a 100644 --- a/trackeroo/lib/frontend/views/details_view.dart +++ b/trackeroo/lib/frontend/views/details_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:get/get.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/frontend/utils/transaction_listtile.dart'; import 'package:trackeroo/logic/models/app_state.dart'; @@ -18,9 +19,10 @@ class DetailsView extends StatefulWidget { } class _DetailsViewState extends State<DetailsView> { - - TransactionsController transactionsController = locator.get<TransactionsController>(); - DateTimeRange timespan = DateTimeRange(start: DateTime.now(), end: DateTime.now()); + TransactionsController transactionsController = + locator.get<TransactionsController>(); + DateTimeRange timespan = + DateTimeRange(start: DateTime.now(), end: DateTime.now()); // List<String> selectedCategoryIds = ; AppState appState = locator.get<AppStateController>().appState; @@ -29,9 +31,8 @@ class _DetailsViewState extends State<DetailsView> { void initState() { if (transactionsController.transactionsList.isNotEmpty) { timespan = DateTimeRange( - start: transactionsController.transactionsList.last.createdAt, - end: transactionsController.transactionsList.first.createdAt - ); + start: transactionsController.transactionsList.last.createdAt, + end: transactionsController.transactionsList.first.createdAt); } super.initState(); } @@ -41,239 +42,281 @@ class _DetailsViewState extends State<DetailsView> { return SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: ValueListenableBuilder( - valueListenable: locator.get<AppStateController>().appStateBox.listenable(), - builder: (context, Box<dynamic> appStateBox, child) { - return ValueListenableBuilder( - valueListenable: locator.get<TransactionsController>().transactionsBox.listenable(), - builder: (context, Box<Transaction> box, child) { - List<Transaction> filteredTransList = box.values.toList().where((element) => appState.detailsTransactionsFilter.contains(element.categoryId)).toList(); - filteredTransList.sort((b, a) => a.createdAt.compareTo(b.createdAt)); - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - const Text( - 'Datails chart', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), - ), - const SizedBox(height: 20.0), - Center( - child : Container( - width: 400, - height: 250, - padding: const EdgeInsets.only(right: 20.0), - child: LineChart( - LineChartData( - borderData: FlBorderData( - show: true, - border: Border.symmetric( - horizontal: BorderSide( - color: Theme.of(context).colorScheme.onSurface, - width: 0.5 - ) - ) - ), - gridData: FlGridData( - show: true, - getDrawingHorizontalLine: (value) { - return FlLine( - color: Theme.of(context).colorScheme.onSurface, - strokeWidth: 0.5 - ); - }, - drawVerticalLine: false, - ), - titlesData: FlTitlesData( - show: true, - rightTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - topTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false) - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - // interval: 1, - reservedSize: 30, - ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - // interval: 50, - reservedSize: 42, - ), - ), - ), - // maxX: 12, - // maxY: 200, - minY: 0, - minX: 0, - lineBarsData: buildBarData(filteredTransList) - ) - ) - ) - ), - const SizedBox(height: 5.0), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - IconButton.filledTonal( - visualDensity: VisualDensity.compact, - onPressed: () => showModalBottomSheet( - useSafeArea: true, - showDragHandle: true, - isScrollControlled: true, - context: context, - builder: (context) => StatefulBuilder( - builder: (BuildContext context, StateSetter setState) => Container( - // height: 650.0, - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Choose categories', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold + valueListenable: + locator.get<AppStateController>().appStateBox.listenable(), + builder: (context, Box<dynamic> appStateBox, child) { + return ValueListenableBuilder( + valueListenable: locator + .get<TransactionsController>() + .transactionsBox + .listenable(), + builder: (context, Box<Transaction> box, child) { + List<Transaction> filteredTransList = box.values + .toList() + .where((element) => appState.detailsTransactionsFilter + .contains(element.categoryId)) + .toList(); + filteredTransList + .sort((b, a) => a.createdAt.compareTo(b.createdAt)); + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + Text( + 'Datails chart'.tr, + style: const TextStyle( + fontSize: 14.0, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 20.0), + Center( + child: Container( + width: 400, + height: 250, + padding: const EdgeInsets.only(right: 20.0), + child: LineChart(LineChartData( + borderData: FlBorderData( + show: true, + border: Border.symmetric( + horizontal: BorderSide( + color: Theme.of(context) + .colorScheme + .onSurface, + width: 0.5))), + gridData: FlGridData( + show: true, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Theme.of(context) + .colorScheme + .onSurface, + strokeWidth: 0.5); + }, + drawVerticalLine: false, ), - ), - for(Category category in locator.get<CategoriesController>().categories.values) CheckboxListTile( - title: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Icon( - IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), - color: Color(category.colorValue), - size: 18.0, + titlesData: FlTitlesData( + show: true, + rightTitles: AxisTitles( + sideTitles: + SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: + SideTitles(showTitles: false)), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + // interval: 1, + reservedSize: 30, ), - const SizedBox(width: 10.0), - Text( - category.title, - style: const TextStyle( - fontSize: 15.0 - ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + // interval: 50, + reservedSize: 42, ), - ], + ), ), - value: appState.detailsTransactionsFilter.contains(category.id), - contentPadding: const EdgeInsets.all(0.0), - dense: true, - onChanged: (value) => setState(() { - if(appState.detailsTransactionsFilter.contains(category.id)) { - appState.detailsTransactionsFilter.remove(category.id); - } else { - appState.detailsTransactionsFilter.add(category.id); - } - locator.get<AppStateController>().safeAppState(); - }) - ), - ] - ), - ), - ) - ), - icon: const Row( + // maxX: 12, + // maxY: 200, + minY: 0, + minX: 0, + lineBarsData: + buildBarData(filteredTransList))))), + const SizedBox(height: 5.0), + Row( + mainAxisAlignment: MainAxisAlignment.end, children: [ - Icon( - Icons.category_rounded, - size: 14.0, - ), - SizedBox(width: 5.0), - Text('Categories') - ], - ) - ), - const SizedBox(width: 10.0), - IconButton.filledTonal( - visualDensity: VisualDensity.compact, - onPressed: () => { - showDateRangePicker( - context: context, - firstDate: filteredTransList.isNotEmpty ? filteredTransList.last.createdAt : DateTime.now(), - lastDate: filteredTransList.isNotEmpty ? filteredTransList.first.createdAt : DateTime.now(), - helpText: 'Choose timespan', - saveText: 'Done' - ), - }, - icon: const Row( - children: [ - Icon( - Icons.date_range_rounded, - size: 14.0, - ), - SizedBox(width: 5.0), - Text('Timespan') + IconButton.filledTonal( + visualDensity: VisualDensity.compact, + onPressed: () => showModalBottomSheet( + useSafeArea: true, + showDragHandle: true, + isScrollControlled: true, + context: context, + builder: (context) => StatefulBuilder( + builder: (BuildContext context, + StateSetter setState) => + Container( + // height: 650.0, + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 20.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + 'Choose categories'.tr, + style: const TextStyle( + fontSize: 16.0, + fontWeight: + FontWeight.bold), + ), + for (Category category in locator + .get< + CategoriesController>() + .categories + .values) + CheckboxListTile( + title: Row( + mainAxisAlignment: + MainAxisAlignment + .start, + children: [ + Icon( + IconData( + category + .iconCodePoint, + fontFamily: + category + .iconFontFamily), + color: Color(category + .colorValue), + size: 18.0, + ), + const SizedBox( + width: 10.0), + Text( + category.title, + style: + const TextStyle( + fontSize: + 15.0), + ), + ], + ), + value: appState + .detailsTransactionsFilter + .contains( + category.id), + contentPadding: + const EdgeInsets + .all(0.0), + dense: true, + onChanged: + (value) => + setState(() { + if (appState + .detailsTransactionsFilter + .contains( + category + .id)) { + appState + .detailsTransactionsFilter + .remove( + category.id); + } else { + appState + .detailsTransactionsFilter + .add(category + .id); + } + locator + .get< + AppStateController>() + .safeAppState(); + })), + ]), + ), + )), + icon: Row( + children: [ + const Icon( + Icons.category_rounded, + size: 14.0, + ), + const SizedBox(width: 5.0), + Text('category'.tr) + ], + )), + const SizedBox(width: 10.0), + IconButton.filledTonal( + visualDensity: VisualDensity.compact, + onPressed: () => { + showDateRangePicker( + context: context, + firstDate: filteredTransList + .isNotEmpty + ? filteredTransList.last.createdAt + : DateTime.now(), + lastDate: + filteredTransList.isNotEmpty + ? filteredTransList + .first.createdAt + : DateTime.now(), + helpText: 'Choose timespan'.tr, + saveText: 'done'.tr), + }, + icon: Row( + children: [ + const Icon( + Icons.date_range_rounded, + size: 14.0, + ), + const SizedBox(width: 5.0), + Text('Timespan'.tr) + ], + )), ], - ) - ), - ], - ), - const SizedBox(height: 10.0), - const Text( - 'Transactions', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), - ), - const SizedBox(height: 5.0), - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: filteredTransList.length, - itemBuilder: (context, index) => TransactionListtile(transaction: filteredTransList[index]), - ), - const SizedBox(height: 65.0) - ] - ); - } - ); - } - ), + ), + const SizedBox(height: 10.0), + Text( + 'transactions'.tr, + style: const TextStyle( + fontSize: 14.0, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 5.0), + ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: filteredTransList.length, + itemBuilder: (context, index) => TransactionListtile( + transaction: filteredTransList[index]), + ), + const SizedBox(height: 65.0) + ]); + }); + }), ); } List<LineChartBarData> buildBarData(List<Transaction> transactionsList) { List<LineChartBarData> categoryBars = []; List<Category> selectedCategories = []; - for(String categoryId in appState.detailsTransactionsFilter) { - if(locator.get<CategoriesController>().categories.containsKey(categoryId)) { - selectedCategories.add(locator.get<CategoriesController>().categories[categoryId]!); + for (String categoryId in appState.detailsTransactionsFilter) { + if (locator + .get<CategoriesController>() + .categories + .containsKey(categoryId)) { + selectedCategories + .add(locator.get<CategoriesController>().categories[categoryId]!); } } - for (Category category in locator.get<CategoriesController>().categories.values) { + for (Category category + in locator.get<CategoriesController>().categories.values) { List<FlSpot> categoryDataPoints = [const FlSpot(0.0, 0.0)]; int xVal = 1; - for(Transaction transaction in transactionsList) { - if(transaction.categoryId == category.id) { - categoryDataPoints.add(FlSpot(xVal.toDouble(), transaction.amount.abs())); + for (Transaction transaction in transactionsList) { + if (transaction.categoryId == category.id) { + categoryDataPoints + .add(FlSpot(xVal.toDouble(), transaction.amount.abs())); xVal++; } } - categoryBars.add( - LineChartBarData( + categoryBars.add(LineChartBarData( spots: categoryDataPoints, isCurved: false, color: Color(category.colorValue), barWidth: 2, isStrokeCapRound: true, dotData: FlDotData( - show: true, - getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter( - radius: 2.5, - color: Color(category.colorValue), - strokeColor: Colors.transparent - ) - ) - ) - ); + show: true, + getDotPainter: (spot, percent, barData, index) => + FlDotCirclePainter( + radius: 2.5, + color: Color(category.colorValue), + strokeColor: Colors.transparent)))); } return categoryBars; } diff --git a/trackeroo/lib/frontend/views/edit_category_view.dart b/trackeroo/lib/frontend/views/edit_category_view.dart index e1550f1..ece5ab7 100644 --- a/trackeroo/lib/frontend/views/edit_category_view.dart +++ b/trackeroo/lib/frontend/views/edit_category_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:trackeroo/logic/constants/selecable_colors.dart'; import 'package:trackeroo/logic/constants/selectable_icons.dart'; import 'package:trackeroo/logic/models/category.dart'; @@ -29,9 +30,10 @@ class _EditCategoryViewState extends State<EditCategoryView> { if (widget.category != null) { _nameController.text = widget.category!.title; _selectedColor = Color(widget.category!.colorValue); - _selectedIcon = IconData(widget.category!.iconCodePoint, fontFamily: widget.category!.iconFontFamily); + _selectedIcon = IconData(widget.category!.iconCodePoint, + fontFamily: widget.category!.iconFontFamily); _hasBudget = !widget.category!.budget.isNegative; - if(_hasBudget) { + if (_hasBudget) { _budget = widget.category!.budget; _budgetController.text = widget.category!.budget.toString(); } @@ -66,33 +68,38 @@ class _EditCategoryViewState extends State<EditCategoryView> { context: context, builder: (BuildContext context) { return AlertDialog( - insetPadding: const EdgeInsets.symmetric(vertical: 100.0, horizontal: 20.0), + insetPadding: + const EdgeInsets.symmetric(vertical: 100.0, horizontal: 20.0), scrollable: true, - title: const Text('Choose color'), + title: Text('CC'.tr), content: Column( children: [ - for(SelectableColor selecableColor in selectableColors.values) SizedBox( - width: 500.0, - child: GestureDetector( - onTap: () => setState(() { - _selectedColor = selectableColors[selecableColor.title]!.color; - Navigator.of(context).pop(); - }), - child: ListTile( - dense: true, - leading: Container( - width: 20.0, - height: 20.0, - decoration: BoxDecoration( - color: selecableColor.color, - shape: BoxShape.circle + for (SelectableColor selecableColor in selectableColors.values) + SizedBox( + width: 500.0, + child: GestureDetector( + onTap: () => setState(() { + _selectedColor = + selectableColors[selecableColor.title]!.color; + Navigator.of(context).pop(); + }), + child: ListTile( + dense: true, + leading: Container( + width: 20.0, + height: 20.0, + decoration: BoxDecoration( + color: selecableColor.color, + shape: BoxShape.circle), ), + title: Text(selecableColor.title), + trailing: _selectedColor == + selectableColors[selecableColor.title]?.color + ? const Icon(Icons.check_rounded) + : null, ), - title: Text(selecableColor.title), - trailing: _selectedColor == selectableColors[selecableColor.title]?.color ? const Icon(Icons.check_rounded) : null, ), - ), - ) + ) ], ), ); @@ -101,18 +108,16 @@ class _EditCategoryViewState extends State<EditCategoryView> { } void _createCategory() { - if(_nameController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Title cannot be empty')) - ); + if (_nameController.text.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text('TCBE'.tr))); return; } Category newCategory = Category( - id: _nameController.text.replaceAll(' ', '_').toLowerCase(), - title: _nameController.text, - iconCodePoint: _selectedIcon.codePoint, - colorValue: _selectedColor.value - ); + id: _nameController.text.replaceAll(' ', '_').toLowerCase(), + title: _nameController.text, + iconCodePoint: _selectedIcon.codePoint, + colorValue: _selectedColor.value); locator.get<CategoriesController>().saveCategory(newCategory); Navigator.of(context).pop(); } @@ -143,38 +148,40 @@ class _EditCategoryViewState extends State<EditCategoryView> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('edit Category'), + title: Text('EC'.tr), actions: [ IconButton( - onPressed: () => widget.category != null ? showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Delete Category'), - content: const Text('Do you really want to delete this category?\nIt will be lost forever.'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); + onPressed: () => widget.category != null + ? showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('DC'.tr), + content: Text('mes'.tr), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('Cancel'.tr), + ), + TextButton( + onPressed: () => _deleteCategory(), + child: Text( + 'Delete'.tr, + style: TextStyle( + color: Theme.of(context).colorScheme.error), + ), + ), + ], + ); }, - child: const Text('Cancel'), - ), - TextButton( - onPressed: () => _deleteCategory(), - child: Text( - 'Delete', - style: TextStyle( - color: Theme.of(context).colorScheme.error - ), - ), - ), - ], - ); - }, - ) : Navigator.of(context).pop(), - padding: const EdgeInsets.all(16.0), - icon: Icon(widget.category != null ? Icons.delete_rounded : Icons.close_rounded) - ) + ) + : Navigator.of(context).pop(), + padding: const EdgeInsets.all(16.0), + icon: Icon(widget.category != null + ? Icons.delete_rounded + : Icons.close_rounded)) ], ), body: SingleChildScrollView( @@ -185,9 +192,7 @@ class _EditCategoryViewState extends State<EditCategoryView> { children: [ const Text( 'Icon', - style: TextStyle( - fontWeight: FontWeight.bold - ), + style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 70.0), Center( @@ -195,38 +200,42 @@ class _EditCategoryViewState extends State<EditCategoryView> { onTap: () => showDialog( context: context, builder: (context) => AlertDialog( - insetPadding: const EdgeInsets.symmetric(vertical: 100.0, horizontal: 20.0), - scrollable: true, - title: const Text('Choose icon'), - content: SizedBox( - height: 450.0, - width: 500.0, - child: GridView.count( - crossAxisCount: 5, - children: [ - for(IconData selectableIconData in selectableIcons) GestureDetector( - onTap: () => setState(() { - _selectedIcon = selectableIconData; - Navigator.of(context).pop(); - }), - child: Container( - height: 20.0, - width: 20.0, - padding: const EdgeInsets.all(5.0), - margin: const EdgeInsets.all(5.0), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: selectableIconData == _selectedIcon - ? Theme.of(context).colorScheme.background - : null - ), - child: Icon(selectableIconData), - ), - ) - ], - ), - ) - ), + insetPadding: const EdgeInsets.symmetric( + vertical: 100.0, horizontal: 20.0), + scrollable: true, + title: Text('Choose icon'.tr), + content: SizedBox( + height: 450.0, + width: 500.0, + child: GridView.count( + crossAxisCount: 5, + children: [ + for (IconData selectableIconData + in selectableIcons) + GestureDetector( + onTap: () => setState(() { + _selectedIcon = selectableIconData; + Navigator.of(context).pop(); + }), + child: Container( + height: 20.0, + width: 20.0, + padding: const EdgeInsets.all(5.0), + margin: const EdgeInsets.all(5.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: + selectableIconData == _selectedIcon + ? Theme.of(context) + .colorScheme + .background + : null), + child: Icon(selectableIconData), + ), + ) + ], + ), + )), ), child: _buildIconContainer(_selectedIcon, 100.0), ), @@ -234,26 +243,19 @@ class _EditCategoryViewState extends State<EditCategoryView> { const SizedBox(height: 70.0), const Text( 'Name', - style: TextStyle( - fontWeight: FontWeight.bold - ), + style: TextStyle(fontWeight: FontWeight.bold), ), TextField( controller: _nameController, - decoration: const InputDecoration( - isDense: true, - hintText: 'Category Name', - hintStyle: TextStyle( - fontWeight: FontWeight.normal - ) - ), + decoration: InputDecoration( + isDense: true, + hintText: 'Category Name'.tr, + hintStyle: const TextStyle(fontWeight: FontWeight.normal)), ), const SizedBox(height: 30.0), - const Text( - 'Color', - style: TextStyle( - fontWeight: FontWeight.bold - ), + Text( + 'Color'.tr, + style: const TextStyle(fontWeight: FontWeight.bold), ), GestureDetector( onTap: _showColorPicker, @@ -269,41 +271,39 @@ class _EditCategoryViewState extends State<EditCategoryView> { height: 20.0, width: 20.0, decoration: BoxDecoration( - color: _selectedColor, - shape: BoxShape.circle - ), + color: _selectedColor, shape: BoxShape.circle), ), const SizedBox(width: 10.0), - Text( - selectableColors.values.where((element) => element.color == _selectedColor).isNotEmpty - ? selectableColors.values.where((element) => element.color == _selectedColor).first.title - : 'Choose color' - ), + Text(selectableColors.values + .where( + (element) => element.color == _selectedColor) + .isNotEmpty + ? selectableColors.values + .where( + (element) => element.color == _selectedColor) + .first + .title + : 'CC'.tr), ], ), ), ), const SizedBox(height: 20.0), - const Text( - 'Budget', - style: TextStyle( - fontWeight: FontWeight.bold - ), + Text( + 'Budget'.tr, + style: const TextStyle(fontWeight: FontWeight.bold), ), CheckboxListTile( - title: const Text( - 'set Budget', - style: TextStyle( - fontSize: 16.0 + title: Text( + 'set Budget'.tr, + style: const TextStyle(fontSize: 16.0), ), - ), - contentPadding: const EdgeInsets.all(0.0), - dense: true, - value: _hasBudget, - onChanged: (value) => setState(() { - _hasBudget = !_hasBudget; - }) - ), + contentPadding: const EdgeInsets.all(0.0), + dense: true, + value: _hasBudget, + onChanged: (value) => setState(() { + _hasBudget = !_hasBudget; + })), AbsorbPointer( absorbing: !_hasBudget, child: Opacity( @@ -315,14 +315,12 @@ class _EditCategoryViewState extends State<EditCategoryView> { Expanded( child: TextField( controller: _budgetController, - decoration: const InputDecoration( - hintText: 'Budget', - hintStyle: TextStyle( - fontWeight: FontWeight.normal - ), - isDense: true, - border: InputBorder.none - ), + decoration: InputDecoration( + hintText: 'Budget'.tr, + hintStyle: const TextStyle( + fontWeight: FontWeight.normal), + isDense: true, + border: InputBorder.none), keyboardType: TextInputType.number, ), ), @@ -336,7 +334,8 @@ class _EditCategoryViewState extends State<EditCategoryView> { ), ), floatingActionButton: FloatingActionButton( - onPressed:() => widget.category != null ? _updateCategory() : _createCategory(), + onPressed: () => + widget.category != null ? _updateCategory() : _createCategory(), child: const Icon(Icons.save_rounded), ), ); diff --git a/trackeroo/lib/frontend/views/edit_settings_view.dart b/trackeroo/lib/frontend/views/edit_settings_view.dart index c74b58f..cbcd806 100644 --- a/trackeroo/lib/frontend/views/edit_settings_view.dart +++ b/trackeroo/lib/frontend/views/edit_settings_view.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:trackeroo/frontend/views/settings_views.dart'; import 'package:trackeroo/logic/services/locator.dart'; import '../../logic/models/profile.dart'; import 'package:trackeroo/logic/services/profile_controller.dart'; @@ -21,6 +20,62 @@ class _EditSettingsView extends State<EditSettingsView> { TextEditingController emailController = TextEditingController(); String imageController = ''; + ProfileController profileController = locator.get<ProfileController>(); + + Widget fillNameTextField(String text) { + if (nameController.text.isEmpty) { + nameController.text = text; + } + return TextField( + controller: nameController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'enterNa'.tr, + prefixIcon: const Icon(Icons.person_2), + border: const OutlineInputBorder(), + ), + style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w300), + ); + } + + Widget fillNumberTextField(String text) { + if (numberController.text.isEmpty) { + numberController.text = text; + } + return TextField( + controller: numberController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + contentPadding: const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'enterNu'.tr, + prefixIcon: const Icon(Icons.phone_android), + border: const OutlineInputBorder(), + ), + style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w300), + ); + } + + Widget fillEmailTextField(String text) { + if (emailController.text.isEmpty) { + emailController.text = text; + } + return TextField( + controller: emailController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'enterE'.tr, + prefixIcon: const Icon(Icons.email), + border: const OutlineInputBorder(), + ), + style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w300), + ); + } + + getImage(String path) { + String filePath = path.replaceFirst('file://', ''); + return filePath; + } + Future<bool> _updateProfile() async { if (nameController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( @@ -70,8 +125,7 @@ class _EditSettingsView extends State<EditSettingsView> { CircleAvatar( radius: 80.0, backgroundImage: _imageFile == null - ? const NetworkImage( - 'https://images.bild.de/64928bbc72f9093ee562d003/2265ccc3e85215843e55f38b5a7cdaf5,8321f2dd?w=992') + ? FileImage(File(getImage(profileController.profile.imagePath))) : FileImage(File(_imageFile!.path)) as ImageProvider<Object>?, ), Positioned( @@ -169,32 +223,28 @@ class _EditSettingsView extends State<EditSettingsView> { const SizedBox( height: 20, ), - TextField( - controller: nameController, - decoration: InputDecoration( - border: const OutlineInputBorder(), - hintText: 'name'.tr, - )), - TextField( - controller: numberController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - border: const OutlineInputBorder(), - hintText: 'Number'.tr, - ), + fillNameTextField(locator.get<ProfileController>().profile.name), + const SizedBox( + height: 20, ), - TextField( - controller: emailController, - decoration: InputDecoration( - border: const OutlineInputBorder(), - hintText: 'email'.tr, - ), + fillNumberTextField( + locator.get<ProfileController>().profile.number.toString()), + const SizedBox( + height: 20, + ), + fillEmailTextField(locator.get<ProfileController>().profile.email), + const SizedBox( + height: 20, ), ElevatedButton( onPressed: () async => {if (await _updateProfile()) Navigator.pop(context)}, + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all<Color>(Colors.grey.shade300), + ), child: Text('Save'.tr), - ) + ), ], ), ), diff --git a/trackeroo/lib/frontend/views/edit_transaction_view.dart b/trackeroo/lib/frontend/views/edit_transaction_view.dart index bd8dd80..a29f08f 100644 --- a/trackeroo/lib/frontend/views/edit_transaction_view.dart +++ b/trackeroo/lib/frontend/views/edit_transaction_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/transaction.dart'; import 'package:trackeroo/logic/services/categories_controller.dart'; @@ -17,7 +18,6 @@ class EditTransactionView extends StatefulWidget { } class _EditTransactionViewState extends State<EditTransactionView> { - final TextEditingController _titleController = TextEditingController(); final TextEditingController _amountController = TextEditingController(); String categoryId = ''; @@ -31,7 +31,7 @@ class _EditTransactionViewState extends State<EditTransactionView> { @override void initState() { transExists = widget.transaction != null; - if(transExists) { + if (transExists) { oldAmount = widget.transaction!.amount; _titleController.text = widget.transaction!.title; isExpense = widget.transaction!.amount.isNegative; @@ -46,194 +46,187 @@ class _EditTransactionViewState extends State<EditTransactionView> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(transExists ? 'Edit Transaction': 'Create Transaction'), + title: Text(transExists ? 'ET'.tr : 'CT'.tr), elevation: 0.0, scrolledUnderElevation: 0.0, actions: [ IconButton( - onPressed: () => Navigator.pop(context), - padding: const EdgeInsets.all(12.0), - icon: const Icon(Icons.close_rounded) - ), + onPressed: () => Navigator.pop(context), + padding: const EdgeInsets.all(12.0), + icon: const Icon(Icons.close_rounded)), const SizedBox(width: 16.0) ], ), body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(30.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - TextField( - controller: _titleController, - decoration: const InputDecoration( - border: InputBorder.none, - hintText: 'Title', - hintStyle: TextStyle( - fontWeight: FontWeight.normal - ) - ), - ), - const SizedBox(height: 50.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - onPressed: () => setState(() { - isExpense = !isExpense; - }), - icon: Icon(isExpense ? Icons.remove_rounded : Icons.add_rounded) - ), - SizedBox( - width: 200.0, - child: TextField( - controller: _amountController, - keyboardType: TextInputType.number, + child: Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + TextField( + controller: _titleController, decoration: const InputDecoration( - contentPadding: EdgeInsets.only(left: 10.0, bottom: 7.0), - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - hintText: 'Amount', - hintStyle: TextStyle( - fontWeight: FontWeight.w300 - ), - ), - style: const TextStyle( - fontSize: 40.0, - fontWeight: FontWeight.w300 - ), - ) - ), - const SizedBox(width: 10.0), - ], - ), - const SizedBox(height: 50.0), - SizedBox( - width: double.infinity, - child: DropdownButton( - hint: const Text('Category'), - isExpanded: true, - borderRadius: const BorderRadius.all(Radius.circular(10.0)), - underline: const SizedBox(), - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.normal, - color: Theme.of(context).colorScheme.onSurface - ), - items: [ - DropdownMenuItem( - value: '', - child: Text( - 'Category', - style: TextStyle( - color: Theme.of(context).colorScheme.onSurface.withAlpha(150) - ) - ), + border: InputBorder.none, + hintText: 'Title', + hintStyle: TextStyle(fontWeight: FontWeight.normal)), + ), + const SizedBox(height: 50.0), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => setState(() { + isExpense = !isExpense; + }), + icon: Icon(isExpense + ? Icons.remove_rounded + : Icons.add_rounded)), + SizedBox( + width: 200.0, + child: TextField( + controller: _amountController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + contentPadding: const EdgeInsets.only( + left: 10.0, bottom: 7.0), + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + hintText: 'amount'.tr, + hintStyle: const TextStyle( + fontWeight: FontWeight.w300), + ), + style: const TextStyle( + fontSize: 40.0, fontWeight: FontWeight.w300), + )), + const SizedBox(width: 10.0), + ], ), - for(Category cat in locator.get<CategoriesController>().categories.values) DropdownMenuItem( - value: cat.id, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Icon(IconData(cat.iconCodePoint, fontFamily: cat.iconFontFamily)), - const SizedBox(width: 20.0), - Text(cat.title) - ], - ), - Container( - height: 15.0, - width: 15.0, - decoration: BoxDecoration( - color: Color(cat.colorValue), - shape: BoxShape.circle + const SizedBox(height: 50.0), + SizedBox( + width: double.infinity, + child: DropdownButton( + hint: Text('category'.tr), + isExpanded: true, + borderRadius: + const BorderRadius.all(Radius.circular(10.0)), + underline: const SizedBox(), + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.normal, + color: Theme.of(context).colorScheme.onSurface), + items: [ + DropdownMenuItem( + value: '', + child: Text('category'.tr, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onSurface + .withAlpha(150))), ), - ) - ], - ) - ) - ], - value: categoryId, - onChanged: (value) { - setState(() { - categoryId = value.toString(); - }); - } - ), - ), - Theme( - data: Theme.of(context).copyWith( - splashColor: Colors.transparent, - highlightColor: Colors.transparent, - hoverColor: Colors.transparent - ), - child: CheckboxListTile( - title: const Text('Scheduled payment'), - contentPadding: const EdgeInsets.all(0.0), - value: isScheduled, - onChanged: (value) => setState(() { - isScheduled = !isScheduled; - }) - ), - ), - AbsorbPointer( - absorbing: !isScheduled, - child: Opacity( - opacity: !isScheduled ? 0.5 : 1, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FilterChip( - onSelected: (value) => setState(() { - selectedTimespan = Timespan.daily; - }), - label: const Text('Daily'), - selected: selectedTimespan == Timespan.daily, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - selectedTimespan = Timespan.weekly; - }), - label: const Text('Weekly'), - selected: selectedTimespan == Timespan.weekly, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - selectedTimespan = Timespan.monthly; - }), - label: const Text('Montly'), - selected: selectedTimespan == Timespan.monthly, - showCheckmark: false - ), - FilterChip( - onSelected: (value) => setState(() { - selectedTimespan = Timespan.yearly; - }), - label: const Text('Yearly'), - selected: selectedTimespan == Timespan.yearly, - showCheckmark: false - ) - ], + for (Category cat in locator + .get<CategoriesController>() + .categories + .values) + DropdownMenuItem( + value: cat.id, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Icon(IconData(cat.iconCodePoint, + fontFamily: cat.iconFontFamily)), + const SizedBox(width: 20.0), + Text(cat.title) + ], + ), + Container( + height: 15.0, + width: 15.0, + decoration: BoxDecoration( + color: Color(cat.colorValue), + shape: BoxShape.circle), + ) + ], + )) + ], + value: categoryId, + onChanged: (value) { + setState(() { + categoryId = value.toString(); + }); + }), + ), + Theme( + data: Theme.of(context).copyWith( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + hoverColor: Colors.transparent), + child: CheckboxListTile( + title: Text('SP'.tr), + contentPadding: const EdgeInsets.all(0.0), + value: isScheduled, + onChanged: (value) => setState(() { + isScheduled = !isScheduled; + })), + ), + AbsorbPointer( + absorbing: !isScheduled, + child: Opacity( + opacity: !isScheduled ? 0.5 : 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FilterChip( + onSelected: (value) => setState(() { + selectedTimespan = Timespan.daily; + }), + label: Text('daily'.tr), + selected: + selectedTimespan == Timespan.daily, + showCheckmark: false), + FilterChip( + onSelected: (value) => setState(() { + selectedTimespan = Timespan.weekly; + }), + label: Text('weekly'.tr), + selected: + selectedTimespan == Timespan.weekly, + showCheckmark: false), + FilterChip( + onSelected: (value) => setState(() { + selectedTimespan = Timespan.monthly; + }), + label: Text('montly'.tr), + selected: + selectedTimespan == Timespan.monthly, + showCheckmark: false), + FilterChip( + onSelected: (value) => setState(() { + selectedTimespan = Timespan.yearly; + }), + label: Text('yearly'.tr), + selected: + selectedTimespan == Timespan.yearly, + showCheckmark: false) + ], + ), + ], + ), ), - ], - ), - ), - ) - ] - ) - ) - ), + ) + ]))), floatingActionButton: FloatingActionButton( onPressed: () async => { - if(await saveChanges()) Navigator.pop(context), + if (await saveChanges()) Navigator.pop(context), }, child: Icon(transExists ? Icons.save_rounded : Icons.check_rounded), ), @@ -241,45 +234,43 @@ class _EditTransactionViewState extends State<EditTransactionView> { } Future<bool> saveChanges() async { - if(_titleController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Title cannot be empty') - ) - ); + if (_titleController.text.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text('TCBE'.tr))); return false; } - if(_amountController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Amount cannot be empty') - ) - ); + if (_amountController.text.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text('ACBE'.tr))); return false; } - if(categoryId.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Category cannot be empty') - ) - ); + if (categoryId.isEmpty) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text('CCBE'.tr))); return false; } - if(transExists) { + if (transExists) { widget.transaction!.title = _titleController.text; - widget.transaction!.amount = isExpense ? -double.parse(_amountController.text) : double.parse(_amountController.text); + widget.transaction!.amount = isExpense + ? -double.parse(_amountController.text) + : double.parse(_amountController.text); widget.transaction!.categoryId = categoryId; - return await locator.get<TransactionsController>().updateTransaction(oldAmount, widget.transaction!); + return await locator + .get<TransactionsController>() + .updateTransaction(oldAmount, widget.transaction!); } else { Transaction newTransaction = Transaction( - title: _titleController.text, - amount: isExpense ? -double.parse(_amountController.text) : double.parse(_amountController.text), - categoryId: categoryId, - createdAt: DateTime.now(), - dueDate: dueDate - ); - return await locator.get<TransactionsController>().saveTransaction(newTransaction); + title: _titleController.text, + amount: isExpense + ? -double.parse(_amountController.text) + : double.parse(_amountController.text), + categoryId: categoryId, + createdAt: DateTime.now(), + dueDate: dueDate); + return await locator + .get<TransactionsController>() + .saveTransaction(newTransaction); } } } diff --git a/trackeroo/lib/frontend/views/home_view.dart b/trackeroo/lib/frontend/views/home_view.dart index 3503ed6..6cad488 100644 --- a/trackeroo/lib/frontend/views/home_view.dart +++ b/trackeroo/lib/frontend/views/home_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:get/get.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/frontend/utils/category_chip.dart'; import 'package:trackeroo/frontend/utils/transaction_listtile.dart'; @@ -30,161 +31,160 @@ class _HomeViewState extends State<HomeView> { child: Padding( padding: const EdgeInsets.all(16.0), child: ValueListenableBuilder( - valueListenable: transContr.transactionsBox.listenable(), - builder: (context, Box<Transaction> box, widget) { - transContr.transactionsList = box.values.toList(); - transContr.transactionsList.sort((b, a) => a.createdAt.compareTo(b.createdAt)); - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - const Text( - 'Balance', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold + valueListenable: transContr.transactionsBox.listenable(), + builder: (context, Box<Transaction> box, widget) { + transContr.transactionsList = box.values.toList(); + transContr.transactionsList + .sort((b, a) => a.createdAt.compareTo(b.createdAt)); + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + Text( + 'balance'.tr, + style: const TextStyle( + fontSize: 14.0, fontWeight: FontWeight.bold), ), - ), - const SizedBox(height: 5.0), - Text( - transContr.balance.toStringAsFixed(2), - style: const TextStyle( - fontSize: 40.0, - fontWeight: FontWeight.w300 + const SizedBox(height: 5.0), + Text( + transContr.balance.toStringAsFixed(2), + style: const TextStyle( + fontSize: 40.0, fontWeight: FontWeight.w300), ), - ), - const SizedBox(height: 10.0), - const Text( - 'Overview', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold + const SizedBox(height: 10.0), + Text( + 'overview'.tr, + style: const TextStyle( + fontSize: 14.0, fontWeight: FontWeight.bold), ), - ), - const SizedBox(height: 5.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Row( - children: [ - Icon(Icons.arrow_downward, color: Colors.green, size: 16.0), - Text('Income'), - ], - ), - Text('${transContr.income.toStringAsFixed(2)} €') - ], - ), - Center( - child: SizedBox( - height: 200.0, - width: 50.0, - child: PieChart( - PieChartData( - centerSpaceRadius: 30.0, - sections: transContr.transactionsList.isNotEmpty ? buildPieChartSectionList(context) : null, - pieTouchData: PieTouchData( - enabled: true - ) + const SizedBox(height: 5.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.arrow_downward, + color: Colors.green, size: 16.0), + Text('income'.tr), + ], ), - swapAnimationDuration: const Duration(milliseconds: 500), - swapAnimationCurve: Curves.easeInOut, - ), + Text('${transContr.income.toStringAsFixed(2)} €') + ], ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Row( - children: [ - Icon(Icons.arrow_upward, color: Colors.red, size: 16.0), - Text('Expenses'), - ], + Center( + child: SizedBox( + height: 200.0, + width: 50.0, + child: PieChart( + PieChartData( + centerSpaceRadius: 30.0, + sections: transContr.transactionsList.isNotEmpty + ? buildPieChartSectionList(context) + : null, + pieTouchData: PieTouchData(enabled: true)), + swapAnimationDuration: + const Duration(milliseconds: 500), + swapAnimationCurve: Curves.easeInOut, + ), ), - Text('${transContr.expenses.toStringAsFixed(2)} €') - ], - ), - ], - ), - const SizedBox(height: 20.0), - Wrap( - children: [ - for(Category cat in inChartShownCats) CategoryChip(category: cat) - ], - ), - const SizedBox(height: 10.0), - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // FilterChip( - // onSelected: (value) => setState(() { - // timespanView = Timespan.daily; - // }), - // label: const Text('Daily'), - // selected: timespanView == Timespan.daily, - // showCheckmark: false - // ), - // FilterChip( - // onSelected: (value) => setState(() { - // timespanView = Timespan.weekly; - // }), - // label: const Text('Weekly'), - // selected: timespanView == Timespan.weekly, - // showCheckmark: false - // ), - // FilterChip( - // onSelected: (value) => setState(() { - // timespanView = Timespan.monthly; - // }), - // label: const Text('Monthly'), - // selected: timespanView == Timespan.monthly, - // showCheckmark: false - // ), - // FilterChip( - // onSelected: (value) => setState(() { - // timespanView = Timespan.yearly; - // }), - // label: const Text('Yearly'), - // selected: timespanView == Timespan.yearly, - // showCheckmark: false - // ), - // FilterChip( - // onSelected: (value) => setState(() { - // timespanView = Timespan.all; - // }), - // label: const Text('All'), - // selected: timespanView == Timespan.all, - // showCheckmark: false - // ) - // ], - // ), - // const SizedBox(height: 20.0), - const Text( - 'Transactions', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.arrow_upward, + color: Colors.red, size: 16.0), + Text('expenses'.tr), + ], + ), + Text('${transContr.expenses.toStringAsFixed(2)} €') + ], + ), + ], ), - ), - const SizedBox(height: 5.0), - box.isEmpty ? const SizedBox( - height: 200.0, - child: Center( - child: Text('no existing transactions yet'), + const SizedBox(height: 20.0), + Wrap( + children: [ + for (Category cat in inChartShownCats) + CategoryChip(category: cat) + ], ), - ) : ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: transContr.transactionsList.length <= 25 ? transContr.transactionsList.length : 25, - itemBuilder: (context, index) => TransactionListtile(transaction: transContr.transactionsList[index]) - ), - const SizedBox(height: 65.0) - ], - ); - } - ), + const SizedBox(height: 10.0), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.daily; + // }), + // label: const Text('Daily'), + // selected: timespanView == Timespan.daily, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.weekly; + // }), + // label: const Text('Weekly'), + // selected: timespanView == Timespan.weekly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.monthly; + // }), + // label: const Text('Monthly'), + // selected: timespanView == Timespan.monthly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.yearly; + // }), + // label: const Text('Yearly'), + // selected: timespanView == Timespan.yearly, + // showCheckmark: false + // ), + // FilterChip( + // onSelected: (value) => setState(() { + // timespanView = Timespan.all; + // }), + // label: const Text('All'), + // selected: timespanView == Timespan.all, + // showCheckmark: false + // ) + // ], + // ), + // const SizedBox(height: 20.0), + Text( + 'transactions'.tr, + style: const TextStyle( + fontSize: 14.0, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 5.0), + box.isEmpty + ? SizedBox( + height: 200.0, + child: Center( + child: Text('NET'.tr), + ), + ) + : ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: transContr.transactionsList.length <= 25 + ? transContr.transactionsList.length + : 25, + itemBuilder: (context, index) => TransactionListtile( + transaction: transContr.transactionsList[index])), + const SizedBox(height: 65.0) + ], + ); + }), ), ); } @@ -193,106 +193,99 @@ class _HomeViewState extends State<HomeView> { List<PieChartSectionData> sectionList = []; inChartShownCats.clear(); - int elapsedDays = transContr.transactionsList.last.createdAt.difference(DateTime.now()).inDays; - if(elapsedDays <= 0) elapsedDays = 1; + int elapsedDays = transContr.transactionsList.last.createdAt + .difference(DateTime.now()) + .inDays; + if (elapsedDays <= 0) elapsedDays = 1; double other = 0; - for (Category cat in locator.get<CategoriesController>().categories.values) { + for (Category cat + in locator.get<CategoriesController>().categories.values) { double categorySum = 0; double avg = 0; - for(Transaction tr in transContr.transactionsList) { - if(tr.categoryId == cat.id) { + for (Transaction tr in transContr.transactionsList) { + if (tr.categoryId == cat.id) { categorySum += tr.amount; } } - if(timespanView == Timespan.daily) { + if (timespanView == Timespan.daily) { avg = categorySum / elapsedDays; - } else if(timespanView == Timespan.weekly) { + } else if (timespanView == Timespan.weekly) { avg = categorySum / (elapsedDays / 7); - } else if(timespanView == Timespan.monthly) { + } else if (timespanView == Timespan.monthly) { avg = categorySum / (elapsedDays / 30); - } else if(timespanView == Timespan.yearly) { + } else if (timespanView == Timespan.yearly) { avg = categorySum / (elapsedDays / 365); } else { avg = categorySum; } - bool meetsThreshold = (categorySum.abs() / transContr.balance.abs()) > 0.06; + bool meetsThreshold = + (categorySum.abs() / transContr.balance.abs()) > 0.06; - if(!meetsThreshold) { + if (!meetsThreshold) { other += avg; } - if(!avg.isNaN && meetsThreshold) { + if (!avg.isNaN && meetsThreshold) { inChartShownCats.add(cat); sectionList.add(PieChartSectionData( - value: double.parse(avg.toStringAsFixed(2)).abs(), - showTitle: false, - title: avg.toStringAsFixed(2), - color: Color(cat.colorValue), - radius: 70.0, - badgeWidget: Container( - height: 30.0, - width: 30.0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - shape: BoxShape.circle, - ), - child: Center( - child: Icon( - IconData( - cat.iconCodePoint, - fontFamily: cat.iconFontFamily, + value: double.parse(avg.toStringAsFixed(2)).abs(), + showTitle: false, + title: avg.toStringAsFixed(2), + color: Color(cat.colorValue), + radius: 70.0, + badgeWidget: Container( + height: 30.0, + width: 30.0, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + shape: BoxShape.circle, ), - color: Color(cat.colorValue), - size: 18.0, - ) - ) - ), - titlePositionPercentageOffset: .4, - titleStyle: TextStyle( - color: Theme.of(context).colorScheme.onSurface - ), - badgePositionPercentageOffset: 1 - )); + child: Center( + child: Icon( + IconData( + cat.iconCodePoint, + fontFamily: cat.iconFontFamily, + ), + color: Color(cat.colorValue), + size: 18.0, + ))), + titlePositionPercentageOffset: .4, + titleStyle: + TextStyle(color: Theme.of(context).colorScheme.onSurface), + badgePositionPercentageOffset: 1)); } } if (other.abs() > 0) { inChartShownCats.add(Category( - id: 'other', - title: 'Other', - iconCodePoint: Icons.category_rounded.codePoint, - colorValue: Colors.grey.value - )); + id: 'other', + title: 'Other', + iconCodePoint: Icons.category_rounded.codePoint, + colorValue: Colors.grey.value)); sectionList.add(PieChartSectionData( - value: double.parse(other.toStringAsFixed(2)).abs(), - showTitle: false, - title: other.toStringAsFixed(2), - color: Colors.grey, - radius: 70.0, - badgeWidget: Container( - height: 30.0, - width: 30.0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - shape: BoxShape.circle - ), - child: const Center( - child: Icon( - Icons.category_rounded, - color: Colors.grey, - size: 18.0, - ) - ) - ), - titlePositionPercentageOffset: .4, - titleStyle: TextStyle( - color: Theme.of(context).colorScheme.onSurface - ), - badgePositionPercentageOffset: 1 - )); + value: double.parse(other.toStringAsFixed(2)).abs(), + showTitle: false, + title: other.toStringAsFixed(2), + color: Colors.grey, + radius: 70.0, + badgeWidget: Container( + height: 30.0, + width: 30.0, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + shape: BoxShape.circle), + child: const Center( + child: Icon( + Icons.category_rounded, + color: Colors.grey, + size: 18.0, + ))), + titlePositionPercentageOffset: .4, + titleStyle: TextStyle(color: Theme.of(context).colorScheme.onSurface), + badgePositionPercentageOffset: 1)); } return sectionList; } diff --git a/trackeroo/lib/frontend/views/onboarding_view.dart b/trackeroo/lib/frontend/views/onboarding_view.dart index 629224e..f4b7ebd 100644 --- a/trackeroo/lib/frontend/views/onboarding_view.dart +++ b/trackeroo/lib/frontend/views/onboarding_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:trackeroo/app_scaffold.dart'; import 'package:trackeroo/frontend/utils/onboarding/ob_categories.dart'; import 'package:trackeroo/frontend/utils/onboarding/ob_details.dart'; @@ -17,7 +18,8 @@ class OnboardingView extends StatefulWidget { class _OnboardingViewState extends State<OnboardingView> { final controller = PageController(); - final AppStateController appStateController = locator.get<AppStateController>(); + final AppStateController appStateController = + locator.get<AppStateController>(); int pageIndex = 0; @@ -50,29 +52,26 @@ class _OnboardingViewState extends State<OnboardingView> { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - onPressed: () { - appStateController.appState.isFirstOpening = false; - appStateController.safeAppState(); - Navigator.of(context).popUntil((route) => route.isFirst); - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => const AppScaffold()) - ); - }, - padding: const EdgeInsets.symmetric(horizontal: 15.0), - icon: const Row( - children: [ - Icon(Icons.close_rounded), - SizedBox(width: 10.0), - Text( - 'skip', - style: TextStyle( - fontSize: 16.0 + onPressed: () { + appStateController.appState.isFirstOpening = false; + appStateController.safeAppState(); + Navigator.of(context).popUntil((route) => route.isFirst); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const AppScaffold())); + }, + padding: const EdgeInsets.symmetric(horizontal: 15.0), + icon: Row( + children: [ + const Icon(Icons.close_rounded), + const SizedBox(width: 10.0), + Text( + 'skip'.tr, + style: const TextStyle(fontSize: 16.0), ), - ), - ], - ) - ), + ], + )), Row( children: [ buildPageIndicator(0), @@ -83,33 +82,34 @@ class _OnboardingViewState extends State<OnboardingView> { ], ), IconButton( - onPressed: () { - if(pageIndex == 4) { - appStateController.appState.isFirstOpening = false; - appStateController.safeAppState(); - Navigator.of(context).popUntil((route) => route.isFirst); - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => const AppScaffold()) - ); - } else { - controller.nextPage(duration: const Duration(milliseconds: 300), curve: Curves.easeInOut); - } - }, - padding: const EdgeInsets.symmetric(horizontal: 15.0), - icon: Row( - children: [ - Text( - pageIndex != 4 ? 'next' : 'done', - style: const TextStyle( - fontSize: 16.0 + onPressed: () { + if (pageIndex == 4) { + appStateController.appState.isFirstOpening = false; + appStateController.safeAppState(); + Navigator.of(context).popUntil((route) => route.isFirst); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const AppScaffold())); + } else { + controller.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut); + } + }, + padding: const EdgeInsets.symmetric(horizontal: 15.0), + icon: Row( + children: [ + Text( + pageIndex != 4 ? 'next'.tr : 'done'.tr, + style: const TextStyle(fontSize: 16.0), ), - ), - const SizedBox(width: 10.0), - Icon(pageIndex != 4 ? Icons.arrow_forward_rounded : Icons.done_rounded), - ], - ) - ), + const SizedBox(width: 10.0), + Icon(pageIndex != 4 + ? Icons.arrow_forward_rounded + : Icons.done_rounded), + ], + )), ], ), ), @@ -117,15 +117,16 @@ class _OnboardingViewState extends State<OnboardingView> { } Widget buildPageIndicator(int index) => GestureDetector( - onTap: () => controller.jumpToPage(index), - child: Container( - height: 10.0, - width: 10.0, - margin: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: pageIndex == index ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.primaryContainer - ), - ), - ); + onTap: () => controller.jumpToPage(index), + child: Container( + height: 10.0, + width: 10.0, + margin: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: pageIndex == index + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.primaryContainer), + ), + ); } diff --git a/trackeroo/lib/frontend/views/settings_views.dart b/trackeroo/lib/frontend/views/settings_views.dart index bb849e6..9575ef4 100644 --- a/trackeroo/lib/frontend/views/settings_views.dart +++ b/trackeroo/lib/frontend/views/settings_views.dart @@ -83,51 +83,81 @@ class _SettingsView extends State<SettingsView> { crossAxisAlignment: CrossAxisAlignment.center, children: [ CircleAvatar( - radius: 55, - backgroundColor: Colors.grey, + radius: 79, + backgroundColor: Colors.blue.shade100, child: profileController.profile.imagePath.isNotEmpty ? CircleAvatar( - radius: 53, + radius: 76, backgroundImage: FileImage(File(getImage( profileController.profile.imagePath))), ) : const Icon(Icons.person), ), - const SizedBox(height: 16), - Text( - 'name'.tr, - style: const TextStyle( - fontSize: 16, fontWeight: FontWeight.bold), + const SizedBox(height: 18), + Container( + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(10.0), + ), + child: InputDecorator( + decoration: InputDecoration( + contentPadding: + const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'name'.tr, + prefixIcon: const Icon(Icons.phone_android), + border: InputBorder.none, + ), + child: Text( + locator.get<ProfileController>().profile.name, + style: const TextStyle(fontSize: 18), + ), + ), ), - Text( - locator.get<ProfileController>().profile.name, - style: const TextStyle(fontSize: 16), + const SizedBox(height: 18), + Container( + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(10.0), + ), + child: InputDecorator( + decoration: InputDecoration( + contentPadding: + const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'Number'.tr, + prefixIcon: const Icon(Icons.phone_android), + border: InputBorder.none, + ), + child: Text( + locator + .get<ProfileController>() + .profile + .number + .toString(), + style: const TextStyle(fontSize: 18), + ), + ), ), - const SizedBox(height: 16), - Text( - 'Number'.tr, - style: const TextStyle( - fontSize: 16, fontWeight: FontWeight.bold), + const SizedBox(height: 18), + Container( + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(10.0), + ), + child: InputDecorator( + decoration: InputDecoration( + contentPadding: + const EdgeInsets.only(left: 10.0, bottom: 7.0), + labelText: 'email'.tr, + prefixIcon: const Icon(Icons.phone_android), + border: InputBorder.none, + ), + child: Text( + locator.get<ProfileController>().profile.email, + style: const TextStyle(fontSize: 18), + ), + ), ), - Text( - locator - .get<ProfileController>() - .profile - .number - .toString(), - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 16), - Text( - 'email'.tr, - style: const TextStyle( - fontSize: 16, fontWeight: FontWeight.bold), - ), - Text( - locator.get<ProfileController>().profile.email, - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 16), + const SizedBox(height: 18), ElevatedButton( onPressed: () { Navigator.push( @@ -136,13 +166,23 @@ class _SettingsView extends State<SettingsView> { builder: (context) => const EditSettingsView()), ); }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all<Color>( + Colors.grey.shade300), + ), child: Text('EP'.tr), ), - Text('hello'.tr), + const SizedBox( + height: 18, + ), ElevatedButton( onPressed: () { biulddialog(context); }, + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all<Color>( + Colors.grey.shade300), + ), child: Text('Lang'.tr), ) ], diff --git a/trackeroo/lib/logic/models/local_String.dart b/trackeroo/lib/logic/models/local_String.dart index 76db96d..e4c6d73 100644 --- a/trackeroo/lib/logic/models/local_String.dart +++ b/trackeroo/lib/logic/models/local_String.dart @@ -12,11 +12,56 @@ class LocalString extends Translations { 'Gallery': 'Gallery', 'EP': 'Edit Profile', 'name': 'Name', - 'Number': 'Mobile number', + 'Number': 'Mobile Phone number', 'email': 'E-Mail', 'Save': 'Save', 'Lang': 'Select a language', 'Profile': 'Profile', + 'enterNu': 'Enter your Mobile Phone Number', + 'enterNa': 'Enter your Name', + 'enterE': 'Enter your E-Mail', + 'skip': 'skip', + 'next': 'next', + 'done': 'done', + 'balance': 'Balance', + 'overview': 'Overview', + 'income': 'Income', + 'expenses': 'Expenses', + 'transactions': 'Transactions', + 'Transaction deleted': 'Transaction deleted', + 'NET': 'no existing transactions yet', + 'ET': 'Edit Transaction', + 'CT': 'Create Transaction', + 'amount': 'Amount', + 'category': 'Category', + 'SP': 'Scheduled payment', + 'daily': 'Daily', + 'weekly': 'Weekly', + 'montly': 'Montly', + 'yearly': 'Yearly', + 'TCBE': 'Title cannot be empty', + 'ACBE': 'Amount cannot be empty', + 'CCBE': 'Category cannot be empty', + 'CC': 'Choose color', + 'EC': 'edit Category', + 'DC': 'Delete Category', + 'mes': + 'Do you really want to delete this category?\nIt will be lost forever.', + 'Cancel': 'Cancel', + 'Delete': 'Delete', + 'Choose icon': 'Choose icon', + 'Category Name': 'Category Name', + 'Color': 'Color', + 'Budget': 'Budget', + 'set Budget': 'set Budget', + 'Datails chart': 'Datails chart', + 'Choose categories': 'Choose categories', + 'Choose timespan': 'Choose timespan', + 'Timespan': 'Timespan', + 'Categories': 'Categories', + 'add Category': 'add Category', + 'add Transaction': 'add Transaction', + 'Undo': 'Undo', }, 'de_DE': { 'hello': 'SERVUS', @@ -32,6 +77,51 @@ class LocalString extends Translations { 'Save': 'Speichern', 'Lang': 'Sprache einstellen', 'Profile': 'Profil', + 'enterNu': 'Geben Sie Ihre Handynummer ein', + 'enterNa': 'Geben Sie Ihren Namen ein', + 'enterE': 'Geben Sie Ihre E-Mail ein', + 'skip': 'überspringen', + 'next': 'Weiter', + 'done': 'Fertig', + 'balance': 'Kontostand', + 'overview': 'Übersicht', + 'income': 'Einkommen', + 'expenses': 'Ausgaben', + 'transactions': 'Transaktionen', + 'Transaction deleted': 'Transaktion Löschen', + 'NET': 'Keine Transaktionen Vorhanden', + 'ET': 'Transaktion Bearbeiten', + 'CT': 'Transaktion erstellen', + 'amount': 'Betrag', + 'category': 'Kategorie', + 'SP': 'Geplante Zahlung ', + 'daily': 'Täglich', + 'weekly': 'Wöchentlich', + 'montly': 'Monatlich', + 'yearly': 'Jährlich', + 'TCBE': 'Titel darf nicht leer sein', + 'ACBE': 'Betrag darf nicht leer sein', + 'CCBE': 'Kategorie darf nicht leer sein', + 'CC': 'Wähle die Farbe aus', + 'EC': 'Kategorie Bearbeiten', + 'DC': 'Kategorie Löschen', + 'mes': + 'Willst du diese Kategorie wirklich löschen?\nDadurch wird Sie für immer Verloren.', + 'Cancel': 'Abbrechen', + 'Delete': 'Löschen', + 'Choose icon': 'Wähle ein Icon aus', + 'Category Name': 'Kategorie Name', + 'Color': 'Farbe', + 'Budget': 'Budget', + 'set Budget': 'Budget Festlegen', + 'Datails chart': 'Datenübersicht', + 'Choose categories': 'Wähle die Kategorie aus', + 'Choose timespan': 'Zeitspanne wählen', + 'Timespan': 'Zeitspanne', + 'Categories': 'Kategorien', + 'add Category': 'Kategrie Hinzufügen', + 'add Transaction': 'Transaktion Hinzufügen', + 'Undo': 'Rückgängig', } }; } -- GitLab