mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 21:23:44 +02:00
feat: add week template day selector
This commit is contained in:
parent
92703d536d
commit
5b54111850
3 changed files with 197 additions and 5 deletions
|
@ -38,6 +38,8 @@ class AvailabilityTranslations {
|
||||||
required this.createWeekTemplate,
|
required this.createWeekTemplate,
|
||||||
required this.deleteTemplateButton,
|
required this.deleteTemplateButton,
|
||||||
required this.dayTemplateTitle,
|
required this.dayTemplateTitle,
|
||||||
|
required this.weekTemplateTitle,
|
||||||
|
required this.weekTemplateDayTitle,
|
||||||
required this.templateTitleHintText,
|
required this.templateTitleHintText,
|
||||||
required this.templateTitleLabel,
|
required this.templateTitleLabel,
|
||||||
required this.templateColorLabel,
|
required this.templateColorLabel,
|
||||||
|
@ -61,6 +63,7 @@ class AvailabilityTranslations {
|
||||||
required this.periodFormatter,
|
required this.periodFormatter,
|
||||||
required this.monthYearFormatter,
|
required this.monthYearFormatter,
|
||||||
required this.weekDayAbbreviatedFormatter,
|
required this.weekDayAbbreviatedFormatter,
|
||||||
|
required this.weekDayFormatter,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// AvailabilityTranslations constructor where everything is optional.
|
/// AvailabilityTranslations constructor where everything is optional.
|
||||||
|
@ -97,6 +100,8 @@ class AvailabilityTranslations {
|
||||||
this.createWeekTemplate = "Create week template",
|
this.createWeekTemplate = "Create week template",
|
||||||
this.deleteTemplateButton = "Delete template",
|
this.deleteTemplateButton = "Delete template",
|
||||||
this.dayTemplateTitle = "Day template",
|
this.dayTemplateTitle = "Day template",
|
||||||
|
this.weekTemplateTitle = "Week template",
|
||||||
|
this.weekTemplateDayTitle = "When",
|
||||||
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",
|
||||||
|
@ -123,6 +128,7 @@ class AvailabilityTranslations {
|
||||||
this.periodFormatter = _defaultPeriodFormatter,
|
this.periodFormatter = _defaultPeriodFormatter,
|
||||||
this.monthYearFormatter = _defaultMonthYearFormatter,
|
this.monthYearFormatter = _defaultMonthYearFormatter,
|
||||||
this.weekDayAbbreviatedFormatter = _defaultWeekDayAbbreviatedFormatter,
|
this.weekDayAbbreviatedFormatter = _defaultWeekDayAbbreviatedFormatter,
|
||||||
|
this.weekDayFormatter = _defaultWeekDayFormatter,
|
||||||
this.timeFormatter = _defaultTimeFormatter,
|
this.timeFormatter = _defaultTimeFormatter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -208,6 +214,12 @@ class AvailabilityTranslations {
|
||||||
/// The title for the day template edit screen
|
/// The title for the day template edit screen
|
||||||
final String dayTemplateTitle;
|
final String dayTemplateTitle;
|
||||||
|
|
||||||
|
/// The title for the week template edit screen
|
||||||
|
final String weekTemplateTitle;
|
||||||
|
|
||||||
|
/// The title above the section with the week template days
|
||||||
|
final String weekTemplateDayTitle;
|
||||||
|
|
||||||
/// The hint text for the template title input field
|
/// The hint text for the template title input field
|
||||||
final String templateTitleHintText;
|
final String templateTitleHintText;
|
||||||
|
|
||||||
|
@ -286,12 +298,20 @@ class AvailabilityTranslations {
|
||||||
/// the weekday in english
|
/// the weekday in english
|
||||||
final String Function(BuildContext, DateTime) weekDayAbbreviatedFormatter;
|
final String Function(BuildContext, DateTime) weekDayAbbreviatedFormatter;
|
||||||
|
|
||||||
|
/// Gets the weekday formatted as a string
|
||||||
|
///
|
||||||
|
/// The default implementation is the full name of the weekday in english
|
||||||
|
final String Function(BuildContext, DateTime) weekDayFormatter;
|
||||||
|
|
||||||
/// Get the time formatted as a string
|
/// Get the time formatted as a string
|
||||||
///
|
///
|
||||||
/// The default implementation is `HH:mm`
|
/// The default implementation is `HH:mm`
|
||||||
final String Function(BuildContext, TimeOfDay) timeFormatter;
|
final String Function(BuildContext, TimeOfDay) timeFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _defaultWeekDayFormatter(BuildContext context, DateTime date) =>
|
||||||
|
_getDayName(date.weekday);
|
||||||
|
|
||||||
String _defaultTimeFormatter(BuildContext context, TimeOfDay time) =>
|
String _defaultTimeFormatter(BuildContext context, TimeOfDay time) =>
|
||||||
"${time.hour.toString().padLeft(2, '0')}:"
|
"${time.hour.toString().padLeft(2, '0')}:"
|
||||||
"${time.minute.toString().padLeft(2, '0')}";
|
"${time.minute.toString().padLeft(2, '0')}";
|
||||||
|
|
|
@ -37,11 +37,8 @@ class CalendarGrid extends StatelessWidget {
|
||||||
var calendarDays =
|
var calendarDays =
|
||||||
_generateCalendarDays(month, days, selectedRange, colors, colorScheme);
|
_generateCalendarDays(month, days, selectedRange, colors, colorScheme);
|
||||||
|
|
||||||
// get the names of the days of the week
|
var dayNames =
|
||||||
var dayNames = List.generate(7, (index) {
|
getDaysOfTheWeekAsAbbreviatedStrings(translations, context);
|
||||||
var day = DateTime(2024, 7, 8 + index); // this is a monday
|
|
||||||
return translations.weekDayAbbreviatedFormatter(context, day);
|
|
||||||
});
|
|
||||||
|
|
||||||
var calendarDaysRow = Row(
|
var calendarDaysRow = Row(
|
||||||
children: List.generate(13, (index) {
|
children: List.generate(13, (index) {
|
||||||
|
@ -122,6 +119,31 @@ class CalendarGrid extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the days of the week as abbreviated strings
|
||||||
|
/// The first day of the week is monday
|
||||||
|
List<String> getDaysOfTheWeekAsAbbreviatedStrings(
|
||||||
|
AvailabilityTranslations translations,
|
||||||
|
BuildContext context,
|
||||||
|
) {
|
||||||
|
var dayNames = List.generate(7, (index) {
|
||||||
|
var day = DateTime(2024, 7, 8 + index); // this is a monday
|
||||||
|
return translations.weekDayAbbreviatedFormatter(context, day);
|
||||||
|
});
|
||||||
|
return dayNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the days of the week as strings
|
||||||
|
List<String> getDaysOfTheWeekAsStrings(
|
||||||
|
AvailabilityTranslations translations,
|
||||||
|
BuildContext context,
|
||||||
|
) {
|
||||||
|
var dayNames = List.generate(7, (index) {
|
||||||
|
var day = DateTime(2024, 7, 8 + index); // this is a monday
|
||||||
|
return translations.weekDayFormatter(context, day);
|
||||||
|
});
|
||||||
|
return dayNames;
|
||||||
|
}
|
||||||
|
|
||||||
/// A Special day in the calendar that needs to be displayed differently
|
/// A Special day in the calendar that needs to be displayed differently
|
||||||
class CalendarDay {
|
class CalendarDay {
|
||||||
///
|
///
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
// ignore_for_file: avoid_positional_boolean_parameters
|
||||||
|
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
|
||||||
|
import "package:flutter_availability/src/util/scope.dart";
|
||||||
|
|
||||||
|
/// A widget for selecting a day of the week
|
||||||
|
class TemplateWeekDaySelection extends StatefulWidget {
|
||||||
|
/// Creates a [TemplateWeekDaySelection]
|
||||||
|
const TemplateWeekDaySelection({
|
||||||
|
required this.onDaySelected,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Callback for when a day is selected
|
||||||
|
final void Function(int) onDaySelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TemplateWeekDaySelection> createState() =>
|
||||||
|
_TemplateWeekDaySelectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TemplateWeekDaySelectionState extends State<TemplateWeekDaySelection> {
|
||||||
|
int _selectedDayIndex = 0;
|
||||||
|
|
||||||
|
@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 days = getDaysOfTheWeekAsAbbreviatedStrings(translations, context);
|
||||||
|
|
||||||
|
void onDaySelected(bool selected, int index) {
|
||||||
|
if (!selected) return;
|
||||||
|
widget.onDaySelected(index);
|
||||||
|
setState(() {
|
||||||
|
_selectedDayIndex = index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(translations.weekTemplateDayTitle, style: textTheme.titleMedium),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
SizedBox(
|
||||||
|
height: 72,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
for (var day in days) ...[
|
||||||
|
_DaySelectionCard(
|
||||||
|
day: day,
|
||||||
|
days: days,
|
||||||
|
selectedDayIndex: _selectedDayIndex,
|
||||||
|
onDaySelected: (selected) =>
|
||||||
|
onDaySelected(selected, days.indexOf(day)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DaySelectionCard extends StatelessWidget {
|
||||||
|
const _DaySelectionCard({
|
||||||
|
required this.selectedDayIndex,
|
||||||
|
required this.day,
|
||||||
|
required this.days,
|
||||||
|
required this.onDaySelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String day;
|
||||||
|
final List<String> days;
|
||||||
|
|
||||||
|
final int selectedDayIndex;
|
||||||
|
|
||||||
|
final void Function(bool) onDaySelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var index = days.indexOf(day);
|
||||||
|
var isSelected = index == selectedDayIndex;
|
||||||
|
|
||||||
|
return _DaySelectionCardLayout(
|
||||||
|
day: day,
|
||||||
|
isSelected: isSelected,
|
||||||
|
onDaySelected: onDaySelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DaySelectionCardLayout extends StatelessWidget {
|
||||||
|
const _DaySelectionCardLayout({
|
||||||
|
required this.day,
|
||||||
|
required this.isSelected,
|
||||||
|
required this.onDaySelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String day;
|
||||||
|
final bool isSelected;
|
||||||
|
|
||||||
|
final void Function(bool) onDaySelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var theme = Theme.of(context);
|
||||||
|
var textTheme = theme.textTheme;
|
||||||
|
var abbreviationTextStyle = textTheme.headlineMedium;
|
||||||
|
|
||||||
|
abbreviationTextStyle = isSelected
|
||||||
|
? abbreviationTextStyle?.copyWith(
|
||||||
|
color: theme.colorScheme.onPrimary,
|
||||||
|
)
|
||||||
|
: abbreviationTextStyle;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
height: isSelected ? 72 : 64,
|
||||||
|
width: isSelected ? 72 : 64,
|
||||||
|
child: ChoiceChip(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
label: Center(
|
||||||
|
child: Text(
|
||||||
|
day.toUpperCase(),
|
||||||
|
style: abbreviationTextStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
selected: isSelected,
|
||||||
|
showCheckmark: theme.chipTheme.showCheckmark ?? false,
|
||||||
|
onSelected: onDaySelected,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue