mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 13:13:44 +02:00
feat: add template legend on the calendar screen
This commit is contained in:
parent
a22c8ed69e
commit
63caa27f0a
3 changed files with 226 additions and 3 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<AvailabilityOverview> {
|
|||
},
|
||||
);
|
||||
|
||||
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
|
||||
|
|
|
@ -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<AvailabilityTemplateModel> templates;
|
||||
|
||||
/// Callback for when the user wants to navigate to the overview of templates
|
||||
final VoidCallback onViewTemplates;
|
||||
|
||||
@override
|
||||
State<TemplateLegend> createState() => _TemplateLegendState();
|
||||
}
|
||||
|
||||
class _TemplateLegendState extends State<TemplateLegend> {
|
||||
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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue