diff --git a/trackeroo/lib/app_scaffold.dart b/trackeroo/lib/app_scaffold.dart index c7010969fb360ffbcc881a97dd678081676d6b91..fe248eab7fb964a2cbacb42cf5e52fd97eb951ac 100644 --- a/trackeroo/lib/app_scaffold.dart +++ b/trackeroo/lib/app_scaffold.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.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'; import 'package:trackeroo/frontend/views/details_view.dart'; -import 'package:trackeroo/frontend/views/category_view.dart'; +import 'package:trackeroo/frontend/views/categories_view.dart'; +import 'package:trackeroo/logic/services/locator.dart'; +import 'package:trackeroo/logic/services/transactions_controller.dart'; class AppScaffold extends StatefulWidget { const AppScaffold({Key? key}) : super(key: key); @@ -17,7 +20,7 @@ class _AppScaffoldState extends State<AppScaffold> { final screens = [ const HomeView(), const DetailsView(), - const CategoryView(), + const CategoriesView(), ]; @override @@ -76,20 +79,25 @@ class _AppScaffoldState extends State<AppScaffold> { ], ), ), - floatingActionButton: FloatingActionButton( - onPressed: () { - if(index == 0 || index == 1) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => const EditTransactionView()) - ); - } - if(index == 2) { - // add category - } - }, + 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') + ], + ) ), ); } + void fabOnPressed() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => index == 2 ? const EditCategoryView() : const EditTransactionView()) + ); + } } diff --git a/trackeroo/lib/frontend/utils/category_listtile.dart b/trackeroo/lib/frontend/utils/category_listtile.dart index 9ffeec0c8ee18a96df4d57d6865478b0a73bc78d..5f13920c1cd238e7a89680f0d3eba66856dba7c7 100644 --- a/trackeroo/lib/frontend/utils/category_listtile.dart +++ b/trackeroo/lib/frontend/utils/category_listtile.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/frontend/views/edit_category_view.dart'; +import 'package:trackeroo/logic/models/category.dart'; class CategoryListtile extends StatelessWidget { const CategoryListtile({Key? key, required this.category}) : super(key: key); @@ -10,84 +10,66 @@ class CategoryListtile extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - margin: const EdgeInsets.symmetric(vertical: 8.0), - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 11.0), + margin: const EdgeInsets.only(bottom: 5.0), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 5, - offset: const Offset(0, 3), // Ändert die Position des Schattens - ), - ], + border: Border.all(), + borderRadius: BorderRadius.circular(12.0), ), child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Container( - width: 50.0, - height: 50.0, - decoration: BoxDecoration( - color: Color(category.colorValue), - borderRadius: BorderRadius.circular(8.0), - ), - child: Icon( - IconData( - category.iconCodePoint, - fontFamily: category.iconFontFamily, + Row( + children: [ + Container( + width: 50.0, + height: 50.0, + decoration: BoxDecoration( + color: Color(category.colorValue), + borderRadius: BorderRadius.circular(8.0), + ), + child: Icon( + IconData( + category.iconCodePoint, + fontFamily: category.iconFontFamily, + ), + color: Colors.white, + size: 30.0, + ), ), - color: Colors.white, - size: 30.0, - ), - ), - const SizedBox(width: 8.0), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( + const SizedBox(width: 15.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( category.title, style: const TextStyle( - fontSize: 16.0, + fontSize: 18.0, fontWeight: FontWeight.bold, ), ), - ), - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => EditCategoryPage(category: category), - ), - ); - }, - ), - ], - ), - Text( - 'Budget: ${category.budget}', - style: const TextStyle( - fontSize: 17.0, - color: Color.fromARGB(255, 81, 78, 78), - ), - ), - const SizedBox(height: 22.0), - Container( - height: 6.0, - decoration: BoxDecoration( - color: Color(category.colorValue), - borderRadius: BorderRadius.circular(8.0), + ], ), + !category.budget.isNegative ? Text( + 'Budget: ${category.budget}', + ) : const SizedBox(), + ], + ), + ], + ), + IconButton( + padding: const EdgeInsets.all(0), + icon: const Icon(Icons.edit, size: 14.0), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EditCategoryView(category: category), ), - ], - ), + ); + }, ), ], ), diff --git a/trackeroo/lib/frontend/utils/transaction_listtile.dart b/trackeroo/lib/frontend/utils/transaction_listtile.dart index 2c23f187f13d325162af04ad33fb0c11c075e0f6..4e5ba2ea98c3c77acbd1b89e189caffde8a4badd 100644 --- a/trackeroo/lib/frontend/utils/transaction_listtile.dart +++ b/trackeroo/lib/frontend/utils/transaction_listtile.dart @@ -70,7 +70,7 @@ class _TransactionListtileState extends State<TransactionListtile> { }, ), child: Container( - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 12.0), + padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 11.0), color: Theme.of(context).colorScheme.secondaryContainer, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/trackeroo/lib/frontend/views/categories_view.dart b/trackeroo/lib/frontend/views/categories_view.dart new file mode 100644 index 0000000000000000000000000000000000000000..f89252671c0c9427bd8cc307be5ca941ae3981fb --- /dev/null +++ b/trackeroo/lib/frontend/views/categories_view.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:trackeroo/frontend/utils/category_listtile.dart'; +import 'package:trackeroo/logic/models/category.dart'; +import 'package:trackeroo/logic/services/categories_controller.dart'; +import 'package:trackeroo/logic/services/locator.dart'; + +class CategoriesView extends StatelessWidget { + const CategoriesView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: <Widget>[ + const Text( + 'Categories', + style: 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)), + ); + } + ), + const SizedBox(height: 65.0) + ], + ), + ), + ); + } +} diff --git a/trackeroo/lib/frontend/views/category_view.dart b/trackeroo/lib/frontend/views/category_view.dart deleted file mode 100644 index 8361e8829e72216bd8390a3c0938824929c50055..0000000000000000000000000000000000000000 --- a/trackeroo/lib/frontend/views/category_view.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:trackeroo/frontend/utils/category_listtile.dart'; -import 'package:trackeroo/logic/services/categories_controller.dart'; -import 'package:trackeroo/logic/services/locator.dart'; - -class CategoryView extends StatelessWidget { - const CategoryView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: <Widget>[ - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: locator.get<CategoriesController>().categories.length, - itemBuilder: (context, index) => CategoryListtile(category: locator.get<CategoriesController>().categories.values.elementAt(index)), - ) - ], - ), - ), - ); - } -} diff --git a/trackeroo/lib/frontend/views/details_view.dart b/trackeroo/lib/frontend/views/details_view.dart index 9bfdd7e041d81e0914b32533ccca3624e21f08e6..1ad2adcbaa702dd1b57b1c93b5269db6161ce808 100644 --- a/trackeroo/lib/frontend/views/details_view.dart +++ b/trackeroo/lib/frontend/views/details_view.dart @@ -8,8 +8,6 @@ import 'package:trackeroo/logic/services/categories_controller.dart'; import 'package:trackeroo/logic/services/locator.dart'; import 'package:trackeroo/logic/services/transactions_controller.dart'; -enum Timespan { daily, weekly, monthly, yearly, all } - class DetailsView extends StatefulWidget { const DetailsView({super.key}); @@ -19,244 +17,261 @@ class DetailsView extends StatefulWidget { class _DetailsViewState extends State<DetailsView> { - Timespan timespanView = Timespan.monthly; TransactionsController transactionsController = locator.get<TransactionsController>(); + DateTimeRange timespan = DateTimeRange(start: DateTime.now(), end: DateTime.now()); List<String> selectedCategories = []; + @override + void initState() { + if (transactionsController.transactionsList.isNotEmpty) { + timespan = DateTimeRange( + start: transactionsController.transactionsList.last.createdAt, + end: transactionsController.transactionsList.first.createdAt + ); + } + super.initState(); + } + @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - const Row( - children: [ - Text( + child: ValueListenableBuilder( + valueListenable: locator.get<TransactionsController>().transactionsBox.listenable(), + builder: (context, Box<Transaction> box, child) { + List<Transaction> filteredTransList = box.values.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, - reservedSize: 30, - interval: 1, + 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 + ) + ) ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - interval: 50, - reservedSize: 42, + gridData: FlGridData( + show: true, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Theme.of(context).colorScheme.onSurface, + strokeWidth: 0.5 + ); + }, + drawVerticalLine: false, ), - ), - ), - maxX: 12, - maxY: 200, - minY: 0, - minX: 0, - lineBarsData: [ - LineChartBarData( - spots: [ - const FlSpot(0, 0), - const FlSpot(5, 5), - const FlSpot(7, 6), - const FlSpot(8, 4), - ], - isCurved: false, - color: Colors.red, - barWidth: 3, - isStrokeCapRound: true, - dotData: FlDotData(show: false) - ) - ] - ) - ) - ) - ), - 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 - ), + titlesData: FlTitlesData( + show: true, + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false) + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 30, + interval: 1, ), - 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: selectedCategories.contains(category.id), - contentPadding: const EdgeInsets.all(0.0), - dense: true, - onChanged: (value) => setState(() { - if(selectedCategories.contains(category.id)) { - selectedCategories.remove(category.id); - } else { - selectedCategories.add(category.id); - } - }) + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + // interval: 50, + reservedSize: 42, ), - ] + ), ), - ), + maxX: 12, + // maxY: 200, + minY: 0, + minX: 0, + lineBarsData: buildBarData() + ) ) - ), - icon: const Row( - 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: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.first.createdAt : DateTime.now(), - lastDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.last.createdAt : DateTime.now(), - helpText: 'Choose timespan', - saveText: 'Done' - ), - }, - // onPressed: () => showModalBottomSheet( - // useSafeArea: true, - // showDragHandle: true, - // context: context, - // builder: (context) => Container( - // width: double.infinity, - // padding: const EdgeInsets.symmetric(horizontal: 20.0), - // child: const Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // 'Choose categories', - // style: TextStyle( - // fontSize: 16.0, - // fontWeight: FontWeight.bold - // ), - // ) - // ], - // ), - // ), - // ), - icon: const Row( - children: [ - Icon( - Icons.date_range_rounded, - size: 14.0, + 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 + ), + ), + 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: selectedCategories.contains(category.id), + contentPadding: const EdgeInsets.all(0.0), + dense: true, + onChanged: (value) => setState(() { + if(selectedCategories.contains(category.id)) { + selectedCategories.remove(category.id); + } else { + selectedCategories.add(category.id); + } + }) + ), + ] + ), + ), + ) ), - SizedBox(width: 5.0), - Text('Timespan') - ], - ) + icon: const Row( + 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: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.first.createdAt : DateTime.now(), + lastDate: transactionsController.transactionsList.isNotEmpty ? transactionsController.transactionsList.last.createdAt : DateTime.now(), + helpText: 'Choose timespan', + saveText: 'Done' + ), + }, + // onPressed: () => showModalBottomSheet( + // useSafeArea: true, + // showDragHandle: true, + // context: context, + // builder: (context) => Container( + // width: double.infinity, + // padding: const EdgeInsets.symmetric(horizontal: 20.0), + // child: const Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text( + // 'Choose categories', + // style: TextStyle( + // fontSize: 16.0, + // fontWeight: FontWeight.bold + // ), + // ) + // ], + // ), + // ), + // ), + icon: const Row( + children: [ + Icon( + Icons.date_range_rounded, + size: 14.0, + ), + SizedBox(width: 5.0), + Text('Timespan') + ], + ) + ), + ], ), - ], - ), - const SizedBox(height: 10.0), - const Text( - 'Transactions', - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold - ), - ), - const SizedBox(height: 5.0), - ValueListenableBuilder( - valueListenable: locator.get<TransactionsController>().transactionsBox.listenable(), - builder: (context, Box<Transaction> box, child) { - List<Transaction> filteredTransList = box.values.toList(); - filteredTransList.sort((b, a) => a.createdAt.compareTo(b.createdAt)); - return ListView.builder( + 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) + ] + ); + } ), ); } + + List<LineChartBarData> buildBarData() { + List<LineChartBarData> categoryBars = []; + for (Category category in locator.get<CategoriesController>().categories.values) { + List<FlSpot> categoryDataPoints = [const FlSpot(0.0, 0.0)]; + for(Transaction transaction in transactionsController.transactionsList) { + if(transaction.categoryId == category.id) { + categoryDataPoints.add(FlSpot(transaction.createdAt.day.toDouble(), transaction.amount.abs())); + } + } + categoryBars.add( + LineChartBarData( + spots: categoryDataPoints, + isCurved: false, + color: Color(category.colorValue), + barWidth: 3, + isStrokeCapRound: true, + dotData: FlDotData(show: false) + ) + ); + } + return categoryBars; + } } diff --git a/trackeroo/lib/frontend/views/edit_category_view.dart b/trackeroo/lib/frontend/views/edit_category_view.dart index a15e500e8773e56963780a14e51c87efe4714041..e1550f14ba6956d33a88df2afb16d2a523bfb969 100644 --- a/trackeroo/lib/frontend/views/edit_category_view.dart +++ b/trackeroo/lib/frontend/views/edit_category_view.dart @@ -1,66 +1,64 @@ import 'package:flutter/material.dart'; -import 'package:flutter_colorpicker/flutter_colorpicker.dart'; +import 'package:trackeroo/logic/constants/selecable_colors.dart'; +import 'package:trackeroo/logic/constants/selectable_icons.dart'; import 'package:trackeroo/logic/models/category.dart'; -import 'package:hive/hive.dart'; +import 'package:trackeroo/logic/models/selecable_color.dart'; +import 'package:trackeroo/logic/services/categories_controller.dart'; +import 'package:trackeroo/logic/services/locator.dart'; -class EditCategoryPage extends StatefulWidget { - final Category category; +class EditCategoryView extends StatefulWidget { + const EditCategoryView({Key? key, this.category}) : super(key: key); - const EditCategoryPage({Key? key, required this.category}) : super(key: key); + final Category? category; @override - _EditCategoryPageState createState() => _EditCategoryPageState(); + State<EditCategoryView> createState() => _EditCategoryViewState(); } -class _EditCategoryPageState extends State<EditCategoryPage> { - TextEditingController _nameController = TextEditingController(); - Color _selectedColor = Colors.red; - IconData _selectedIcon = Icons.star; - double _budget = 0; - bool _showIconPicker = false; +class _EditCategoryViewState extends State<EditCategoryView> { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _budgetController = TextEditingController(); + Color _selectedColor = selectableColors['Ocean']!.color; + IconData _selectedIcon = selectableIcons.first; + double _budget = -1; + bool _hasBudget = false; @override void initState() { super.initState(); - _nameController.text = widget.category.title; - _selectedColor = Color(widget.category.colorValue); - _selectedIcon = _getValidIconData(widget.category.iconCodePoint); - _budget = widget.category.budget ?? 0; - } - - IconData _getValidIconData(int codePoint) { - if (codePoint == Icons.star.codePoint) { - return Icons.star; - } else if (codePoint == Icons.favorite.codePoint) { - return Icons.favorite; - } else { - return Icons.star; + if (widget.category != null) { + _nameController.text = widget.category!.title; + _selectedColor = Color(widget.category!.colorValue); + _selectedIcon = IconData(widget.category!.iconCodePoint, fontFamily: widget.category!.iconFontFamily); + _hasBudget = !widget.category!.budget.isNegative; + if(_hasBudget) { + _budget = widget.category!.budget; + _budgetController.text = widget.category!.budget.toString(); + } } } @override void dispose() { _nameController.dispose(); + _budgetController.dispose(); super.dispose(); } - void _updateCategoryName() async { - String newName = _nameController.text; - Category updatedCategory = Category( - id: widget.category.id, - title: newName, - iconCodePoint: _selectedIcon.codePoint, - iconFontFamily: 'MaterialIcons', - colorValue: _selectedColor.value, - spendings: widget.category.spendings, - budget: _budget, + Widget _buildIconContainer(IconData iconData, double size) { + return Container( + width: size, + height: size, + decoration: BoxDecoration( + color: _selectedColor, + shape: BoxShape.circle, + ), + child: Icon( + iconData, + color: Theme.of(context).colorScheme.background, + size: size * 0.6, + ), ); - - final categoryBox = await Hive.openBox<Category>('categories'); - categoryBox.put(widget.category.id, updatedCategory); - categoryBox.close(); - - Navigator.pop(context); } void _showColorPicker() { @@ -68,281 +66,279 @@ class _EditCategoryPageState extends State<EditCategoryPage> { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('Farbe auswählen'), - content: SingleChildScrollView( - child: ColorPicker( - pickerColor: _selectedColor, - onColorChanged: (color) { - setState(() { - _selectedColor = color; - }); - }, - showLabel: true, - pickerAreaHeightPercent: 0.8, - ), + insetPadding: const EdgeInsets.symmetric(vertical: 100.0, horizontal: 20.0), + scrollable: true, + title: const Text('Choose color'), + 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 + ), + ), + title: Text(selecableColor.title), + trailing: _selectedColor == selectableColors[selecableColor.title]?.color ? const Icon(Icons.check_rounded) : null, + ), + ), + ) + ], ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Abbrechen'), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('OK'), - ), - ], ); }, ); } - void _onIconChanged(IconData? newIcon) { - if (newIcon != null) { - setState(() { - _selectedIcon = newIcon; - }); + void _createCategory() { + if(_nameController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Title cannot be empty')) + ); + return; } + Category newCategory = Category( + id: _nameController.text.replaceAll(' ', '_').toLowerCase(), + title: _nameController.text, + iconCodePoint: _selectedIcon.codePoint, + colorValue: _selectedColor.value + ); + locator.get<CategoriesController>().saveCategory(newCategory); + Navigator.of(context).pop(); } - Widget _buildIconContainer(IconData iconData, double size) { - return Container( - width: size, - height: size, - decoration: BoxDecoration( - color: _selectedColor, - shape: BoxShape.circle, - ), - child: Icon( - iconData, - color: Colors.white, - size: size * 0.6, - ), + void _updateCategory() { + Category updatedCategory = Category( + id: widget.category!.id, + title: _nameController.text, + iconCodePoint: _selectedIcon.codePoint, + iconFontFamily: 'MaterialIcons', + colorValue: _selectedColor.value, + spendings: widget.category!.spendings, + budget: _budget, ); - } - void _deleteCategory() async { - final categoryBox = await Hive.openBox<Category>('categories'); - categoryBox.delete(widget.category.id); - categoryBox.close(); + locator.get<CategoriesController>().updateCategory(updatedCategory); Navigator.pop(context); } + void _deleteCategory() { + locator.get<CategoriesController>().deleteCategory(widget.category!.id); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Kategorie bearbeiten'), + title: const Text('edit Category'), + 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(); + }, + 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) + ) + ], ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Kategorie bearbeiten', - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 16.0), - Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _showIconPicker = !_showIconPicker; - }); - }, - child: _buildIconContainer(_selectedIcon, 48.0), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Icon', + style: TextStyle( + fontWeight: FontWeight.bold ), - const SizedBox(width: 16.0), - Expanded( - child: TextField( - controller: _nameController, - decoration: const InputDecoration( - labelText: 'Name', + ), + const SizedBox(height: 70.0), + Center( + child: GestureDetector( + 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), + ), + ) + ], + ), + ) ), ), + child: _buildIconContainer(_selectedIcon, 100.0), ), - ], - ), - if (_showIconPicker) - Expanded( - child: GridView.count( - shrinkWrap: true, - crossAxisCount: 6, - childAspectRatio: 1.0, - children: [ - Icons.star, - Icons.favorite, - Icons.attach_money, - Icons.shopping_cart, - Icons.home, - Icons.work, - Icons.school, - Icons.pets, - Icons.luggage, - Icons.savings, - Icons.liquor, - Icons.celebration, - ].map((iconData) { - return GestureDetector( - onTap: () { - setState(() { - _onIconChanged(iconData); - _showIconPicker = false; - }); - }, - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: _selectedIcon == iconData - ? Colors.blue - : Colors.transparent, - width: 2.0, - ), - ), - child: _buildIconContainer(iconData, 32.0), - ), - ); - }).toList(), + ), + const SizedBox(height: 70.0), + const Text( + 'Name', + style: TextStyle( + fontWeight: FontWeight.bold ), ), - const SizedBox(height: 16.0), - Row( - children: [ - const Text( - 'Budget', - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - ), + TextField( + controller: _nameController, + decoration: const InputDecoration( + isDense: true, + hintText: 'Category Name', + hintStyle: TextStyle( + fontWeight: FontWeight.normal + ) ), - const SizedBox(width: 16.0), - GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (BuildContext context) { - TextEditingController _budgetController = - TextEditingController(text: _budget.toString()); - - return AlertDialog( - title: const Text('Budget ändern'), - content: TextField( - controller: _budgetController, - keyboardType: const TextInputType.numberWithOptions( - decimal: true, - ), - decoration: const InputDecoration( - labelText: 'Neues Budget', - ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Abbrechen'), - ), - TextButton( - onPressed: () { - double newBudget = double.tryParse( - _budgetController.text) ?? - 0; - setState(() { - _budget = newBudget; - }); - Navigator.of(context).pop(); - }, - child: const Text('OK'), - ), - ], - ); - }, - ); - }, - child: Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.black12, - width: 1.0, + ), + const SizedBox(height: 30.0), + const Text( + 'Color', + style: TextStyle( + fontWeight: FontWeight.bold + ), + ), + GestureDetector( + onTap: _showColorPicker, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 10.0), + // color is needed because of the container NOT beeing width double.infinity + // when no color is specified + color: Theme.of(context).colorScheme.background, + child: Row( + children: [ + Container( + height: 20.0, + width: 20.0, + decoration: BoxDecoration( + color: _selectedColor, + shape: BoxShape.circle + ), ), - ), - child: Text( - '${_budget.toStringAsFixed(2)} €', - style: const TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, + 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' ), - ), + ], ), ), - ], - ), - const SizedBox(height: 16.0), - GestureDetector( - onTap: _showColorPicker, - child: Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: _selectedColor, - borderRadius: BorderRadius.circular(8.0), + ), + const SizedBox(height: 20.0), + const Text( + 'Budget', + style: TextStyle( + fontWeight: FontWeight.bold ), - child: const Text( - 'Farbe auswählen', + ), + CheckboxListTile( + title: const Text( + 'set Budget', style: TextStyle( - color: Colors.black, - fontSize: 19.0, - fontWeight: FontWeight.bold, + fontSize: 16.0 ), ), + contentPadding: const EdgeInsets.all(0.0), + dense: true, + value: _hasBudget, + onChanged: (value) => setState(() { + _hasBudget = !_hasBudget; + }) ), - ), - const SizedBox(height: 16.0), - ElevatedButton( - onPressed: _updateCategoryName, - child: const Text('Speichern'), - ), - const SizedBox(height: 16.0), - ElevatedButton( - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Kategorie löschen'), - content: const Text('Möchten Sie diese Kategorie wirklich löschen?'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Abbrechen'), - ), - TextButton( - onPressed: () { - _deleteCategory(); - }, - child: const Text('Löschen'), + AbsorbPointer( + absorbing: !_hasBudget, + child: Opacity( + opacity: !_hasBudget ? 0.5 : 1.0, + child: Row( + children: [ + const Icon(Icons.savings_outlined, size: 18.0), + const SizedBox(width: 10.0), + Expanded( + child: TextField( + controller: _budgetController, + decoration: const InputDecoration( + hintText: 'Budget', + hintStyle: TextStyle( + fontWeight: FontWeight.normal + ), + isDense: true, + border: InputBorder.none + ), + keyboardType: TextInputType.number, ), - ], - ); - }, - ); - }, - child: const Text('Löschen'), - ), - ], + ), + const Text('€') + ], + ), + ), + ) + ], + ), ), ), + floatingActionButton: FloatingActionButton( + onPressed:() => widget.category != null ? _updateCategory() : _createCategory(), + child: const Icon(Icons.save_rounded), + ), ); } } diff --git a/trackeroo/lib/frontend/views/edit_transaction_view.dart b/trackeroo/lib/frontend/views/edit_transaction_view.dart index 20fc6cd922c600d5e5f68f64b29380ee0844dcfe..f92a07ad3f8cf05e5a3fe6c02f817d49ae1712ae 100644 --- a/trackeroo/lib/frontend/views/edit_transaction_view.dart +++ b/trackeroo/lib/frontend/views/edit_transaction_view.dart @@ -114,7 +114,7 @@ class _EditTransactionViewState extends State<EditTransactionView> { SizedBox( width: double.infinity, child: DropdownButton( - hint: const Text('Kategorie'), + hint: const Text('Category'), isExpanded: true, borderRadius: const BorderRadius.all(Radius.circular(10.0)), underline: const SizedBox(), @@ -127,7 +127,7 @@ class _EditTransactionViewState extends State<EditTransactionView> { DropdownMenuItem( value: '', child: Text( - 'Kategorie', + 'Category', style: TextStyle( color: Theme.of(context).colorScheme.onSurface.withAlpha(150) ) @@ -228,8 +228,7 @@ class _EditTransactionViewState extends State<EditTransactionView> { ], ), ), - ), - Text(categoryId) + ) ] ) ) diff --git a/trackeroo/lib/frontend/views/home_view.dart b/trackeroo/lib/frontend/views/home_view.dart index a9fe58b3c1c387cda8a357be2d5e235f95c0cb6d..3c90e71bcbe2c7d8761b2fcba76d2321c763c3cf 100644 --- a/trackeroo/lib/frontend/views/home_view.dart +++ b/trackeroo/lib/frontend/views/home_view.dart @@ -3,7 +3,7 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/frontend/utils/onboarding/category_chip.dart'; import 'package:trackeroo/frontend/utils/transaction_listtile.dart'; -import 'package:trackeroo/frontend/views/onboarding_view.dart'; +// import 'package:trackeroo/frontend/views/onboarding_view.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/transaction.dart'; import 'package:trackeroo/logic/services/categories_controller.dart'; @@ -138,7 +138,7 @@ class _HomeViewState extends State<HomeView> { onSelected: (value) => setState(() { timespanView = Timespan.monthly; }), - label: const Text('Montly'), + label: const Text('Monthly'), selected: timespanView == Timespan.monthly, showCheckmark: false ), @@ -180,15 +180,16 @@ class _HomeViewState extends State<HomeView> { itemCount: transContr.transactionsList.length <= 25 ? transContr.transactionsList.length : 25, itemBuilder: (context, index) => TransactionListtile(transaction: transContr.transactionsList[index]) ), - FilledButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => const OnboardingView()) - ); - }, - child: const Text('onboarding') - ), + // FilledButton( + // onPressed: () { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const OnboardingView()) + // ); + // }, + // child: const Text('onboarding') + // ), + const SizedBox(height: 65.0) ], ); } @@ -299,7 +300,7 @@ class _HomeViewState extends State<HomeView> { ), badgePositionPercentageOffset: 1.1 )); -} + } return sectionList; } } diff --git a/trackeroo/lib/frontend/views/new_category_view.dart b/trackeroo/lib/frontend/views/new_category_view.dart deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/trackeroo/lib/logic/constants/selecable_colors.dart b/trackeroo/lib/logic/constants/selecable_colors.dart new file mode 100644 index 0000000000000000000000000000000000000000..237f8378ba68c0547e57ddb28d7d1192d070bebd --- /dev/null +++ b/trackeroo/lib/logic/constants/selecable_colors.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:trackeroo/logic/models/selecable_color.dart'; + +Map<String, SelectableColor> selectableColors = { + 'Ocean': SelectableColor(title: 'Ocean', color: const Color(0xFF99c1fe)), + 'Sky': SelectableColor(title: 'Sky', color: const Color(0xFF90ceff)), + 'Baby Blue': SelectableColor(title: 'Baby Blue', color: const Color(0xFF9ee2ff)), + 'Stormy Blue': SelectableColor(title: 'Stormy Blue', color: const Color(0xFFb6c9d8)), + 'Barely Blue': SelectableColor(title: 'Barely Blue', color: const Color(0xFFb0bbc0)), + 'Sorta Eucalyptus': SelectableColor(title: 'Sorta Eucalyptus', color: const Color(0xFFb6ccba)), + 'Caribean': SelectableColor(title: 'Caribean', color: const Color(0xFFa2ffe3)), + 'Eucalyptus': SelectableColor(title: 'Eucalyptus', color: const Color(0xFF009688)), + 'Dark Olive': SelectableColor(title: 'Dark Olive', color: const Color(0xFF6e7872)), + 'Basil': SelectableColor(title: 'Basil', color: const Color(0xFF0b8043)), + 'Betty': SelectableColor(title: 'Betty', color: const Color(0xFF33b679)), + 'Mint': SelectableColor(title: 'Mint', color: const Color(0xFF96ffc4)), + 'Sage': SelectableColor(title: 'Sage', color: const Color(0xFFc7fcd0)), + 'Sorta Sage': SelectableColor(title: 'Sorta Sage', color: const Color(0xFF99aaa5)), + 'Pistacio': SelectableColor(title: 'Pistacio', color: const Color(0xFF7cb342)), + 'Avocado': SelectableColor(title: 'Avocado', color: const Color(0xFFc0ca33)), + 'Citron': SelectableColor(title: 'Citron', color: const Color(0xFFe4c441)), + 'Lemon Pop': SelectableColor(title: 'Lemon Pop', color: const Color(0xFFe4e274)), + 'Sun': SelectableColor(title: 'Sun', color: const Color(0xFFf9f586)), + 'Warm Day': SelectableColor(title: 'Warm Day', color: const Color(0xFFffe68d)), + 'Banana': SelectableColor(title: 'Banana', color: const Color(0xFFf6bf26)), + 'Pale Yellow': SelectableColor(title: 'Pale Yellow', color: const Color(0xFFe1cd8b)), + 'Linen': SelectableColor(title: 'Linen', color: const Color(0xFFdccfaf)), + 'Skin': SelectableColor(title: 'Skin', color: const Color(0xFFffd2af)), + 'Beige': SelectableColor(title: 'Beige', color: const Color(0xFFe2c0a3)), + 'Piggy': SelectableColor(title: 'Piggy', color: const Color(0xFFe7bdb5)), + 'Flamingo': SelectableColor(title: 'Flamingo', color: const Color(0xFFffa8ad)), + 'Sunrise': SelectableColor(title: 'Sunrise', color: const Color(0xFFff9d82)), + 'Salmon': SelectableColor(title: 'Salmon', color: const Color(0xFFff9366)), + 'Mango': SelectableColor(title: 'Mango', color: const Color(0xFFf09300)), + 'Pumpkin': SelectableColor(title: 'Pumpkin', color: const Color(0xFFef6c00)), + 'Tangerine': SelectableColor(title: 'Tangerine', color: const Color(0xFFf4511e)), + 'Shell': SelectableColor(title: 'Shell', color: const Color(0xFFb58a8c)), + 'Coral': SelectableColor(title: 'Coral', color: const Color(0xFFbf796b)), + 'Terra Cotta': SelectableColor(title: 'Terra Cotta', color: const Color(0xFFa14536)), + 'Tomato': SelectableColor(title: 'Tomato', color: const Color(0xFFd50000)), + 'Cherry Blossom': SelectableColor(title: 'Cherry Blossom', color: const Color(0xFFd81b60)), + 'Radicchio': SelectableColor(title: 'Radicchio', color: const Color(0xFFad1457)), + 'Warm Stone': SelectableColor(title: 'Warm Stone', color: const Color(0xFF8f7967)), + 'Just Black': SelectableColor(title: 'Just Black', color: const Color(0xFF494c4f)), + 'Clearly White': SelectableColor(title: 'Clearly White', color: const Color(0xFFedefea)), +}; diff --git a/trackeroo/lib/logic/constants/selectable_icons.dart b/trackeroo/lib/logic/constants/selectable_icons.dart new file mode 100644 index 0000000000000000000000000000000000000000..25464720a4536af4897b2933b1262448ac021e82 --- /dev/null +++ b/trackeroo/lib/logic/constants/selectable_icons.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +List<IconData> selectableIcons = [ + Icons.atm, + Icons.local_atm_rounded, + Icons.local_bar_rounded, + Icons.restaurant_menu_rounded, + Icons.local_cafe_rounded, + Icons.local_florist_rounded, + Icons.book_rounded, + Icons.print_rounded, + Icons.payment_rounded, + Icons.payments_rounded, + Icons.paypal, + Icons.people_alt_rounded, + Icons.family_restroom_rounded, + Icons.kitchen, + Icons.medication_rounded, + Icons.health_and_safety_rounded, + Icons.chair_rounded, + Icons.table_restaurant_rounded, + Icons.local_activity_rounded, + Icons.phone_android_rounded, + Icons.tablet_rounded, + Icons.laptop_mac_rounded, + Icons.tv_rounded, + Icons.cabin_rounded, + Icons.local_convenience_store_rounded, + Icons.downhill_skiing_rounded, + Icons.shopping_cart_rounded, + Icons.directions_bus_rounded, + Icons.directions_car_rounded, + Icons.local_gas_station_rounded, + Icons.directions_bike_rounded, + Icons.directions_boat_rounded, + Icons.directions_subway_rounded, + Icons.directions_walk_rounded, + Icons.local_airport_rounded +]; \ No newline at end of file diff --git a/trackeroo/lib/logic/models/selecable_color.dart b/trackeroo/lib/logic/models/selecable_color.dart new file mode 100644 index 0000000000000000000000000000000000000000..048635da1b32e9015a59fd5d322b8e2ea0b99273 --- /dev/null +++ b/trackeroo/lib/logic/models/selecable_color.dart @@ -0,0 +1,8 @@ +import 'package:flutter/material.dart'; + +class SelectableColor { + SelectableColor({required this.title, required this.color}); + + String title; + Color color; +} diff --git a/trackeroo/lib/logic/services/locator.dart b/trackeroo/lib/logic/services/locator.dart index 756ebb955b506bb8165b36edfd11af56a9fa732c..51b71879272417216cdd4cf0f1905de5568614e3 100644 --- a/trackeroo/lib/logic/services/locator.dart +++ b/trackeroo/lib/logic/services/locator.dart @@ -1,7 +1,7 @@ -import 'package:flutter/material.dart'; - import 'package:hive/hive.dart'; import 'package:get_it/get_it.dart'; +import 'package:trackeroo/logic/constants/selecable_colors.dart'; +import 'package:trackeroo/logic/constants/selectable_icons.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/app_state.dart'; @@ -27,18 +27,18 @@ Future<void> setupLocatorService() async { if(appState.isFirstOpening) { // create default categories categoriesBox.putAll({ - 'food_and_groceries': Category(id: 'food_and_groceries', title: 'Food & Groceries', iconCodePoint: Icons.kitchen.codePoint, colorValue: Colors.green.value), - 'transport_and_car': Category(id: 'transport_and_car', title: 'Transport & Car', iconCodePoint: Icons.directions_bus_rounded.codePoint, colorValue: Colors.amber.value), - 'healthcare_and_drug_stores': Category(id: 'healthcare_and_drug_stores', title: 'Healthcare & Drug Stores', iconCodePoint: Icons.health_and_safety_rounded.codePoint, colorValue: Colors.red.value), - 'shopping': Category(id: 'shopping', title: 'Shopping', iconCodePoint: Icons.shopping_cart_rounded.codePoint, colorValue: Colors.blue.value), - 'bars_and_restaurants': Category(id: 'bars_and_restaurants', title: 'Bars & Restaurants', iconCodePoint: Icons.local_bar_rounded.codePoint, colorValue: Colors.brown.value), - 'family_and_friends': Category(id: 'family_and_friends', title: 'Family & Friends', iconCodePoint: Icons.people_rounded.codePoint, colorValue: Colors.cyan.value), - 'leisure_and_entertainment': Category(id: 'leisure_and_entertainment', title: 'Leisure & Entertainment', iconCodePoint: Icons.local_activity_rounded.codePoint, colorValue: Colors.purple.value), - 'media_and_electronics': Category(id: 'media_and_electronics', title: 'Media & Electronics', iconCodePoint: Icons.laptop_rounded.codePoint, colorValue: Colors.grey.value), - 'education': Category(id: 'education', title: 'Education', iconCodePoint: Icons.book.codePoint, colorValue: Colors.lightGreen.value), - 'household_and_utilities': Category(id: 'household_and_utilities', title: 'Household & Utilities', iconCodePoint: Icons.chair_rounded.codePoint, colorValue: Colors.orange.value), - 'travel_and_holidays': Category(id: 'travel_and_holidays', title: 'Travel & Holidays', iconCodePoint: Icons.flight_rounded.codePoint, colorValue: Colors.teal.value), - 'atm': Category(id: 'atm', title: 'ATM', iconCodePoint: Icons.local_atm_rounded.codePoint, colorValue: Colors.deepPurple.value) + 'food_and_groceries': Category(id: 'food_and_groceries', title: 'Food & Groceries', iconCodePoint: selectableIcons[13].codePoint, colorValue: selectableColors['Sorta Sage']!.color.value), + 'transport_and_car': Category(id: 'transport_and_car', title: 'Transport & Car', iconCodePoint: selectableIcons[27].codePoint, colorValue: selectableColors['Pale Yellow']!.color.value), + 'healthcare_and_drug_stores': Category(id: 'healthcare_and_drug_stores', title: 'Healthcare & Drug Stores', iconCodePoint: selectableIcons[14].codePoint, colorValue: selectableColors['Terra Cotta']!.color.value), + 'shopping': Category(id: 'shopping', title: 'Shopping', iconCodePoint: selectableIcons[26].codePoint, colorValue: selectableColors['Ocean']!.color.value), + 'bars_and_restaurants': Category(id: 'bars_and_restaurants', title: 'Bars & Restaurants', iconCodePoint: selectableIcons[2].codePoint, colorValue: selectableColors['Coral']!.color.value), + 'family_and_friends': Category(id: 'family_and_friends', title: 'Family & Friends', iconCodePoint: selectableIcons[11].codePoint, colorValue: selectableColors['Caribean']!.color.value), + 'leisure_and_entertainment': Category(id: 'leisure_and_entertainment', title: 'Leisure & Entertainment', iconCodePoint: selectableIcons[18].codePoint, colorValue: selectableColors['Mint']!.color.value), + 'media_and_electronics': Category(id: 'media_and_electronics', title: 'Media & Electronics', iconCodePoint: selectableIcons[21].codePoint, colorValue: selectableColors['Dark Olive']!.color.value), + 'education': Category(id: 'education', title: 'Education', iconCodePoint: selectableIcons[6].codePoint, colorValue: selectableColors['Eucalyptus']!.color.value), + 'household_and_utilities': Category(id: 'household_and_utilities', title: 'Household & Utilities', iconCodePoint: selectableIcons[16].codePoint, colorValue: selectableColors['Salmon']!.color.value), + 'travel_and_holidays': Category(id: 'travel_and_holidays', title: 'Travel & Holidays', iconCodePoint: selectableIcons[34].codePoint, colorValue: selectableColors['Sorta Sage']!.color.value), + 'atm': Category(id: 'atm', title: 'ATM', iconCodePoint: selectableIcons[1].codePoint, colorValue: selectableColors['Warm Stone']!.color.value) }); } Map<dynamic, Category> categoriesMap = categoriesBox.toMap();