feat: add week template overview

This commit is contained in:
Freek van de Ven 2024-07-16 10:17:45 +02:00 committed by FlutterJoey
parent 5b54111850
commit c7ea82677c
3 changed files with 214 additions and 0 deletions

View file

@ -125,6 +125,7 @@ class AvailabilityColors {
this.outsideMonthTextColor,
this.textDarkColor,
this.textLightColor,
this.templateWeekOverviewBackgroundColor,
this.templateColors = const [
Color(0xFF9bb8f2),
Color(0xFF4b77d0),
@ -160,6 +161,11 @@ class AvailabilityColors {
/// If not provided the text color will be the theme's text color
final Color? textDarkColor;
/// The color of the background in the template week overview that creates a
/// layered effect by interchanging a color and a transparent color
/// If not provided the color will be the theme's [ColorScheme.surface]
final Color? templateWeekOverviewBackgroundColor;
/// The colors that are used for the templates
final List<Color> templateColors;
}

View file

@ -43,9 +43,13 @@ class AvailabilityTranslations {
required this.templateTitleHintText,
required this.templateTitleLabel,
required this.templateColorLabel,
required this.weekTemplateOverviewTitle,
required this.pause,
required this.unavailable,
required this.time,
required this.timeSeparator,
required this.timeMinutes,
required this.timeMinutesShort,
required this.templateTimeLabel,
required this.pauseSectionTitle,
required this.pauseSectionOptional,
@ -105,9 +109,13 @@ class AvailabilityTranslations {
this.templateTitleHintText = "What do you want to call this template?",
this.templateTitleLabel = "Template Title",
this.templateColorLabel = "Colorlabel",
this.weekTemplateOverviewTitle = "Overview availability",
this.pause = "Pause",
this.unavailable = "Unavailable",
this.time = "Time",
this.timeSeparator = "to",
this.timeMinutes = "minutes",
this.timeMinutesShort = "min",
this.templateTimeLabel = "When are you available?",
this.pauseSectionTitle = "Add a pause",
this.pauseSectionOptional = "(Optional)",
@ -229,6 +237,15 @@ class AvailabilityTranslations {
/// The title above the color selection for templates
final String templateColorLabel;
/// The title for the week overview section
final String weekTemplateOverviewTitle;
/// The label used for pause
final String pause;
/// The label used for unavailable
final String unavailable;
/// The title for time sections
final String time;
@ -238,6 +255,9 @@ class AvailabilityTranslations {
/// The text used for minutes
final String timeMinutes;
/// The text used for minutes in a short form
final String timeMinutesShort;
/// The label for the template time input
final String templateTimeLabel;

View file

@ -0,0 +1,188 @@
import "package:flutter/material.dart";
import "package:flutter_availability/src/ui/models/view_template_daydata.dart";
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
import "package:flutter_availability/src/util/scope.dart";
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
/// Shows an overview of the template of a week before saving it
class TemplateWeekOverview extends StatelessWidget {
///
const TemplateWeekOverview({
required this.template,
super.key,
});
/// The template to show
final AvailabilityTemplateModel template;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var textTheme = theme.textTheme;
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
var translations = options.translations;
var colors = options.colors;
var dayNames = getDaysOfTheWeekAsStrings(translations, context);
var templateData = template.templateData as WeekTemplateData;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
translations.weekTemplateOverviewTitle,
style: textTheme.titleMedium,
),
const SizedBox(height: 8),
DecoratedBox(
decoration: BoxDecoration(
color: colors.templateWeekOverviewBackgroundColor ??
theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: theme.dividerColor,
),
),
child: Column(
children: [
for (var day in WeekDay.values) ...[
_TemplateDayDetailRow(
dayName: dayNames[day.index],
dayData: templateData.data.containsKey(day)
? ViewDayTemplateData.fromDayTemplateData(
templateData.data[day]!,
)
: null,
isOdd: day.index.isOdd,
),
],
],
),
),
],
);
}
}
class _TemplateDayDetailRow extends StatelessWidget {
const _TemplateDayDetailRow({
required this.dayName,
required this.dayData,
required this.isOdd,
});
/// The name of the day
final String dayName;
/// There odd rows do not have a background color
/// This causes a layered effect
final bool isOdd;
/// The data of the day
final ViewDayTemplateData? dayData;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var textTheme = theme.textTheme;
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
var translations = options.translations;
var startTime = dayData?.startTime;
var endTime = dayData?.endTime;
var dayHasAvailability = startTime != null && endTime != null;
String? dayPeriod;
if (dayHasAvailability) {
dayPeriod = "${translations.timeFormatter(context, startTime)} - "
"${translations.timeFormatter(context, endTime)}";
} else {
dayPeriod = translations.unavailable;
}
var breaks = dayData?.breaks ?? <AvailabilityBreakModel>[];
BoxDecoration? boxDecoration;
if (isOdd) {
boxDecoration = BoxDecoration(
color: Colors.white,
border: Border(
left: BorderSide(
color: theme.dividerColor,
),
right: BorderSide(
color: theme.dividerColor,
),
),
);
}
return Container(
decoration: boxDecoration,
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(dayName, style: textTheme.bodyLarge),
Text(dayPeriod, style: textTheme.bodyLarge),
],
),
// for each break add a line
for (var dayBreak in breaks) ...[
const SizedBox(height: 4),
_TemplateDayDetailPauseRow(dayBreak: dayBreak),
],
],
),
);
}
}
class _TemplateDayDetailPauseRow extends StatelessWidget {
const _TemplateDayDetailPauseRow({
required this.dayBreak,
});
final AvailabilityBreakModel dayBreak;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var textTheme = theme.textTheme;
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
var translations = options.translations;
var startTime = TimeOfDay.fromDateTime(dayBreak.startTime);
var endTime = TimeOfDay.fromDateTime(dayBreak.endTime);
var startTimeString = translations.timeFormatter(context, startTime);
var endTimeString = translations.timeFormatter(context, endTime);
var pausePeriod =
"$startTimeString - $endTimeString (${dayBreak.duration.inMinutes} "
"${translations.timeMinutesShort})";
var pauseTextStyle = textTheme.bodyMedium?.copyWith(
fontStyle: FontStyle.italic,
);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 16),
child: Text(
translations.pause,
style: pauseTextStyle,
),
),
Text(
pausePeriod,
style: pauseTextStyle,
),
],
);
}
}