From 983f3316e69772b15a053cf2892ef1ad071e8360 Mon Sep 17 00:00:00 2001 From: Marco Date: Sun, 12 Jan 2025 17:16:55 +0100 Subject: [PATCH] Change behavior of global state Until now, FoodEntryBloc (which is holding the global state for every day) would cause a change in every widget in the tree. For example, when an entry for one day gets added, all other entries in opened days would also be rebuilt. Now, the GlobalState will be emitted with an additional date, which signals, which date caused the state change. With this information, I selectively only build the EntryLists that needs to be rebuilt. Additionally, the calendar FAB will push a new route instead of navigating to a new day by utilizing the pageController. --- lib/food_entry/food_entry_bloc.dart | 36 +++++++++++++++----- lib/perdate/entry_list.dart | 1 + lib/perdate/perdate_pageview_controller.dart | 7 ++-- lib/perdate/perdate_widget.dart | 5 +++ 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/food_entry/food_entry_bloc.dart b/lib/food_entry/food_entry_bloc.dart index f30b014..de21a49 100644 --- a/lib/food_entry/food_entry_bloc.dart +++ b/lib/food_entry/food_entry_bloc.dart @@ -27,7 +27,8 @@ class FoodEntryBloc extends Bloc { var newList = await storage.getEntriesForDate(event.forDate); state.foodEntries.addAll({event.forDate: newList}); - emit(GlobalEntryState(foodEntries: state.foodEntries)); + emit(GlobalEntryState( + foodEntries: state.foodEntries, stateChangedForDate: event.forDate)); } void handleFoodEntryEvent( @@ -43,7 +44,8 @@ class FoodEntryBloc extends Bloc { var newFoodEntries = state.foodEntries; newFoodEntries.addAll({event.forDate: entriesForDate}); - emit(GlobalEntryState(foodEntries: newFoodEntries)); + emit(GlobalEntryState( + foodEntries: newFoodEntries, stateChangedForDate: event.forDate)); } void handleFoodChangedEvent( @@ -64,7 +66,8 @@ class FoodEntryBloc extends Bloc { var newFoodEntries = state.foodEntries; newFoodEntries.addAll({event.forDate: entriesForDate}); - emit(GlobalEntryState(foodEntries: newFoodEntries)); + emit(GlobalEntryState( + foodEntries: newFoodEntries, stateChangedForDate: event.forDate)); } void handleDeleteFoodEvent( @@ -79,7 +82,8 @@ class FoodEntryBloc extends Bloc { var newFoodEntries = state.foodEntries; newFoodEntries.addAll({event.forDate: entriesForDate}); - emit(GlobalEntryState(foodEntries: newFoodEntries)); + emit(GlobalEntryState( + foodEntries: newFoodEntries, stateChangedForDate: event.forDate)); } void handleBarcodeScannedEvent( @@ -91,6 +95,7 @@ class FoodEntryBloc extends Bloc { if (e.code == BarcodeScanner.cameraAccessDenied) { emit(GlobalEntryState( foodEntries: state.foodEntries, + stateChangedForDate: event.forDate, appError: GlobalAppError(GlobalAppErrorType.errCameraPermissionDenied))); } @@ -107,6 +112,7 @@ class FoodEntryBloc extends Bloc { if (scanResult.type == ResultType.Error) { emit(GlobalEntryState( foodEntries: state.foodEntries, + stateChangedForDate: event.forDate, appError: GlobalAppError(GlobalAppErrorType.errGeneralError))); return; } @@ -122,7 +128,10 @@ class FoodEntryBloc extends Bloc { entriesForDate.add(newEntryWaiting); state.foodEntries.addAll({event.forDate: entriesForDate}); - emit(GlobalEntryState(foodEntries: state.foodEntries)); + emit(GlobalEntryState( + foodEntries: state.foodEntries, + stateChangedForDate: event.forDate, + )); await responseFuture.then((response) async { var index = entriesForDate @@ -140,6 +149,7 @@ class FoodEntryBloc extends Bloc { emit(GlobalEntryState( foodEntries: newFoodEntries, + stateChangedForDate: event.forDate, appError: GlobalAppError(GlobalAppErrorType.errbarcodeNotFound))); return; } @@ -151,6 +161,7 @@ class FoodEntryBloc extends Bloc { emit(GlobalEntryState( foodEntries: newFoodEntries, + stateChangedForDate: event.forDate, appError: GlobalAppError(GlobalAppErrorType.errServerNotReachable))); return; @@ -173,7 +184,8 @@ class FoodEntryBloc extends Bloc { var newFoodEntries = state.foodEntries; newFoodEntries.addAll({event.forDate: entriesForDate}); - emit(GlobalEntryState(foodEntries: newFoodEntries)); + emit(GlobalEntryState( + foodEntries: newFoodEntries, stateChangedForDate: event.forDate)); }); } @@ -194,7 +206,8 @@ class FoodEntryBloc extends Bloc { selectedEntry.isSelected = !oldStateOfTappedEntry; - emit(GlobalEntryState(foodEntries: state.foodEntries)); + emit(GlobalEntryState( + foodEntries: state.foodEntries, stateChangedForDate: event.forDate)); } } @@ -240,12 +253,17 @@ class PermissionException extends FoodEvent { PermissionException({required super.forDate}); } -/// This is the state for one date/page +class PageEntryState {} + class GlobalEntryState { final Map> foodEntries; final GlobalAppError? appError; - GlobalEntryState({required this.foodEntries, this.appError}); + //we use this to only redraw pages whose entries changed + final DateTime? stateChangedForDate; + + GlobalEntryState( + {required this.foodEntries, this.stateChangedForDate, this.appError}); factory GlobalEntryState.init() { return GlobalEntryState(foodEntries: {}); diff --git a/lib/perdate/entry_list.dart b/lib/perdate/entry_list.dart index a4c7e0e..b1a2c84 100644 --- a/lib/perdate/entry_list.dart +++ b/lib/perdate/entry_list.dart @@ -22,6 +22,7 @@ class FoodEntryList extends StatelessWidget { @override Widget build(BuildContext context) { + print("FoodEntryList for date $date being built"); var headerStyle = TextStyle( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface); diff --git a/lib/perdate/perdate_pageview_controller.dart b/lib/perdate/perdate_pageview_controller.dart index 4094110..db51168 100644 --- a/lib/perdate/perdate_pageview_controller.dart +++ b/lib/perdate/perdate_pageview_controller.dart @@ -92,10 +92,9 @@ class PerDatePageViewController extends StatelessWidget { onDateSelected: (dateSelected) { if (dateSelected == null) return; - var dateDiff = dateSelected.difference(initialDate).inDays; - - log("dateDiff = $dateDiff"); - pageController.jumpToPage(initialOffset - dateDiff); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => + PerDatePageViewController(initialDate: dateSelected))); }, ), ], diff --git a/lib/perdate/perdate_widget.dart b/lib/perdate/perdate_widget.dart index be9ff6e..0e603d1 100644 --- a/lib/perdate/perdate_widget.dart +++ b/lib/perdate/perdate_widget.dart @@ -33,6 +33,11 @@ class _PerDateWidgetState extends State showNewSnackbarWith(context, pageState.appError!); } }, + buildWhen: (previous, current) { + if (current.stateChangedForDate == null) return true; + if (current.stateChangedForDate == widget.date) return true; + return false; + }, builder: (context, pageState) { return FoodEntryList( entries: pageState.foodEntries[widget.date] ?? [],