diff --git a/packages/flutter_availability/lib/src/config/availability_translations.dart b/packages/flutter_availability/lib/src/config/availability_translations.dart index 4dac92b..5069e45 100644 --- a/packages/flutter_availability/lib/src/config/availability_translations.dart +++ b/packages/flutter_availability/lib/src/config/availability_translations.dart @@ -14,6 +14,7 @@ class AvailabilityTranslations { required this.appbarTitle, required this.editAvailabilityButton, required this.templateLegendTitle, + required this.templateSelectionLabel, required this.overviewScreenTitle, required this.createTemplateButton, required this.monthYearFormatter, @@ -26,6 +27,7 @@ class AvailabilityTranslations { this.appbarTitle = "Availability", this.editAvailabilityButton = "Edit availability", this.templateLegendTitle = "Templates", + this.templateSelectionLabel = "Selected day(s)", this.createTemplateButton = "Create a new template", this.overviewScreenTitle = "Availability", this.monthYearFormatter = _defaultMonthYearFormatter, @@ -41,6 +43,9 @@ class AvailabilityTranslations { /// The title for the legend template section on the overview screen final String templateLegendTitle; + /// The text for the selected days in the template legend + final String templateSelectionLabel; + /// The title on the overview screen final String overviewScreenTitle; 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 acedbe3..4f59a2f 100644 --- a/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart +++ b/packages/flutter_availability/lib/src/ui/screens/availability_overview.dart @@ -1,6 +1,8 @@ import "package:flutter/material.dart"; import "package:flutter_availability/src/ui/widgets/calendar.dart"; +import "package:flutter_availability/src/ui/widgets/template_legend.dart"; import "package:flutter_availability/src/util/scope.dart"; +import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; /// class AvailabilityOverview extends StatefulWidget { @@ -58,9 +60,35 @@ class _AvailabilityOverviewState extends State { }, ); - const templateLegend = SizedBox( - height: 40, - child: Placeholder(), + var templateLegend = TemplateLegend( + onViewTemplates: widget.onViewTemplates, + templates: [ + for (var template in <(Color, String)>[ + (Colors.red, "Template 1"), + (Colors.blue, "Template 2"), + // do 10 more + (Colors.green, "Template 3"), + (Colors.yellow, "Template 4"), + (Colors.purple, "Template 5"), + (Colors.orange, "Template 6"), + (Colors.teal, "Template 7"), + (Colors.pink, "Template 8"), + (Colors.indigo, "Template 9"), + ]) ...[ + AvailabilityTemplateModel( + userId: "1", + id: "1", + name: template.$2, + templateType: AvailabilityTemplateType.day, + templateData: DayTemplateData( + startTime: DateTime.now(), + endTime: DateTime.now(), + breaks: [], + ), + color: template.$1.value, + ), + ], + ], ); // if there is no range selected we want to disable the button diff --git a/packages/flutter_availability/lib/src/ui/widgets/template_legend.dart b/packages/flutter_availability/lib/src/ui/widgets/template_legend.dart new file mode 100644 index 0000000..7a74095 --- /dev/null +++ b/packages/flutter_availability/lib/src/ui/widgets/template_legend.dart @@ -0,0 +1,190 @@ +import "package:flutter/material.dart"; +import "package:flutter_availability/src/util/scope.dart"; +import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart"; + +/// This shows all the templates of a given month and an option to navigate to +/// the template overview +class TemplateLegend extends StatefulWidget { + /// + const TemplateLegend({ + required this.templates, + required this.onViewTemplates, + super.key, + }); + + /// + final List templates; + + /// Callback for when the user wants to navigate to the overview of templates + final VoidCallback onViewTemplates; + + @override + State createState() => _TemplateLegendState(); +} + +class _TemplateLegendState extends State { + bool _templateDrawerOpen = false; + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var textTheme = theme.textTheme; + var colorScheme = theme.colorScheme; + var availabilityScope = AvailabilityScope.of(context); + var options = availabilityScope.options; + var colors = options.colors; + var translations = options.translations; + + var templatesAvailable = widget.templates.isNotEmpty; + + void onDrawerHeaderClick() { + if (!templatesAvailable) { + return; + } + setState(() { + _templateDrawerOpen = !_templateDrawerOpen; + }); + } + + var createNewTemplateButton = GestureDetector( + onTap: () => widget.onViewTemplates(), + child: ColoredBox( + color: Colors.transparent, + child: Row( + children: [ + const SizedBox(width: 12), + const Icon(Icons.add, size: 20), + const SizedBox(width: 6), + Text( + translations.createTemplateButton, + style: textTheme.bodyLarge, + ), + ], + ), + ), + ); + return Column( + children: [ + GestureDetector( + onTap: onDrawerHeaderClick, + child: ColoredBox( + color: Colors.transparent, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + translations.templateLegendTitle, + style: textTheme.titleMedium, + ), + // a button to open a drawer with all the templates + if (templatesAvailable) ...[ + Icon( + _templateDrawerOpen + ? Icons.arrow_drop_up + : Icons.arrow_drop_down, + ), + ], + ], + ), + ), + ), + const SizedBox(height: 4), + if (_templateDrawerOpen) ...[ + // show a container with all the templates with a max height and after + // that scrollable but as small as possible + Container( + decoration: BoxDecoration( + border: Border.all( + color: theme.colorScheme.onSurface, + width: 1, + ), + ), + padding: const EdgeInsets.only(right: 2), + child: Column( + children: [ + Container( + constraints: const BoxConstraints( + maxHeight: 100, + ), + child: Scrollbar( + thumbVisibility: true, + trackVisibility: true, + thickness: 2, + child: ListView.builder( + shrinkWrap: true, + itemCount: widget.templates.length + 1, + itemBuilder: (context, index) { + if (index == 0) { + return _TemplateLegendItem( + name: translations.templateSelectionLabel, + backgroundColor: colors.selectedDayColor ?? + colorScheme.primaryFixedDim, + borderColor: colorScheme.primary, + ); + } + var template = widget.templates[index - 1]; + return _TemplateLegendItem( + name: template.name, + backgroundColor: Color(template.color), + ); + }, + ), + ), + ), + const SizedBox(height: 4), + createNewTemplateButton, + const SizedBox(height: 8), + ], + ), + ), + ] else ...[ + const Divider(height: 1), + ], + if (!templatesAvailable) ...[ + const SizedBox(height: 12), + createNewTemplateButton, + ], + ], + ); + } +} + +class _TemplateLegendItem extends StatelessWidget { + const _TemplateLegendItem({ + required this.name, + required this.backgroundColor, + this.borderColor, + }); + + final String name; + + final Color backgroundColor; + + final Color? borderColor; + + @override + Widget build(BuildContext context) => Padding( + padding: const EdgeInsets.only( + top: 10, + left: 12, + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(5), + border: Border.all( + color: borderColor ?? Colors.transparent, + ), + ), + width: 20, + height: 20, + ), + const SizedBox(width: 6), + Text(name, style: Theme.of(context).textTheme.bodyLarge), + ], + ), + ); +}