fix: extract deeply nested widgets

This commit is contained in:
Bart Ribbers 2024-07-18 14:42:59 +02:00 committed by Freek van de Ven
parent 9efbcbf48b
commit cdaca15901
5 changed files with 153 additions and 129 deletions

View file

@ -65,56 +65,89 @@ class AvailabilityTemplateSelection extends StatelessWidget {
if (selectedTemplates.isEmpty) ...[ if (selectedTemplates.isEmpty) ...[
addButton, addButton,
] else ...[ ] else ...[
// TODO(Joey): Extract this as a widget _TemplateList(
Container( selectedTemplates: selectedTemplates,
padding: const EdgeInsets.all(12), onTemplatesRemoved: onTemplatesRemoved,
decoration: BoxDecoration(
border: Border.all(
color: theme.colorScheme.primary,
width: 1,
),
// TODO(Joey): This seems like a repeating borderRadius. I can
// understand if these are not configurable, but I do think that
// they should be defined only once.
borderRadius: options.borderRadius,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (var template in selectedTemplates) ...[
// TODO(Joey): Extract this as a widget
Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(template.color),
borderRadius: options.borderRadius,
),
width: 20,
height: 20,
),
const SizedBox(width: 12),
Text(template.name, style: textTheme.bodyLarge),
],
),
if (template != selectedTemplates.last)
const SizedBox(height: 12),
],
],
),
GestureDetector(
onTap: onTemplatesRemoved,
child: const Icon(Icons.remove),
),
],
),
), ),
], ],
], ],
); );
} }
} }
class _TemplateList extends StatelessWidget {
const _TemplateList({
required this.selectedTemplates,
required this.onTemplatesRemoved,
});
final List<AvailabilityTemplateModel> selectedTemplates;
final VoidCallback onTemplatesRemoved;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(
color: theme.colorScheme.primary,
width: 1,
),
borderRadius: options.borderRadius,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (var template in selectedTemplates) ...[
_TemplateListItem(template: template),
if (template != selectedTemplates.last) ...[
const SizedBox(height: 12),
],
],
],
),
InkWell(
onTap: onTemplatesRemoved,
child: const Icon(Icons.remove),
),
],
),
);
}
}
class _TemplateListItem extends StatelessWidget {
const _TemplateListItem({required this.template});
final AvailabilityTemplateModel template;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
return Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(template.color),
borderRadius: options.borderRadius,
),
width: 20,
height: 20,
),
const SizedBox(width: 12),
Text(template.name, style: theme.textTheme.bodyLarge),
],
);
}
}

View file

@ -2,6 +2,31 @@ import "package:flutter/material.dart";
import "package:flutter_availability/flutter_availability.dart"; import "package:flutter_availability/flutter_availability.dart";
import "package:flutter_availability/src/util/scope.dart"; import "package:flutter_availability/src/util/scope.dart";
/// 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;
}
/// ///
class CalendarGrid extends StatelessWidget { class CalendarGrid extends StatelessWidget {
/// ///
@ -68,84 +93,68 @@ class CalendarGrid extends StatelessWidget {
crossAxisSpacing: 12, crossAxisSpacing: 12,
mainAxisSpacing: 12, mainAxisSpacing: 12,
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) => _CalendarDay(
var day = calendarDays[index]; day: calendarDays[index],
return _CalendarDayTile( onDayTap: onDayTap,
day: day, ),
onDayTap: onDayTap,
);
},
), ),
], ],
); );
} }
} }
class _CalendarDayTile extends StatelessWidget { class _CalendarDay extends StatelessWidget {
const _CalendarDayTile({ const _CalendarDay({
required this.day, required this.day,
required this.onDayTap, required this.onDayTap,
}); });
final CalendarDay day; final CalendarDay day;
final void Function(DateTime) onDayTap; final void Function(DateTime date) onDayTap;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var theme = Theme.of(context); var theme = Theme.of(context);
var textTheme = theme.textTheme;
var colorScheme = theme.colorScheme;
var availabilityScope = AvailabilityScope.of(context); var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options; var options = availabilityScope.options;
var colors = options.colors; var colors = options.colors;
var dayColor = var dayColor = day.color ??
day.color ?? colors.customAvailabilityColor ?? colorScheme.secondary; colors.customAvailabilityColor ??
theme.colorScheme.secondary;
Color? textColor; Color? textColor;
TextStyle? textStyle; TextStyle? textStyle;
if (day.outsideMonth) { if (day.outsideMonth) {
textColor = colors.outsideMonthTextColor ?? colorScheme.onSurface; textColor = colors.outsideMonthTextColor ?? theme.colorScheme.onSurface;
textStyle = textTheme.bodyMedium?.copyWith(color: textColor); textStyle = theme.textTheme.bodyMedium?.copyWith(color: textColor);
} else if (day.hasAvailability) { } else if (day.hasAvailability) {
textColor = dayColor; textColor = dayColor;
textStyle = textTheme.titleMedium?.copyWith(color: textColor); textStyle = theme.textTheme.titleMedium?.copyWith(color: textColor);
} }
var decoration = day.outsideMonth
? null
: BoxDecoration(
border: Border(
bottom: BorderSide(
color: textColor ?? Colors.transparent,
width: 1,
),
),
);
return InkWell( return InkWell(
onTap: () => onDayTap(day.date), onTap: () => onDayTap(day.date),
child: DecoratedBox( child: DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), color: dayColor,
borderRadius: options.borderRadius,
border: Border.all( border: Border.all(
color: day.isSelected ? theme.dividerColor : Colors.transparent, color: day.isSelected && !day.outsideMonth
width: 1.5, ? theme.colorScheme.primary
: Colors.transparent,
), ),
), ),
child: Stack( child: Stack(
children: [ children: [
Center( Center(
child: Container( child: Text(day.date.day.toString(), style: textStyle),
padding: const EdgeInsets.symmetric(horizontal: 4),
decoration: decoration,
child: Text(day.date.day.toString(), style: textStyle),
),
), ),
if (day.templateDeviation) if (day.templateDeviation) ...[
Positioned( Positioned(
right: 4, right: 4,
child: Text("*", style: textStyle), child: Text("*", style: textStyle),
), ),
],
], ],
), ),
), ),
@ -153,31 +162,6 @@ class _CalendarDayTile 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 {
/// ///

View file

@ -145,8 +145,7 @@ class BreakDisplay extends StatelessWidget {
breakModel.endTime!, breakModel.endTime!,
); );
// TODO(Joey): Watch out with gesture detectors return InkWell(
return GestureDetector(
onTap: onClick, onTap: onClick,
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -164,8 +163,10 @@ class BreakDisplay extends StatelessWidget {
"$endTime", "$endTime",
), ),
const Spacer(), const Spacer(),
// TODO(Joey): Watch out with gesturedetectors InkWell(
GestureDetector(onTap: onRemove, child: const Icon(Icons.remove)), onTap: onRemove,
child: const Icon(Icons.remove),
),
], ],
), ),
), ),

View file

@ -8,22 +8,10 @@ bool isTemplateDeviated(
AvailabilityTemplateModel template, AvailabilityTemplateModel template,
) { ) {
var dayOfWeek = availability.startDate.weekday; var dayOfWeek = availability.startDate.weekday;
DateTime? templateStartDate; var templateStartDate =
DateTime? templateEndDate; template.getStartTimeForDayOfWeek(WeekDay.values[dayOfWeek - 1]);
var templateEndDate =
// TODO(Joey): Add a method to a templateModel: getEndTimeForDayOfWeek() template.getEndTimeForDayOfWeek(WeekDay.values[dayOfWeek - 1]);
// as well as for start time. Allow polymorphism to resolve this if statement
if (template.templateType == AvailabilityTemplateType.week) {
templateStartDate = (template.templateData as WeekTemplateData)
.data[WeekDay.values[dayOfWeek - 1]]
?.startTime;
templateEndDate = (template.templateData as WeekTemplateData)
.data[WeekDay.values[dayOfWeek - 1]]
?.endTime;
} else {
templateStartDate = (template.templateData as DayTemplateData).startTime;
templateEndDate = (template.templateData as DayTemplateData).endTime;
}
if (templateStartDate == null || templateEndDate == null) { if (templateStartDate == null || templateEndDate == null) {
return true; return true;

View file

@ -95,6 +95,24 @@ class AvailabilityTemplateModel {
templateType: templateType ?? this.templateType, templateType: templateType ?? this.templateType,
templateData: templateData ?? this.templateData, templateData: templateData ?? this.templateData,
); );
/// Get the start time for the specified day in the week for this template
DateTime? getStartTimeForDayOfWeek(WeekDay weekDay) {
if (templateType == AvailabilityTemplateType.week) {
return (templateData as WeekTemplateData).data[weekDay]?.startTime;
}
return (templateData as DayTemplateData).startTime;
}
/// Get the end time for the specified day in the week for this template
DateTime? getEndTimeForDayOfWeek(WeekDay weekDay) {
if (templateType == AvailabilityTemplateType.week) {
return (templateData as WeekTemplateData).data[weekDay]?.endTime;
}
return (templateData as DayTemplateData).endTime;
}
} }
/// Used as the key for defining week-based templates /// Used as the key for defining week-based templates