diff --git a/packages/flutter_availability/lib/src/service/pop_handler.dart b/packages/flutter_availability/lib/src/service/pop_handler.dart new file mode 100644 index 0000000..348a28d --- /dev/null +++ b/packages/flutter_availability/lib/src/service/pop_handler.dart @@ -0,0 +1,24 @@ +import "package:flutter/material.dart"; + +/// +class PopHandler { + /// Constructor + PopHandler(); + + final List _handlers = []; + + /// Registers a new handler + void add(VoidCallback handler) { + _handlers.add(handler); + } + + /// Removes a handler + void remove(VoidCallback handler) { + _handlers.remove(handler); + } + + /// Handles the pop + void handlePop() { + _handlers.lastOrNull?.call(); + } +} diff --git a/packages/flutter_availability/lib/src/ui/screens/availability_modification.dart b/packages/flutter_availability/lib/src/ui/screens/availability_modification.dart index a3c0775..84c476f 100644 --- a/packages/flutter_availability/lib/src/ui/screens/availability_modification.dart +++ b/packages/flutter_availability/lib/src/ui/screens/availability_modification.dart @@ -9,11 +9,12 @@ import "package:flutter_availability/src/ui/widgets/base_page.dart"; import "package:flutter_availability/src/ui/widgets/pause_selection.dart"; import "package:flutter_availability/src/util/scope.dart"; import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; /// Screen for modifying the availabilities for a specific daterange /// There might already be availabilities for the selected period but they /// will be overwritten -class AvailabilitiesModificationScreen extends StatefulWidget { +class AvailabilitiesModificationScreen extends StatefulHookWidget { /// Constructor const AvailabilitiesModificationScreen({ required this.dateRange, @@ -62,6 +63,11 @@ class _AvailabilitiesModificationScreenState var spacing = options.spacing; var translations = options.translations; + useEffect(() { + availabilityScope.popHandler.add(widget.onExit); + return () => availabilityScope.popHandler.remove(widget.onExit); + }); + // TODO(freek): the selected period might be longer than 1 month //so we need to get all the availabilites through a stream Future onSave() async { @@ -180,7 +186,7 @@ class _AvailabilitiesModificationScreenState } } -class _AvailabilitiesModificationScreenLayout extends StatelessWidget { +class _AvailabilitiesModificationScreenLayout extends HookWidget { const _AvailabilitiesModificationScreenLayout({ required this.dateRange, required this.clearAvailability, diff --git a/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart b/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart index 2cd7e6a..5767ab3 100644 --- a/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart +++ b/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart @@ -17,7 +17,7 @@ class AvailabilityOverview extends StatefulHookWidget { }); /// Callback for when the user gives an availability range - final void Function( + final Future Function( DateTimeRange range, List selectedAvailabilities, ) onEditDateRange; @@ -49,6 +49,11 @@ class _AvailabilityOverviewState extends State { [_selectedDate], ); + useEffect(() { + availabilityScope.popHandler.add(widget.onExit); + return () => availabilityScope.popHandler.remove(widget.onExit); + }); + var availabilitySnapshot = useStream(availabilityStream); var selectedAvailabilities = [ @@ -94,14 +99,16 @@ class _AvailabilityOverviewState extends State { VoidCallback? onButtonPress; if (_selectedRange != null) { - onButtonPress = () { - widget.onEditDateRange( + onButtonPress = () async { + await widget.onEditDateRange( _selectedRange!, selectedAvailabilities, ); - setState(() { - _selectedRange = null; - }); + if (mounted) { + setState(() { + _selectedRange = null; + }); + } }; } diff --git a/packages/flutter_availability/lib/src/ui/screens/template_day_modification.dart b/packages/flutter_availability/lib/src/ui/screens/template_day_modification.dart index ea7181f..91130b7 100644 --- a/packages/flutter_availability/lib/src/ui/screens/template_day_modification.dart +++ b/packages/flutter_availability/lib/src/ui/screens/template_day_modification.dart @@ -7,9 +7,10 @@ import "package:flutter_availability/src/ui/widgets/template_name_input.dart"; import "package:flutter_availability/src/ui/widgets/template_time_break.dart"; import "package:flutter_availability/src/util/scope.dart"; import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; /// Page for creating or editing a day template -class DayTemplateModificationScreen extends StatefulWidget { +class DayTemplateModificationScreen extends StatefulHookWidget { /// Constructor const DayTemplateModificationScreen({ required this.template, @@ -50,6 +51,11 @@ class _DayTemplateModificationScreenState var options = availabilityScope.options; var translations = options.translations; + useEffect(() { + availabilityScope.popHandler.add(widget.onExit); + return () => availabilityScope.popHandler.remove(widget.onExit); + }); + Future onDeletePressed() async { var isConfirmed = await options.confirmationDialogBuilder( context, diff --git a/packages/flutter_availability/lib/src/ui/screens/template_overview.dart b/packages/flutter_availability/lib/src/ui/screens/template_overview.dart index 461f61c..f93ec25 100644 --- a/packages/flutter_availability/lib/src/ui/screens/template_overview.dart +++ b/packages/flutter_availability/lib/src/ui/screens/template_overview.dart @@ -41,6 +41,11 @@ class AvailabilityTemplateOverview extends HookWidget { var dayTemplatesSnapshot = useStream(dayTemplateStream); var weekTemplatesSnapshot = useStream(weekTemplateStream); + useEffect(() { + availabilityScope.popHandler.add(onExit); + return () => availabilityScope.popHandler.remove(onExit); + }); + var dayTemplates = dayTemplatesSnapshot.data ?? []; var weekTemplates = diff --git a/packages/flutter_availability/lib/src/ui/screens/template_week_modification.dart b/packages/flutter_availability/lib/src/ui/screens/template_week_modification.dart index 7e843dd..feaf817 100644 --- a/packages/flutter_availability/lib/src/ui/screens/template_week_modification.dart +++ b/packages/flutter_availability/lib/src/ui/screens/template_week_modification.dart @@ -8,9 +8,10 @@ import "package:flutter_availability/src/ui/widgets/template_week_day_selection. import "package:flutter_availability/src/ui/widgets/template_week_overview.dart"; import "package:flutter_availability/src/util/scope.dart"; import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; /// Page for creating or editing a day template -class WeekTemplateModificationScreen extends StatefulWidget { +class WeekTemplateModificationScreen extends StatefulHookWidget { /// Constructor const WeekTemplateModificationScreen({ required this.template, @@ -111,6 +112,11 @@ class _WeekTemplateModificationScreenState widget.onExit(); } + useEffect(() { + availabilityScope.popHandler.add(onBackPressed); + return () => availabilityScope.popHandler.remove(onBackPressed); + }); + var canSave = _viewModel.canSave; var nextButton = options.primaryButtonBuilder( context, diff --git a/packages/flutter_availability/lib/src/ui/widgets/pause_selection.dart b/packages/flutter_availability/lib/src/ui/widgets/pause_selection.dart index 692ed0a..9364b5e 100644 --- a/packages/flutter_availability/lib/src/ui/widgets/pause_selection.dart +++ b/packages/flutter_availability/lib/src/ui/widgets/pause_selection.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:flutter_availability/flutter_availability.dart"; import "package:flutter_availability/src/service/availability_service.dart"; +import "package:flutter_availability/src/service/pop_handler.dart"; import "package:flutter_availability/src/ui/view_models/break_view_model.dart"; import "package:flutter_availability/src/ui/widgets/generic_time_selection.dart"; import "package:flutter_availability/src/ui/widgets/input_fields.dart"; @@ -32,6 +33,7 @@ class PauseSelection extends StatelessWidget { var availabilityScope = AvailabilityScope.of(context); var options = availabilityScope.options; var translations = options.translations; + var popHandler = availabilityScope.popHandler; Future openBreakDialog( BreakViewModel? initialBreak, @@ -43,6 +45,7 @@ class PauseSelection extends StatelessWidget { userId: availabilityScope.userId, options: options, service: availabilityScope.service, + popHandler: popHandler, editingTemplate: editingTemplate, ); } @@ -201,6 +204,7 @@ class AvailabilityBreakSelectionDialog extends StatefulWidget { required AvailabilityOptions options, required String userId, required AvailabilityService service, + required PopHandler popHandler, required bool editingTemplate, BreakViewModel? initialBreak, }) async => @@ -217,6 +221,7 @@ class AvailabilityBreakSelectionDialog extends StatefulWidget { userId: userId, options: options, service: service, + popHandler: popHandler, child: AvailabilityBreakSelectionDialog( initialBreak: initialBreak, editingTemplate: editingTemplate, diff --git a/packages/flutter_availability/lib/src/userstories.dart b/packages/flutter_availability/lib/src/userstories.dart index 8d1bf9a..88009d3 100644 --- a/packages/flutter_availability/lib/src/userstories.dart +++ b/packages/flutter_availability/lib/src/userstories.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_availability/src/config/availability_options.dart"; import "package:flutter_availability/src/routes.dart"; import "package:flutter_availability/src/service/availability_service.dart"; +import "package:flutter_availability/src/service/pop_handler.dart"; import "package:flutter_availability/src/util/scope.dart"; /// This pushes the availability user story to the navigator stack. @@ -58,15 +59,21 @@ class _AvailabilityUserStoryState extends State { dataInterface: widget.options.dataInterface, ); + late final PopHandler _popHandler = PopHandler(); + @override Widget build(BuildContext context) => AvailabilityScope( userId: widget.userId, options: widget.options, service: _service, - child: Navigator( - onGenerateInitialRoutes: (state, route) => [ - homePageRoute(widget.onExit ?? () {}), - ], + popHandler: _popHandler, + child: NavigatorPopHandler( + onPop: _popHandler.handlePop, + child: Navigator( + onGenerateInitialRoutes: (state, route) => [ + homePageRoute(widget.onExit ?? () {}), + ], + ), ), ); diff --git a/packages/flutter_availability/lib/src/util/scope.dart b/packages/flutter_availability/lib/src/util/scope.dart index 7fd92b4..f21ee00 100644 --- a/packages/flutter_availability/lib/src/util/scope.dart +++ b/packages/flutter_availability/lib/src/util/scope.dart @@ -1,6 +1,7 @@ import "package:flutter/widgets.dart"; import "package:flutter_availability/src/config/availability_options.dart"; import "package:flutter_availability/src/service/availability_service.dart"; +import "package:flutter_availability/src/service/pop_handler.dart"; /// class AvailabilityScope extends InheritedWidget { @@ -9,6 +10,7 @@ class AvailabilityScope extends InheritedWidget { required this.userId, required this.options, required this.service, + required this.popHandler, required super.child, super.key, }); @@ -22,6 +24,9 @@ class AvailabilityScope extends InheritedWidget { /// final AvailabilityService service; + /// + final PopHandler popHandler; + @override bool updateShouldNotify(AvailabilityScope oldWidget) => oldWidget.userId != userId || options != options;