From be2ab69a3f5bf22758a428d62baac837870bb3b4 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 11 Jun 2024 19:05:42 +0200 Subject: [PATCH] Instead of a global FoodEntryBloc, every PerDateWidget has one --- lib/app_drawer.dart | 5 +- lib/calendar_floating_button.dart | 2 +- lib/food_entry_bloc.dart | 43 ++++------- lib/main.dart | 30 +++----- lib/perdate_widget.dart | 116 +++++++++++++++++++----------- lib/settings.dart | 6 +- lib/settings_bloc.dart | 37 ++++++++++ lib/storage/storage.dart | 6 +- lib/sum_widget.dart | 19 +++-- 9 files changed, 162 insertions(+), 102 deletions(-) create mode 100644 lib/settings_bloc.dart diff --git a/lib/app_drawer.dart b/lib/app_drawer.dart index 1be7621..eb9aedd 100644 --- a/lib/app_drawer.dart +++ b/lib/app_drawer.dart @@ -20,7 +20,7 @@ class AppDrawer extends StatelessWidget { leading: IconButton( icon: const Icon(Icons.close), onPressed: () { - Navigator.pop(context); + context.pop(); }, ), title: const Text('MenĂ¼')), @@ -29,7 +29,8 @@ class AppDrawer extends StatelessWidget { title: const Text('Einstellungen'), trailing: const Icon(Icons.settings), onTap: () { - context.goNamed('settings'); + context.pop(); + context.pushNamed('settings'); }, ), ], diff --git a/lib/calendar_floating_button.dart b/lib/calendar_floating_button.dart index 0f0ac6f..693e030 100644 --- a/lib/calendar_floating_button.dart +++ b/lib/calendar_floating_button.dart @@ -20,7 +20,7 @@ class CalendarFloatingButton extends StatelessWidget { lastDate: DateTime.now(), ); - router.goNamed('perDay', extra: datePicked); + router.pushNamed('perDay', extra: datePicked); }, child: const Icon(Icons.today)); } diff --git a/lib/food_entry_bloc.dart b/lib/food_entry_bloc.dart index f7eb54f..7162e2f 100644 --- a/lib/food_entry_bloc.dart +++ b/lib/food_entry_bloc.dart @@ -3,20 +3,25 @@ import 'package:kalodings/storage/storage.dart'; import 'package:uuid/uuid.dart'; class FoodEntryBloc extends Bloc { + final FoodEntryState initialState; final FoodStorage storage; + final DateTime forDate; - FoodEntryBloc(super.initialState, {required this.storage}) { + FoodEntryBloc( + {required this.initialState, + required this.forDate, + required this.storage}) + : super(initialState) { on(addFoodEntry); on(deleteFood); on(updateEntries); - on(persistDailyLimit); } void addFoodEntry(FoodEntryEvent event, Emitter emit) async { FoodEntryState newState = FoodEntryState.from(state); newState.addEntry(event.entry); - await storage.writeEntriesForDate(event.date, newState.foodEntries); + await storage.writeEntriesForDate(forDate, newState.foodEntries); emit(newState); } @@ -24,7 +29,7 @@ class FoodEntryBloc extends Bloc { void deleteFood(FoodDeletionEvent event, Emitter emit) async { state.foodEntries.removeWhere((entry) => entry.id == event.entryID); - await storage.writeEntriesForDate(event.date, state.foodEntries); + await storage.writeEntriesForDate(forDate, state.foodEntries); emit(FoodEntryState.from(state)); } @@ -32,35 +37,23 @@ class FoodEntryBloc extends Bloc { void updateEntries( PageChangedEvent event, Emitter emit) async { var entries = await storage.getEntriesForDate(event.changedToDate); - var limit = await storage.readLimit(); - var newState = FoodEntryState(foodEntries: entries, kcalLimit: limit); + var newState = FoodEntryState(foodEntries: entries); emit(newState); } - - void persistDailyLimit( - DailyKcalLimitUpdated event, Emitter emit) async { - await storage.updateLimit(event.kcal); - emit(FoodEntryState(foodEntries: state.foodEntries, kcalLimit: event.kcal)); - } - - void getDailyLimit( - DailyKcalLimitUpdated event, Emitter emit) async {} } class FoodEvent {} class FoodEntryEvent extends FoodEvent { final FoodEntry entry; - final DateTime date; - FoodEntryEvent({required this.entry, required this.date}); + FoodEntryEvent({required this.entry}); } class FoodDeletionEvent extends FoodEvent { final String entryID; - final DateTime date; - FoodDeletionEvent({required this.entryID, required this.date}); + FoodDeletionEvent({required this.entryID}); } class PageChangedEvent extends FoodEvent { @@ -69,24 +62,18 @@ class PageChangedEvent extends FoodEvent { PageChangedEvent({required this.changedToDate}); } -class DailyKcalLimitUpdated extends FoodEvent { - final double kcal; - DailyKcalLimitUpdated({required this.kcal}); -} - class FoodEntryState { final List foodEntries; - final double kcalLimit; - FoodEntryState({required this.foodEntries, required this.kcalLimit}); + FoodEntryState({required this.foodEntries}); factory FoodEntryState.init() { - return FoodEntryState(foodEntries: [], kcalLimit: 0); + return FoodEntryState(foodEntries: []); } static from(FoodEntryState state) { List newList = List.from(state.foodEntries); - return FoodEntryState(foodEntries: newList, kcalLimit: state.kcalLimit); + return FoodEntryState(foodEntries: newList); } void addEntry(FoodEntry entry) { diff --git a/lib/main.dart b/lib/main.dart index 8c082c1..b9e97de 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:go_router/go_router.dart'; -import 'package:kalodings/food_entry_bloc.dart'; +import 'package:kalodings/settings_bloc.dart'; import 'package:kalodings/perdate_widget.dart'; import 'package:kalodings/settings.dart'; import 'package:kalodings/storage/storage.dart'; @@ -10,20 +10,22 @@ import 'package:kalodings/storage/storage.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); var storage = await FoodStorage.create(); + var kcalLimit = await storage.readLimit(); - runApp(MainApp(storage: storage)); + runApp(MainApp(storage: storage, kcalLimit: kcalLimit)); } class MainApp extends StatelessWidget { final FoodStorage storage; - const MainApp({required this.storage, super.key}); + final double kcalLimit; + + const MainApp({required this.storage, required this.kcalLimit, super.key}); @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) { - return FoodEntryBloc(FoodEntryState.init(), storage: storage); - }, + create: (context) => SettingsDataBloc(SettingsState(kcalLimit: kcalLimit), + storage: storage), child: MaterialApp.router( localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, @@ -40,16 +42,7 @@ class MainApp extends StatelessWidget { } } -final router = GoRouter(routes: [ - GoRoute( - path: '/', - name: 'perDayToday', - builder: (context, state) { - context - .read() - .add(PageChangedEvent(changedToDate: DateTime.now())); - return PerDateWidget(DateTime.now()); - }), +final router = GoRouter(initialLocation: '/day', routes: [ GoRoute( path: '/day', name: 'perDay', @@ -60,11 +53,8 @@ final router = GoRouter(routes: [ } else { date = state.extra as DateTime; } - context - .read() - .add(PageChangedEvent(changedToDate: date)); - return PerDateWidget(date); + return PerDateWidget(date: date); }), GoRoute( path: '/settings', diff --git a/lib/perdate_widget.dart b/lib/perdate_widget.dart index c3959b1..4da71d0 100644 --- a/lib/perdate_widget.dart +++ b/lib/perdate_widget.dart @@ -6,59 +6,95 @@ import 'package:kalodings/calendar_floating_button.dart'; import 'package:kalodings/enter_food_widget.dart'; import 'package:kalodings/food_entry_bloc.dart'; import 'package:kalodings/food_entry_widget.dart'; +import 'package:kalodings/storage/storage.dart'; import 'package:kalodings/sum_widget.dart'; -class PerDateWidget extends StatelessWidget { +class PerDateWidget extends StatefulWidget { final DateTime date; - const PerDateWidget(this.date, {super.key}); + const PerDateWidget({super.key, required this.date}); + + @override + State createState() => _PerDateWidgetState(); +} + +class _PerDateWidgetState extends State { + late FoodStorage storage; + late Future> entriesFuture; + late List entries; + + @override + void initState() { + super.initState(); + + storage = FoodStorage.getInstance(); + entriesFuture = storage.getEntriesForDate(widget.date); + entriesFuture.then((val) { + entries = val; + }); + } @override Widget build(BuildContext context) { - var formattedDate = DateFormat.yMMMMd('de').format(date); + var formattedDate = DateFormat.yMMMMd('de').format(widget.date); return Scaffold( appBar: AppBar( title: Text(formattedDate), ), drawer: const AppDrawer(), - body: BlocBuilder( - builder: (context, state) { - return ListView.builder( - itemCount: state.foodEntries.length + 2, - itemBuilder: (BuildContext itemBuilderContext, int index) { - if (index == state.foodEntries.length) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: SumWidget(limit: state.kcalLimit), - ); - } - if (index == state.foodEntries.length + 1) { - return Column( - children: [ - EnterFoodWidget( - onAdd: (context, entry) { - context - .read() - .add(FoodEntryEvent(entry: entry, date: date)); - }, - ), - const SizedBox(height: 75), - ], - ); - } - - return FoodEntryWidget( - entry: state.foodEntries[index], - onDelete: (callbackContext) { - callbackContext.read().add( - FoodDeletionEvent( - entryID: state.foodEntries[index].id, date: date), + body: FutureBuilder( + future: entriesFuture, + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return const Center(child: CircularProgressIndicator()); + } else { + return BlocProvider( + create: (context) => FoodEntryBloc( + initialState: FoodEntryState(foodEntries: entries), + storage: storage, + forDate: widget.date), + child: BlocBuilder( + builder: (context, state) { + return ListView.builder( + itemCount: state.foodEntries.length + 2, + itemBuilder: (BuildContext itemBuilderContext, int index) { + if (index == state.foodEntries.length) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: SumWidget(foodEntries: state.foodEntries), ); - }, - ); - }, - ); + } + if (index == state.foodEntries.length + 1) { + return Column( + children: [ + EnterFoodWidget( + onAdd: (context, entry) { + context + .read() + .add(FoodEntryEvent(entry: entry)); + }, + ), + const SizedBox(height: 75), + ], + ); + } + + return FoodEntryWidget( + entry: state.foodEntries[index], + onDelete: (callbackContext) { + callbackContext + .read() + .add(FoodDeletionEvent( + entryID: state.foodEntries[index].id, + )); + }, + ); + }, + ); + }), + ); + } }, ), - floatingActionButton: CalendarFloatingButton(date: date)); + floatingActionButton: CalendarFloatingButton(date: widget.date)); } } diff --git a/lib/settings.dart b/lib/settings.dart index 15c9a62..8f9cb35 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:kalodings/app_drawer.dart'; import 'package:kalodings/calendar_floating_button.dart'; -import 'package:kalodings/food_entry_bloc.dart'; +import 'package:kalodings/settings_bloc.dart'; import 'package:settings_ui/settings_ui.dart'; class SettingsWidget extends StatefulWidget { @@ -19,7 +19,7 @@ class _SettingsWidgetState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: BlocBuilder( + body: BlocBuilder( builder: (context, state) { return SettingsList(sections: [ SettingsSection( @@ -45,7 +45,7 @@ class _SettingsWidgetState extends State { } catch (e) { setting = 2000.0; } - context.read().add( + context.read().add( DailyKcalLimitUpdated(kcal: setting)); ctx.pop(); }, diff --git a/lib/settings_bloc.dart b/lib/settings_bloc.dart new file mode 100644 index 0000000..624ce9f --- /dev/null +++ b/lib/settings_bloc.dart @@ -0,0 +1,37 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:kalodings/storage/storage.dart'; + +class SettingsDataBloc extends Bloc { + final FoodStorage storage; + + SettingsDataBloc(super.initialState, {required this.storage}) { + on(persistDailyLimit); + } + + void persistDailyLimit( + DailyKcalLimitUpdated event, Emitter emit) async { + await storage.updateLimit(event.kcal); + emit(SettingsState(kcalLimit: event.kcal)); + } +} + +class SettingsEvent {} + +class DailyKcalLimitUpdated extends SettingsEvent { + final double kcal; + DailyKcalLimitUpdated({required this.kcal}); +} + +class SettingsState { + final double kcalLimit; + + SettingsState({required this.kcalLimit}); + + factory SettingsState.init() { + return SettingsState(kcalLimit: 2000); + } + + static from(SettingsState state) { + return SettingsState(kcalLimit: state.kcalLimit); + } +} diff --git a/lib/storage/storage.dart b/lib/storage/storage.dart index 9bf659a..93b60ee 100644 --- a/lib/storage/storage.dart +++ b/lib/storage/storage.dart @@ -4,6 +4,7 @@ import 'package:kalodings/food_entry_bloc.dart'; import 'package:path_provider/path_provider.dart'; class FoodStorage { + static late FoodStorage _instance; late String path; FoodStorage._create(); @@ -11,10 +12,13 @@ class FoodStorage { var storage = FoodStorage._create(); var directory = await getApplicationCacheDirectory(); storage.path = directory.path; + _instance = storage; - return storage; + return _instance; } + static FoodStorage getInstance() => _instance; + Future> getEntriesForDate(DateTime date) async { List entries = []; var filePath = '$path/${date.year}/${date.month}/${date.day}'; diff --git a/lib/sum_widget.dart b/lib/sum_widget.dart index 507d6f3..dac3137 100644 --- a/lib/sum_widget.dart +++ b/lib/sum_widget.dart @@ -1,19 +1,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kalodings/food_entry_bloc.dart'; +import 'package:kalodings/settings_bloc.dart'; import 'package:kalodings/row_with_spacers_widget.dart'; -class SumWidget extends StatelessWidget { - final double limit; - - const SumWidget({required this.limit, super.key}); +class SumWidget extends StatefulWidget { + final List foodEntries; + const SumWidget({required this.foodEntries, super.key}); + @override + State createState() => _SumWidgetState(); +} + +class _SumWidgetState extends State { @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocBuilder( builder: (context, state) { var sum = 0.0; - for (var entry in state.foodEntries) { + for (var entry in widget.foodEntries) { sum += entry.kcalPerMass / 100 * entry.mass; } @@ -21,7 +26,7 @@ class SumWidget extends StatelessWidget { null, null, const Text("kcal heute:"), - Text('${sum.toString()}/$limit'), + Text('${sum.toString()}/${state.kcalLimit}'), null, ); },