From 1a7f28703afc12ec2a7502eb972a069d51221466 Mon Sep 17 00:00:00 2001 From: gltron Date: Wed, 14 Feb 2024 23:41:50 +0100 Subject: [PATCH] Added theme, reworked UI --- lib/app.dart | 11 ++- lib/domains/charts/chart_bloc.dart | 44 +++++++++--- lib/domains/charts/chart_event.dart | 12 +++- lib/domains/charts/chart_state.dart | 5 ++ lib/pages/common/titled_container.dart | 57 +++++++++++++++ lib/pages/data/data_page.dart | 21 +++--- lib/pages/data/widgets/account_settings.dart | 36 +++------- .../data/widgets/categories_settings.dart | 68 +++++++++--------- lib/pages/data/widgets/import_settings.dart | 20 +----- lib/pages/stats/stats_page.dart | 6 +- lib/pages/stats/widgets/account_counters.dart | 19 +++-- .../widgets/categories_totals_chart.dart | 20 ++++-- lib/pages/stats/widgets/global_counter.dart | 39 +++++++++++ ...tal_chart.dart => global_total_chart.dart} | 13 ++-- lib/pages/stats/widgets/main_counter.dart | 30 -------- .../monthly_categories_total_chart.dart | 4 +- lib/pages/stats/widgets/profit_indicator.dart | 4 +- lib/pages/stats/widgets/year_selector.dart | 4 +- .../widgets/transaction_line.dart | 4 +- lib/repositories/account/models/category.dart | 10 ++- lib/theme.dart | 69 +++++++++++++++++++ pubspec.lock | 20 +++++- pubspec.yaml | 3 +- 23 files changed, 356 insertions(+), 163 deletions(-) create mode 100644 lib/pages/common/titled_container.dart create mode 100644 lib/pages/stats/widgets/global_counter.dart rename lib/pages/stats/widgets/{monthly_total_chart.dart => global_total_chart.dart} (87%) delete mode 100644 lib/pages/stats/widgets/main_counter.dart create mode 100644 lib/theme.dart diff --git a/lib/app.dart b/lib/app.dart index afb6c47..d4a7c8c 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,6 +4,7 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:tunas/clients/storage/storage_client.dart'; import 'package:tunas/pages/home/home_page.dart'; import 'package:tunas/repositories/account/account_repository.dart'; +import 'package:tunas/theme.dart'; class App extends StatefulWidget { const App({super.key}); @@ -44,13 +45,9 @@ class _AppViewState extends State { providers: [RepositoryProvider.value(value: _accountRepository)], child: MaterialApp( title: 'Tunas', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed( - seedColor: const Color.fromARGB(255, 55, 55, 55), - brightness: Brightness.dark - ), - useMaterial3: true - ), + theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme), + darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme), + themeMode: ThemeMode.dark, initialRoute: '/home', routes: { '/home':(context) => const HomePage(), diff --git a/lib/domains/charts/chart_bloc.dart b/lib/domains/charts/chart_bloc.dart index 9adc9f4..1d4d58d 100644 --- a/lib/domains/charts/chart_bloc.dart +++ b/lib/domains/charts/chart_bloc.dart @@ -5,6 +5,7 @@ import 'package:tunas/domains/charts/models/month_totals.dart'; import 'package:tunas/domains/transaction/models/transaction_line.dart'; import 'package:tunas/domains/charts/models/chart_item.dart'; import 'package:tunas/repositories/account/account_repository.dart'; +import 'package:tunas/repositories/account/models/category.dart'; import 'package:tunas/repositories/account/models/transaction.dart'; part 'chart_event.dart'; @@ -16,20 +17,30 @@ class ChartBloc extends Bloc { ChartBloc({required AccountRepository accountRepository}) : _accountRepository = accountRepository, super(const ChartState()) { - on(_onAccountLoad); + on(_onChartTransactionsLoad); + on(_onChartCategoriesLoad); on(_onNextYear); on(_onPreviousYear); _accountRepository .getTransactionsStream() - .listen((transactions) => add(ChartAccountLoad(transactions))); + .listen((transactions) => add(ChartTransactionsLoad(transactions))); + + _accountRepository + .getCategoriesStream() + .listen((categories) => add(ChartCategoriesLoad(categories))); } - _onAccountLoad(ChartAccountLoad event, Emitter emit) { + _onChartTransactionsLoad(ChartTransactionsLoad event, Emitter emit) { ChartState localState = state.copyWith(transactions: event.transactions); emit(_computeStateStats(localState)); } + _onChartCategoriesLoad(ChartCategoriesLoad event, Emitter emit) { + ChartState localState = state.copyWith(categories: Map.fromEntries(event.categories.map((category) => MapEntry(category.label, category)))); + emit(_computeStateStats(localState)); + } + _onNextYear(ChartNextYear event, Emitter emit) { if (state.lastDate!.year >= state.currentYear + 1) { ChartState localState = state.copyWith(currentYear: state.currentYear + 1); @@ -123,7 +134,8 @@ class ChartBloc extends Bloc { scopedMonthlyTotals[transactionDateDay] = FlSpot(transactionDateDay.toDouble(), transactionLine.subTotal); - if (transaction.category.isEmpty) { + final category = state.categories[transaction.category]; + if (category == null || category.saving) { continue; } @@ -201,15 +213,20 @@ class ChartBloc extends Bloc { List scopedSimplifiedCategoriesPositiveTotals = []; List scopedSimplifiedCategoriesNegativeTotals = []; - scopedCategoriesPositiveTotals.sort((a, b) => a.value.compareTo(b.value)); - scopedCategoriesPositiveTotalsPercents.sort((a, b) => a.value.compareTo(b.value)); + scopedCategoriesPositiveTotals.sort((a, b) => b.value.compareTo(a.value)); + scopedCategoriesPositiveTotalsPercents.sort((a, b) => b.value.compareTo(a.value)); scopedCategoriesNegativeTotals.sort((a, b) => a.value.compareTo(b.value)); scopedCategoriesNegativeTotalsPercents.sort((a, b) => a.value.compareTo(b.value)); - scopedSimplifiedCategoriesPositiveTotals.sort((a, b) => a.value.compareTo(b.value)); - scopedSimplifiedCategoriesPositiveTotalsPercents.sort((a, b) => a.value.compareTo(b.value)); + scopedSimplifiedCategoriesPositiveTotals.sort((a, b) => b.value.compareTo(a.value)); + scopedSimplifiedCategoriesPositiveTotalsPercents.sort((a, b) => b.value.compareTo(a.value)); scopedSimplifiedCategoriesNegativeTotals.sort((a, b) => a.value.compareTo(b.value)); scopedSimplifiedCategoriesNegativeTotalsPercents.sort((a, b) => a.value.compareTo(b.value)); + for (var monthTotals in scopedCategoriesMonthlyTotals.values) { + _sortMapByValues(monthTotals.positives); + _sortMapByValues(monthTotals.negatives); + } + return state.copyWith( scoppedProfit: scoppedTotal, scopedCategoriesPositiveTotals: scopedCategoriesPositiveTotals, @@ -226,4 +243,15 @@ class ChartBloc extends Bloc { scopedMonthlyNegativeTotals: scopedMonthlyNegativeTotals, ); } + + Map _sortMapByValues(Map map) { + final sortedEntries = map.entries.toList()..sort((a, b) { + var diff = b.value.compareTo(a.value); + return diff; + }); + + return map + ..clear() + ..addEntries(sortedEntries); + } } diff --git a/lib/domains/charts/chart_event.dart b/lib/domains/charts/chart_event.dart index da88356..ef02258 100644 --- a/lib/domains/charts/chart_event.dart +++ b/lib/domains/charts/chart_event.dart @@ -7,13 +7,21 @@ sealed class ChartEvent extends Equatable { List get props => []; } -final class ChartAccountLoad extends ChartEvent { +final class ChartTransactionsLoad extends ChartEvent { final List transactions; - const ChartAccountLoad(this.transactions); + const ChartTransactionsLoad(this.transactions); @override List get props => [transactions]; } +final class ChartCategoriesLoad extends ChartEvent { + final List categories; + const ChartCategoriesLoad(this.categories); + + @override + List get props => [categories]; +} + final class ChartNextYear extends ChartEvent {} final class ChartPreviousYear extends ChartEvent {} diff --git a/lib/domains/charts/chart_state.dart b/lib/domains/charts/chart_state.dart index 70ad345..24c43ca 100644 --- a/lib/domains/charts/chart_state.dart +++ b/lib/domains/charts/chart_state.dart @@ -1,6 +1,7 @@ part of 'chart_bloc.dart'; final class ChartState extends Equatable { + final Map categories; final List transactions; final List transactionsLines; @@ -34,6 +35,7 @@ final class ChartState extends Equatable { final double scoppedProfit; const ChartState({ + this.categories = const {}, this.transactions = const [], this.transactionsLines = const [], this.globalTotal = 0, @@ -60,6 +62,7 @@ final class ChartState extends Equatable { }); ChartState copyWith({ + Map? categories, List? transactions, List? transactionsLines, double? globalTotal, @@ -85,6 +88,7 @@ final class ChartState extends Equatable { Map? scopedMonthlyNegativeTotals, }) { return ChartState( + categories: categories ?? this.categories, transactions: transactions ?? this.transactions, transactionsLines: transactionsLines ?? this.transactionsLines, globalTotal: globalTotal ?? this.globalTotal, @@ -113,6 +117,7 @@ final class ChartState extends Equatable { @override List get props => [ + categories, transactions, transactionsLines, globalTotal, diff --git a/lib/pages/common/titled_container.dart b/lib/pages/common/titled_container.dart new file mode 100644 index 0000000..bec26c1 --- /dev/null +++ b/lib/pages/common/titled_container.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +class TitledContainer extends StatelessWidget { + final String title; + final Widget child; + + const TitledContainer({super.key, required this.title, required this.child}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Theme.of(context).colorScheme.shadow, + blurRadius: 10, + offset: const Offset(2, 2), + spreadRadius: 0.1, + blurStyle: BlurStyle.normal, + ) + ] + ), + margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.secondaryContainer, + borderRadius: const BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)), + ), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15), + child: Text( + title, + style: const TextStyle( + fontWeight: FontWeight.w300, + fontSize: 20, + ), + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + child: child, + ), + ], + ) + ); + } +} \ No newline at end of file diff --git a/lib/pages/data/data_page.dart b/lib/pages/data/data_page.dart index 3d670af..5bb857c 100644 --- a/lib/pages/data/data_page.dart +++ b/lib/pages/data/data_page.dart @@ -15,24 +15,25 @@ class DataPage extends StatelessWidget { ), padding: const EdgeInsets.symmetric(vertical: 9, horizontal: 10), margin: const EdgeInsets.symmetric(vertical: 2, horizontal: 10), - child: const Column( + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( + const Text( 'Settings', style: TextStyle( fontWeight: FontWeight.w900, fontSize: 35, ), ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ImportSettings(), - CategoriesSettings(), - AccountSettings(), - ], - ) + Expanded( + child: ListView( + children: const [ + ImportSettings(), + CategoriesSettings(), + AccountSettings(), + ] + ) + ), ] ) ) diff --git a/lib/pages/data/widgets/account_settings.dart b/lib/pages/data/widgets/account_settings.dart index 76785a6..57ffe40 100644 --- a/lib/pages/data/widgets/account_settings.dart +++ b/lib/pages/data/widgets/account_settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tunas/domains/account/account_bloc.dart'; +import 'package:tunas/pages/common/titled_container.dart'; class AccountSettings extends StatelessWidget { const AccountSettings({super.key}); @@ -16,34 +17,15 @@ class AccountSettings extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - builder: (context, state) => Container( - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(5), + builder: (context, state) => TitledContainer( + title: "Accounts", + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _computeCategoryList(state.subAccounts), + ), ), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), - margin: const EdgeInsets.all(5), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Accounts", - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 20, - ), - ), - const SizedBox(height: 10), - SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _computeCategoryList(state.subAccounts), - ), - ), - ], - ) ), ); } diff --git a/lib/pages/data/widgets/categories_settings.dart b/lib/pages/data/widgets/categories_settings.dart index 3cb5681..5c6ff89 100644 --- a/lib/pages/data/widgets/categories_settings.dart +++ b/lib/pages/data/widgets/categories_settings.dart @@ -1,21 +1,42 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tunas/domains/category/category_bloc.dart'; +import 'package:tunas/pages/common/titled_container.dart'; import 'package:tunas/repositories/account/models/category.dart'; class CategoriesSettings extends StatelessWidget { const CategoriesSettings({super.key}); - List _computeCategoryList(List categories) { + List _computeCategoryList(BuildContext context, List categories) { return categories.map((category) => Row( children: [ - Container( - height: 10, - width: 10, + IconButton( + onPressed: () {}, + icon: const Icon(Icons.palette), color: category.rgbToColor(), ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.savings), + color: category.saving ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error, + ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.foundation), + color: category.essential ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error, + ), Container(width: 5), - Text(category.label), + Expanded( + child: Text(category.label) + ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.edit), + ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.delete), + ), ], )).toList(); } @@ -23,35 +44,16 @@ class CategoriesSettings extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - builder: (context, state) => Container( - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(5), + builder: (context, state) => TitledContainer( + title: "Categories", + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _computeCategoryList(context, state.categories), + ), ), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), - margin: const EdgeInsets.all(5), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Categories", - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 20, - ), - ), - const SizedBox(height: 10), - SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _computeCategoryList(state.categories), - ), - ), - ], - ) - ), + ) ); } } \ No newline at end of file diff --git a/lib/pages/data/widgets/import_settings.dart b/lib/pages/data/widgets/import_settings.dart index 10ce384..47f2e87 100644 --- a/lib/pages/data/widgets/import_settings.dart +++ b/lib/pages/data/widgets/import_settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tunas/domains/account/account_bloc.dart'; +import 'package:tunas/pages/common/titled_container.dart'; class ImportSettings extends StatelessWidget { const ImportSettings({super.key}); @@ -8,25 +9,10 @@ class ImportSettings extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - builder: (context, state) => Container( - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(5) - ), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), - margin: const EdgeInsets.all(5), + builder: (context, state) => TitledContainer( + title: "Import", child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - "Import", - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 20, - ), - ), - const SizedBox(height: 10), FilledButton( onPressed: () => context.read().add(const AccountImportCSV()), child: const Text('Import CSV') diff --git a/lib/pages/stats/stats_page.dart b/lib/pages/stats/stats_page.dart index d7cfbb4..4ec208b 100644 --- a/lib/pages/stats/stats_page.dart +++ b/lib/pages/stats/stats_page.dart @@ -3,9 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tunas/domains/charts/chart_bloc.dart'; import 'package:tunas/pages/stats/widgets/account_counters.dart'; import 'package:tunas/pages/stats/widgets/categories_totals_chart.dart'; -import 'package:tunas/pages/stats/widgets/main_counter.dart'; +import 'package:tunas/pages/stats/widgets/global_counter.dart'; import 'package:tunas/pages/stats/widgets/monthly_categories_total_chart.dart'; -import 'package:tunas/pages/stats/widgets/monthly_total_chart.dart'; +import 'package:tunas/pages/stats/widgets/global_total_chart.dart'; import 'package:tunas/pages/stats/widgets/profit_indicator.dart'; import 'package:tunas/pages/stats/widgets/year_selector.dart'; import 'package:tunas/repositories/account/account_repository.dart'; @@ -31,7 +31,7 @@ class StatsPage extends StatelessWidget { children: [ Expanded( flex: 2, - child: MainCounter(value: state.globalTotal) + child: GlobalCounter(value: state.globalTotal) ), Expanded( flex: 1, diff --git a/lib/pages/stats/widgets/account_counters.dart b/lib/pages/stats/widgets/account_counters.dart index a42bef9..3adb786 100644 --- a/lib/pages/stats/widgets/account_counters.dart +++ b/lib/pages/stats/widgets/account_counters.dart @@ -6,7 +6,7 @@ class AccountCounter extends StatelessWidget { const AccountCounter({super.key, required this.accountsTotals}); - List _renderAccountTotals() { + List _renderAccountTotals(BuildContext context) { return accountsTotals.entries.toList().map((entry) => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -21,7 +21,7 @@ class AccountCounter extends StatelessWidget { style: TextStyle( fontFamily: 'NovaMono', fontSize: 15, - color: entry.value > 0 ? const Color.fromARGB(255, 0, 255, 8) : Colors.red + color: entry.value > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error )), ], )).toList(); @@ -33,13 +33,22 @@ class AccountCounter extends StatelessWidget { padding: const EdgeInsets.all(10), margin: const EdgeInsets.all(20), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: Colors.blue + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.primaryContainer, + boxShadow: [ + BoxShadow( + color: Theme.of(context).colorScheme.shadow, + blurRadius: 10, + offset: const Offset(2, 2), + spreadRadius: 0.1, + blurStyle: BlurStyle.normal, + ) + ] ), alignment: Alignment.centerRight, child: Column( crossAxisAlignment: CrossAxisAlignment.end, - children: _renderAccountTotals(), + children: _renderAccountTotals(context), ), ); } diff --git a/lib/pages/stats/widgets/categories_totals_chart.dart b/lib/pages/stats/widgets/categories_totals_chart.dart index a05df11..700b2b4 100644 --- a/lib/pages/stats/widgets/categories_totals_chart.dart +++ b/lib/pages/stats/widgets/categories_totals_chart.dart @@ -39,7 +39,10 @@ class CategoriesTotalsChart extends StatelessWidget { Container( height: 10, width: 10, - color: categoriesColors[item.label], + decoration: BoxDecoration( + color: categoriesColors[item.label], + borderRadius: BorderRadius.circular(15) + ), ), Container(width: 5), Text(item.label), @@ -64,8 +67,17 @@ class CategoriesTotalsChart extends StatelessWidget { padding: const EdgeInsets.all(10), margin: const EdgeInsets.all(20), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: Colors.blue + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.primaryContainer, + boxShadow: [ + BoxShadow( + color: Theme.of(context).colorScheme.shadow, + blurRadius: 10, + offset: const Offset(2, 2), + spreadRadius: 0.1, + blurStyle: BlurStyle.normal, + ) + ] ), child: Row( children: [ @@ -87,7 +99,7 @@ class CategoriesTotalsChart extends StatelessWidget { padding: const EdgeInsets.all(10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), - color: Colors.blueGrey + color: Theme.of(context).colorScheme.secondaryContainer ), child: SingleChildScrollView( scrollDirection: Axis.vertical, diff --git a/lib/pages/stats/widgets/global_counter.dart b/lib/pages/stats/widgets/global_counter.dart new file mode 100644 index 0000000..28cdc46 --- /dev/null +++ b/lib/pages/stats/widgets/global_counter.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class GlobalCounter extends StatelessWidget { + final double value; + + const GlobalCounter({super.key, required this.value}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(10), + margin: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Theme.of(context).colorScheme.primaryContainer, + boxShadow: [ + BoxShadow( + color: Theme.of(context).colorScheme.shadow, + blurRadius: 10, + offset: const Offset(2, 2), + spreadRadius: 0.1, + blurStyle: BlurStyle.normal, + ) + ] + ), + alignment: Alignment.centerRight, + child: Text( + NumberFormat('000.00 €', 'fr_FR').format(value), + style: TextStyle( + fontFamily: 'NovaMono', + fontSize: 60, + fontWeight: FontWeight.w500, + color: value > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/stats/widgets/monthly_total_chart.dart b/lib/pages/stats/widgets/global_total_chart.dart similarity index 87% rename from lib/pages/stats/widgets/monthly_total_chart.dart rename to lib/pages/stats/widgets/global_total_chart.dart index 75ae130..465e7da 100644 --- a/lib/pages/stats/widgets/monthly_total_chart.dart +++ b/lib/pages/stats/widgets/global_total_chart.dart @@ -18,9 +18,7 @@ class GlobalTotalChart extends StatelessWidget { return Padding( padding: const EdgeInsets.only( - left: 12, bottom: 12, - right: 20, top: 20, ), child: AspectRatio( @@ -31,7 +29,7 @@ class GlobalTotalChart extends StatelessWidget { lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( maxContentWidth: 100, - tooltipBgColor: Colors.black, + tooltipBgColor: Theme.of(context).colorScheme.primaryContainer, getTooltipItems: (touchedSpots) { return touchedSpots.map((LineBarSpot touchedSpot) { final textStyle = TextStyle( @@ -52,13 +50,18 @@ class GlobalTotalChart extends StatelessWidget { ), lineBarsData: [ LineChartBarData( - color: Colors.pink, + color: Theme.of(context).colorScheme.primary, spots: monthlyTotals, isCurved: true, isStrokeCapRound: true, barWidth: 3, belowBarData: BarAreaData( - show: false, + show: true, + gradient: LinearGradient( + colors: [Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.secondary] + .map((color) => color.withOpacity(0.2)) + .toList(), + ), ), dotData: const FlDotData(show: false), ), diff --git a/lib/pages/stats/widgets/main_counter.dart b/lib/pages/stats/widgets/main_counter.dart deleted file mode 100644 index 9a245c4..0000000 --- a/lib/pages/stats/widgets/main_counter.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -class MainCounter extends StatelessWidget { - final double value; - - const MainCounter({super.key, required this.value}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(10), - margin: const EdgeInsets.all(20), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: Colors.blue - ), - alignment: Alignment.centerRight, - child: Text( - NumberFormat('000.00 €', 'fr_FR').format(value), - style: TextStyle( - fontFamily: 'NovaMono', - fontSize: 60, - fontWeight: FontWeight.w500, - color: value > 0 ? const Color.fromARGB(255, 0, 255, 8) : Colors.red - ), - ), - ); - } -} \ No newline at end of file diff --git a/lib/pages/stats/widgets/monthly_categories_total_chart.dart b/lib/pages/stats/widgets/monthly_categories_total_chart.dart index 834f20a..db31c39 100644 --- a/lib/pages/stats/widgets/monthly_categories_total_chart.dart +++ b/lib/pages/stats/widgets/monthly_categories_total_chart.dart @@ -100,10 +100,10 @@ class MonthlyCategoriesTotalChart extends StatelessWidget { Color color = Colors.black; if (rodIndex == 0) { value = "+$value"; - color = Colors.green; + color = Theme.of(context).colorScheme.primary; } else { value = "-$value"; - color = Colors.red; + color = Theme.of(context).colorScheme.error; } return BarTooltipItem( diff --git a/lib/pages/stats/widgets/profit_indicator.dart b/lib/pages/stats/widgets/profit_indicator.dart index b57f4e5..b599170 100644 --- a/lib/pages/stats/widgets/profit_indicator.dart +++ b/lib/pages/stats/widgets/profit_indicator.dart @@ -13,7 +13,7 @@ class ProfitIndicator extends StatelessWidget { margin: const EdgeInsets.fromLTRB(0, 0, 20, 0), padding: const EdgeInsets.fromLTRB(10, 5, 10, 5), decoration: BoxDecoration( - color: Colors.blue, + color: Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(5) ), child: Text( @@ -22,7 +22,7 @@ class ProfitIndicator extends StatelessWidget { fontFamily: 'NovaMono', fontSize: 20, fontWeight: FontWeight.w500, - color: profit > 0 ? const Color.fromARGB(255, 0, 255, 8) : Colors.red + color: profit > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error ), ) ); diff --git a/lib/pages/stats/widgets/year_selector.dart b/lib/pages/stats/widgets/year_selector.dart index 1164948..02194ab 100644 --- a/lib/pages/stats/widgets/year_selector.dart +++ b/lib/pages/stats/widgets/year_selector.dart @@ -12,8 +12,8 @@ class YearSelector extends StatelessWidget { margin: const EdgeInsets.fromLTRB(20, 0, 0, 0), padding: const EdgeInsets.fromLTRB(5, 0, 5, 0), decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(5) + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(5), ), child: Row( children: [ diff --git a/lib/pages/transactions/widgets/transaction_line.dart b/lib/pages/transactions/widgets/transaction_line.dart index 8b10561..101fe3e 100644 --- a/lib/pages/transactions/widgets/transaction_line.dart +++ b/lib/pages/transactions/widgets/transaction_line.dart @@ -48,13 +48,13 @@ class TransactionLine extends StatelessWidget { Text( NumberFormat(transaction.value > 0 ? '+#######.00 €' : '#######.00 €', 'fr_FR').format(transaction.value), style: TextStyle( - color: transaction.value > 0 ? Colors.green : Colors.red + color: transaction.value > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error ) ), Text( NumberFormat('#######.00 €', 'fr_FR').format(subTotal), style: TextStyle( - color: subTotal > 0 ? Colors.green : Colors.red + color: subTotal > 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.error ) ), ], diff --git a/lib/repositories/account/models/category.dart b/lib/repositories/account/models/category.dart index de1c2e4..6c0403d 100644 --- a/lib/repositories/account/models/category.dart +++ b/lib/repositories/account/models/category.dart @@ -3,22 +3,30 @@ import 'dart:ui'; class Category { String label; String color; + bool essential; + bool saving; Category({ this.label = '', this.color = '', + this.essential = false, + this.saving = false, }); factory Category.fromJson(Map json) { return Category( label: json['label'], - color: json['color'] + color: json['color'], + essential: bool.parse(json['essential']), + saving: bool.parse(json['saving']), ); } Map toJson() => { 'label': label, 'color': color, + 'essential': essential.toString(), + 'saving': saving.toString(), }; Color rgbToColor() { diff --git a/lib/theme.dart b/lib/theme.dart new file mode 100644 index 0000000..b655b80 --- /dev/null +++ b/lib/theme.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; + +const lightColorScheme = ColorScheme( + brightness: Brightness.light, + primary: Color(0xFF006C45), + onPrimary: Color(0xFFFFFFFF), + primaryContainer: Color(0xFF51FFB1), + onPrimaryContainer: Color(0xFF002112), + secondary: Color(0xFF4E6355), + onSecondary: Color(0xFFFFFFFF), + secondaryContainer: Color(0xFFD0E8D7), + onSecondaryContainer: Color(0xFF0B1F15), + tertiary: Color(0xFF3C6472), + onTertiary: Color(0xFFFFFFFF), + tertiaryContainer: Color(0xFFBFE9F9), + onTertiaryContainer: Color(0xFF001F28), + error: Color(0xFFBA1A1A), + errorContainer: Color(0xFFFFDAD6), + onError: Color(0xFFFFFFFF), + onErrorContainer: Color(0xFF410002), + background: Color(0xFFFBFDF8), + onBackground: Color(0xFF191C1A), + surface: Color(0xFFFBFDF8), + onSurface: Color(0xFF191C1A), + surfaceVariant: Color(0xFFDCE5DC), + onSurfaceVariant: Color(0xFF404943), + outline: Color(0xFF707972), + onInverseSurface: Color(0xFFEFF1ED), + inverseSurface: Color(0xFF2E312E), + inversePrimary: Color(0xFF21E297), + shadow: Color(0xFF000000), + surfaceTint: Color(0xFF006C45), + outlineVariant: Color(0xFFC0C9C1), + scrim: Color(0xFF000000), +); + +const darkColorScheme = ColorScheme( + brightness: Brightness.dark, + primary: Color(0xFF21E297), + onPrimary: Color(0xFF003822), + primaryContainer: Color(0xFF005233), + onPrimaryContainer: Color(0xFF51FFB1), + secondary: Color(0xFFB4CCBB), + onSecondary: Color(0xFF203529), + secondaryContainer: Color(0xFF364B3E), + onSecondaryContainer: Color(0xFFD0E8D7), + tertiary: Color(0xFFA4CDDD), + onTertiary: Color(0xFF043542), + tertiaryContainer: Color(0xFF234C59), + onTertiaryContainer: Color(0xFFBFE9F9), + error: Color(0xFFFFB4AB), + errorContainer: Color(0xFF93000A), + onError: Color(0xFF690005), + onErrorContainer: Color(0xFFFFDAD6), + background: Color(0xFF191C1A), + onBackground: Color(0xFFE1E3DF), + surface: Color(0xFF191C1A), + onSurface: Color(0xFFE1E3DF), + surfaceVariant: Color(0xFF404943), + onSurfaceVariant: Color(0xFFC0C9C1), + outline: Color(0xFF8A938B), + onInverseSurface: Color(0xFF191C1A), + inverseSurface: Color(0xFFE1E3DF), + inversePrimary: Color(0xFF006C45), + shadow: Color(0xFF000000), + surfaceTint: Color(0xFF21E297), + outlineVariant: Color(0xFF404943), + scrim: Color(0xFF000000), +); diff --git a/pubspec.lock b/pubspec.lock index 042d880..1340715 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,6 +121,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.65.0" + flex_color_picker: + dependency: "direct main" + description: + name: flex_color_picker + sha256: "0871edc170153cfc3de316d30625f40a85daecfa76ce541641f3cc0ec7757cbf" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flex_seed_scheme: + dependency: transitive + description: + name: flex_seed_scheme + sha256: "29c12aba221eb8a368a119685371381f8035011d18de5ba277ad11d7dfb8657f" + url: "https://pub.dev" + source: hosted + version: "1.4.0" flutter: dependency: "direct main" description: flutter @@ -130,10 +146,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.4" flutter_keyboard_visibility: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 89c62a1..70a1bc6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: cupertino_icons: ^1.0.2 fl_chart: ^0.65.0 logging: ^1.2.0 - flutter_bloc: ^8.1.3 + flutter_bloc: ^8.1.4 path_provider: ^2.1.1 equatable: ^2.0.5 rxdart: ^0.27.7 @@ -27,6 +27,7 @@ dependencies: formz: ^0.6.1 uuid: ^4.3.2 flutter_typeahead: ^5.2.0 + flex_color_picker: ^3.3.1 dev_dependencies: flutter_test: