mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 05:03: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.appbarTitle,
|
||||||
required this.editAvailabilityButton,
|
required this.editAvailabilityButton,
|
||||||
required this.templateLegendTitle,
|
required this.templateLegendTitle,
|
||||||
|
required this.templateSelectionLabel,
|
||||||
required this.overviewScreenTitle,
|
required this.overviewScreenTitle,
|
||||||
required this.createTemplateButton,
|
required this.createTemplateButton,
|
||||||
required this.monthYearFormatter,
|
required this.monthYearFormatter,
|
||||||
|
@ -26,6 +27,7 @@ class AvailabilityTranslations {
|
||||||
this.appbarTitle = "Availability",
|
this.appbarTitle = "Availability",
|
||||||
this.editAvailabilityButton = "Edit availability",
|
this.editAvailabilityButton = "Edit availability",
|
||||||
this.templateLegendTitle = "Templates",
|
this.templateLegendTitle = "Templates",
|
||||||
|
this.templateSelectionLabel = "Selected day(s)",
|
||||||
this.createTemplateButton = "Create a new template",
|
this.createTemplateButton = "Create a new template",
|
||||||
this.overviewScreenTitle = "Availability",
|
this.overviewScreenTitle = "Availability",
|
||||||
this.monthYearFormatter = _defaultMonthYearFormatter,
|
this.monthYearFormatter = _defaultMonthYearFormatter,
|
||||||
|
@ -41,6 +43,9 @@ class AvailabilityTranslations {
|
||||||
/// The title for the legend template section on the overview screen
|
/// The title for the legend template section on the overview screen
|
||||||
final String templateLegendTitle;
|
final String templateLegendTitle;
|
||||||
|
|
||||||
|
/// The text for the selected days in the template legend
|
||||||
|
final String templateSelectionLabel;
|
||||||
|
|
||||||
/// The title on the overview screen
|
/// The title on the overview screen
|
||||||
final String overviewScreenTitle;
|
final String overviewScreenTitle;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/calendar.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/src/util/scope.dart";
|
||||||
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
|
||||||
///
|
///
|
||||||
class AvailabilityOverview extends StatefulWidget {
|
class AvailabilityOverview extends StatefulWidget {
|
||||||
|
@ -58,9 +60,35 @@ class _AvailabilityOverviewState extends State<AvailabilityOverview> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const templateLegend = SizedBox(
|
var templateLegend = TemplateLegend(
|
||||||
height: 40,
|
onViewTemplates: widget.onViewTemplates,
|
||||||
child: Placeholder(),
|
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
|
// 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