From e3474e779b863acbb0854a18c0bf8ae5f5426d73 Mon Sep 17 00:00:00 2001 From: Freek van de Ven Date: Wed, 10 Jul 2024 16:07:49 +0200 Subject: [PATCH] feat: add default confirmation dialog --- .../lib/src/config/availability_options.dart | 17 ++++ .../src/config/availability_translations.dart | 10 ++ .../widgets/default_confirmation_dialog.dart | 93 +++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 packages/flutter_availability/lib/src/ui/widgets/default_confirmation_dialog.dart diff --git a/packages/flutter_availability/lib/src/config/availability_options.dart b/packages/flutter_availability/lib/src/config/availability_options.dart index 0748e82..8334954 100644 --- a/packages/flutter_availability/lib/src/config/availability_options.dart +++ b/packages/flutter_availability/lib/src/config/availability_options.dart @@ -5,6 +5,7 @@ import "package:flutter_availability/src/config/availability_translations.dart"; import "package:flutter_availability/src/service/local_data_interface.dart"; import "package:flutter_availability/src/ui/widgets/default_base_screen.dart"; import "package:flutter_availability/src/ui/widgets/default_buttons.dart"; +import "package:flutter_availability/src/ui/widgets/default_confirmation_dialog.dart"; import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; /// Class that holds all options for the availability userstory @@ -19,6 +20,7 @@ class AvailabilityOptions { this.spacing = const AvailabilitySpacing(), this.textStyles = const AvailabilityTextStyles(), this.colors = const AvailabilityColors(), + this.confirmationDialogBuilder = DefaultConfirmationDialog.builder, this.timePickerBuilder, this.loadingIndicatorBuilder = defaultLoader, AvailabilityDataInterface? dataInterface, @@ -55,6 +57,11 @@ class AvailabilityOptions { /// The colors used in the userstory final AvailabilityColors colors; + /// A way to provide your own confirmation dialog implementation + /// If not provided the [DefaultConfirmationDialog.builder] will be used + /// which shows a modal bottom sheet with a title and a description + final ConfirmationDialogBuilder confirmationDialogBuilder; + /// A way to provide your own time picker implementation or customize /// the default time picker final TimePickerBuilder? timePickerBuilder; @@ -165,6 +172,16 @@ typedef TimePickerBuilder = Future Function( TimeOfDay? initialTime, ); +/// Builder definition for providing a custom confirmation dialog +/// +/// The function should return a [Future] that resolves to `true` if the user +/// confirms. +typedef ConfirmationDialogBuilder = Future Function( + BuildContext context, { + required String title, + required String description, +}); + /// Builder definition for providing a loading indicator implementation Widget defaultLoader( BuildContext context, diff --git a/packages/flutter_availability/lib/src/config/availability_translations.dart b/packages/flutter_availability/lib/src/config/availability_translations.dart index 879f2c7..ce8d07d 100644 --- a/packages/flutter_availability/lib/src/config/availability_translations.dart +++ b/packages/flutter_availability/lib/src/config/availability_translations.dart @@ -45,6 +45,8 @@ class AvailabilityTranslations { required this.pauseDialogPeriodDescription, required this.saveButton, required this.addButton, + required this.confirmText, + required this.cancelText, required this.timeFormatter, required this.dayMonthFormatter, required this.periodFormatter, @@ -91,6 +93,8 @@ class AvailabilityTranslations { "Select between which times you want to take a break", this.saveButton = "Save", this.addButton = "Add", + this.confirmText = "Yes", + this.cancelText = "No", this.dayMonthFormatter = _defaultDayMonthFormatter, this.periodFormatter = _defaultPeriodFormatter, this.monthYearFormatter = _defaultMonthYearFormatter, @@ -201,6 +205,12 @@ class AvailabilityTranslations { /// The text on the add button final String addButton; + /// The text on the confirm button in the confirmation dialog + final String confirmText; + + /// The text on the cancel button in the confirmation dialog + final String cancelText; + /// Gets the day and month formatted as a string /// /// The default implementation is `Dayname day monthname` in english diff --git a/packages/flutter_availability/lib/src/ui/widgets/default_confirmation_dialog.dart b/packages/flutter_availability/lib/src/ui/widgets/default_confirmation_dialog.dart new file mode 100644 index 0000000..857c563 --- /dev/null +++ b/packages/flutter_availability/lib/src/ui/widgets/default_confirmation_dialog.dart @@ -0,0 +1,93 @@ +import "package:flutter/material.dart"; +import "package:flutter_availability/src/util/scope.dart"; + +/// Default confirmation dialog that uses a modal bottom sheet, it has a title, +/// a description and it gets a secondary and primary button to confirm or +/// cancel the action +class DefaultConfirmationDialog extends StatelessWidget { + /// + const DefaultConfirmationDialog({ + required this.title, + required this.description, + super.key, + }); + + /// Shows a confirmation dialog with a title and a description + static Future builder( + BuildContext context, { + required String title, + required String description, + }) => + showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder(), + builder: (context) => DefaultConfirmationDialog( + title: title, + description: description, + ), + ); + + /// The title shown in the dialog + final String title; + + /// The description shown in the dialog + final String description; + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var textTheme = theme.textTheme; + var availabilityScope = AvailabilityScope.of(context); + var options = availabilityScope.options; + var spacing = options.spacing; + var translations = options.translations; + + void onCancel() => Navigator.of(context).pop(false); + void onConfirm() => Navigator.of(context).pop(true); + + return Padding( + padding: EdgeInsets.only( + top: 40, + left: spacing.sidePadding, + right: spacing.sidePadding, + bottom: spacing.bottomButtonPadding, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: textTheme.titleMedium, + ), + const SizedBox(height: 16), + Text( + description, + style: textTheme.bodyLarge, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: options.secondaryButtonBuilder( + context, + onCancel, + Text(translations.cancelText), + ), + ), + const SizedBox(width: 20), + Expanded( + child: options.primaryButtonBuilder( + context, + onConfirm, + Text(translations.confirmText), + ), + ), + ], + ), + ], + ), + ); + } +}