mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 05:03:44 +02:00
fix: extract deeply nested widgets
This commit is contained in:
parent
9efbcbf48b
commit
cdaca15901
5 changed files with 153 additions and 129 deletions
|
@ -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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
///
|
///
|
||||||
|
|
|
@ -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),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue