mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 13:13:44 +02:00
feat: add week template overview
This commit is contained in:
parent
5b54111850
commit
c7ea82677c
3 changed files with 214 additions and 0 deletions
|
@ -125,6 +125,7 @@ class AvailabilityColors {
|
||||||
this.outsideMonthTextColor,
|
this.outsideMonthTextColor,
|
||||||
this.textDarkColor,
|
this.textDarkColor,
|
||||||
this.textLightColor,
|
this.textLightColor,
|
||||||
|
this.templateWeekOverviewBackgroundColor,
|
||||||
this.templateColors = const [
|
this.templateColors = const [
|
||||||
Color(0xFF9bb8f2),
|
Color(0xFF9bb8f2),
|
||||||
Color(0xFF4b77d0),
|
Color(0xFF4b77d0),
|
||||||
|
@ -160,6 +161,11 @@ class AvailabilityColors {
|
||||||
/// If not provided the text color will be the theme's text color
|
/// If not provided the text color will be the theme's text color
|
||||||
final Color? textDarkColor;
|
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
|
/// The colors that are used for the templates
|
||||||
final List<Color> templateColors;
|
final List<Color> templateColors;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,13 @@ class AvailabilityTranslations {
|
||||||
required this.templateTitleHintText,
|
required this.templateTitleHintText,
|
||||||
required this.templateTitleLabel,
|
required this.templateTitleLabel,
|
||||||
required this.templateColorLabel,
|
required this.templateColorLabel,
|
||||||
|
required this.weekTemplateOverviewTitle,
|
||||||
|
required this.pause,
|
||||||
|
required this.unavailable,
|
||||||
required this.time,
|
required this.time,
|
||||||
required this.timeSeparator,
|
required this.timeSeparator,
|
||||||
required this.timeMinutes,
|
required this.timeMinutes,
|
||||||
|
required this.timeMinutesShort,
|
||||||
required this.templateTimeLabel,
|
required this.templateTimeLabel,
|
||||||
required this.pauseSectionTitle,
|
required this.pauseSectionTitle,
|
||||||
required this.pauseSectionOptional,
|
required this.pauseSectionOptional,
|
||||||
|
@ -105,9 +109,13 @@ class AvailabilityTranslations {
|
||||||
this.templateTitleHintText = "What do you want to call this template?",
|
this.templateTitleHintText = "What do you want to call this template?",
|
||||||
this.templateTitleLabel = "Template Title",
|
this.templateTitleLabel = "Template Title",
|
||||||
this.templateColorLabel = "Colorlabel",
|
this.templateColorLabel = "Colorlabel",
|
||||||
|
this.weekTemplateOverviewTitle = "Overview availability",
|
||||||
|
this.pause = "Pause",
|
||||||
|
this.unavailable = "Unavailable",
|
||||||
this.time = "Time",
|
this.time = "Time",
|
||||||
this.timeSeparator = "to",
|
this.timeSeparator = "to",
|
||||||
this.timeMinutes = "minutes",
|
this.timeMinutes = "minutes",
|
||||||
|
this.timeMinutesShort = "min",
|
||||||
this.templateTimeLabel = "When are you available?",
|
this.templateTimeLabel = "When are you available?",
|
||||||
this.pauseSectionTitle = "Add a pause",
|
this.pauseSectionTitle = "Add a pause",
|
||||||
this.pauseSectionOptional = "(Optional)",
|
this.pauseSectionOptional = "(Optional)",
|
||||||
|
@ -229,6 +237,15 @@ class AvailabilityTranslations {
|
||||||
/// The title above the color selection for templates
|
/// The title above the color selection for templates
|
||||||
final String templateColorLabel;
|
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
|
/// The title for time sections
|
||||||
final String time;
|
final String time;
|
||||||
|
|
||||||
|
@ -238,6 +255,9 @@ class AvailabilityTranslations {
|
||||||
/// The text used for minutes
|
/// The text used for minutes
|
||||||
final String timeMinutes;
|
final String timeMinutes;
|
||||||
|
|
||||||
|
/// The text used for minutes in a short form
|
||||||
|
final String timeMinutesShort;
|
||||||
|
|
||||||
/// The label for the template time input
|
/// The label for the template time input
|
||||||
final String templateTimeLabel;
|
final String templateTimeLabel;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue