fix: add NavigatorPopHandler with a custom PopHandler class for handling backarrow presses in the userstory

This commit is contained in:
Freek van de Ven 2024-07-25 14:51:10 +02:00
parent 26d2eb150a
commit c20a1a603c
9 changed files with 85 additions and 14 deletions

View file

@ -0,0 +1,24 @@
import "package:flutter/material.dart";
///
class PopHandler {
/// Constructor
PopHandler();
final List<VoidCallback> _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();
}
}

View file

@ -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<void> onSave() async {
@ -180,7 +186,7 @@ class _AvailabilitiesModificationScreenState
}
}
class _AvailabilitiesModificationScreenLayout extends StatelessWidget {
class _AvailabilitiesModificationScreenLayout extends HookWidget {
const _AvailabilitiesModificationScreenLayout({
required this.dateRange,
required this.clearAvailability,

View file

@ -17,7 +17,7 @@ class AvailabilityOverview extends StatefulHookWidget {
});
/// Callback for when the user gives an availability range
final void Function(
final Future<void> Function(
DateTimeRange range,
List<AvailabilityWithTemplate> selectedAvailabilities,
) onEditDateRange;
@ -49,6 +49,11 @@ class _AvailabilityOverviewState extends State<AvailabilityOverview> {
[_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<AvailabilityOverview> {
VoidCallback? onButtonPress;
if (_selectedRange != null) {
onButtonPress = () {
widget.onEditDateRange(
onButtonPress = () async {
await widget.onEditDateRange(
_selectedRange!,
selectedAvailabilities,
);
setState(() {
_selectedRange = null;
});
if (mounted) {
setState(() {
_selectedRange = null;
});
}
};
}

View file

@ -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<void> onDeletePressed() async {
var isConfirmed = await options.confirmationDialogBuilder(
context,

View file

@ -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 ?? <AvailabilityTemplateModel>[];
var weekTemplates =

View file

@ -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,

View file

@ -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<BreakViewModel?> 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,

View file

@ -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<AvailabilityUserStory> {
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 ?? () {}),
],
),
),
);

View file

@ -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;