mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 13:13:44 +02:00
fix: use template viewmodels for the UI state
This commit is contained in:
parent
fd81964b75
commit
313a402409
11 changed files with 387 additions and 169 deletions
|
@ -161,7 +161,7 @@ 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
|
/// The color of the background in the template week overview that creates a
|
||||||
/// layered effect by interchanging a color and a transparent color
|
/// layered effect by interchanging a color and a transparent color
|
||||||
/// If not provided the color will be the theme's [ColorScheme.surface]
|
/// If not provided the color will be the theme's [ColorScheme.surface]
|
||||||
final Color? templateWeekOverviewBackgroundColor;
|
final Color? templateWeekOverviewBackgroundColor;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/service/availability_service.dart";
|
import "package:flutter_availability/src/service/availability_service.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/availability_clear.dart";
|
import "package:flutter_availability/src/ui/widgets/availability_clear.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/availability_template_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/availability_template_selection.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/availabillity_time_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/availabillity_time_selection.dart";
|
||||||
|
@ -172,12 +173,16 @@ class _AvailabilitiesModificationScreenState
|
||||||
);
|
);
|
||||||
|
|
||||||
var pauseSelection = PauseSelection(
|
var pauseSelection = PauseSelection(
|
||||||
breaks: _availability.breaks,
|
breaks: _availability.breaks
|
||||||
|
.map(BreakViewModel.fromAvailabilityBreakModel)
|
||||||
|
.toList(),
|
||||||
editingTemplate: false,
|
editingTemplate: false,
|
||||||
// TODO(Joey): Extract these
|
// TODO(Joey): Extract these
|
||||||
onBreaksChanged: (breaks) {
|
onBreaksChanged: (breaks) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_availability = _availability.copyWith(breaks: breaks);
|
_availability = _availability.copyWith(
|
||||||
|
breaks: breaks.map((b) => b.toBreak()).toList(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/ui/models/view_template_daydata.dart";
|
import "package:flutter_availability/src/ui/view_models/day_template_view_model.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/color_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/color_selection.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/template_name_input.dart";
|
import "package:flutter_availability/src/ui/widgets/template_name_input.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/template_time_break.dart";
|
import "package:flutter_availability/src/ui/widgets/template_time_break.dart";
|
||||||
|
@ -28,25 +28,16 @@ class DayTemplateModificationScreen extends StatefulWidget {
|
||||||
|
|
||||||
class _DayTemplateModificationScreenState
|
class _DayTemplateModificationScreenState
|
||||||
extends State<DayTemplateModificationScreen> {
|
extends State<DayTemplateModificationScreen> {
|
||||||
late int? _selectedColor;
|
late DayTemplateViewModel _viewModel;
|
||||||
late AvailabilityTemplateModel _template;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_selectedColor = widget.template?.color;
|
if (widget.template != null) {
|
||||||
_template = widget.template ??
|
_viewModel = DayTemplateViewModel.fromTemplate(widget.template!);
|
||||||
AvailabilityTemplateModel(
|
} else {
|
||||||
userId: "1",
|
_viewModel = const DayTemplateViewModel();
|
||||||
name: "",
|
}
|
||||||
color: 0,
|
|
||||||
templateType: AvailabilityTemplateType.day,
|
|
||||||
templateData: DayTemplateData(
|
|
||||||
startTime: DateTime.now(),
|
|
||||||
endTime: DateTime.now(),
|
|
||||||
breaks: [],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -59,20 +50,21 @@ class _DayTemplateModificationScreenState
|
||||||
var spacing = options.spacing;
|
var spacing = options.spacing;
|
||||||
|
|
||||||
Future<void> onDeletePressed() async {
|
Future<void> onDeletePressed() async {
|
||||||
await service.deleteTemplate(_template);
|
await service.deleteTemplate(widget.template!);
|
||||||
widget.onExit();
|
widget.onExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onSavePressed() async {
|
Future<void> onSavePressed() async {
|
||||||
|
var template = _viewModel.toTemplate();
|
||||||
if (widget.template == null) {
|
if (widget.template == null) {
|
||||||
await service.createTemplate(_template);
|
await service.createTemplate(template);
|
||||||
} else {
|
} else {
|
||||||
await service.updateTemplate(_template);
|
await service.updateTemplate(template);
|
||||||
}
|
}
|
||||||
widget.onExit();
|
widget.onExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var canSave = _template.name.isNotEmpty && _selectedColor != null;
|
var canSave = _viewModel.canSave;
|
||||||
|
|
||||||
var saveButton = options.primaryButtonBuilder(
|
var saveButton = options.primaryButtonBuilder(
|
||||||
context,
|
context,
|
||||||
|
@ -94,34 +86,29 @@ class _DayTemplateModificationScreenState
|
||||||
);
|
);
|
||||||
|
|
||||||
var templateTitleSection = TemplateNameInput(
|
var templateTitleSection = TemplateNameInput(
|
||||||
initialValue: _template.name,
|
initialValue: _viewModel.name,
|
||||||
onNameChanged: (name) {
|
onNameChanged: (name) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_template = _template.copyWith(name: name);
|
_viewModel = _viewModel.copyWith(name: name);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
var colorSection = TemplateColorSelection(
|
var colorSection = TemplateColorSelection(
|
||||||
selectedColor: _selectedColor,
|
selectedColor: _viewModel.color,
|
||||||
// TODO(Joey): Extract this
|
// TODO(Joey): Extract this
|
||||||
onColorSelected: (color) {
|
onColorSelected: (color) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedColor = color;
|
_viewModel = _viewModel.copyWith(color: color);
|
||||||
_template = _template.copyWith(color: color);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
var availabilitySection = TemplateTimeAndBreakSection(
|
var availabilitySection = TemplateTimeAndBreakSection(
|
||||||
dayData: ViewDayTemplateData.fromDayTemplateData(
|
dayData: _viewModel.data,
|
||||||
_template.templateData as DayTemplateData,
|
|
||||||
),
|
|
||||||
onDayDataChanged: (data) {
|
onDayDataChanged: (data) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_template = _template.copyWith(
|
_viewModel = _viewModel.copyWith(data: data);
|
||||||
templateData: data.toDayTemplateData(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/ui/models/view_template_daydata.dart";
|
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/week_template_view_models.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/color_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/color_selection.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/template_name_input.dart";
|
import "package:flutter_availability/src/ui/widgets/template_name_input.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/template_time_break.dart";
|
import "package:flutter_availability/src/ui/widgets/template_time_break.dart";
|
||||||
|
@ -30,23 +31,16 @@ class WeekTemplateModificationScreen extends StatefulWidget {
|
||||||
|
|
||||||
class _WeekTemplateModificationScreenState
|
class _WeekTemplateModificationScreenState
|
||||||
extends State<WeekTemplateModificationScreen> {
|
extends State<WeekTemplateModificationScreen> {
|
||||||
late int? _selectedColor;
|
|
||||||
late AvailabilityTemplateModel _template;
|
|
||||||
bool _editing = true;
|
bool _editing = true;
|
||||||
WeekDay _selectedDay = WeekDay.monday;
|
WeekDay _selectedDay = WeekDay.monday;
|
||||||
|
late WeekTemplateViewModel _viewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_selectedColor = widget.template?.color;
|
_viewModel = widget.template != null
|
||||||
_template = widget.template ??
|
? WeekTemplateViewModel.fromTemplate(widget.template!)
|
||||||
AvailabilityTemplateModel(
|
: const WeekTemplateViewModel();
|
||||||
userId: "1",
|
|
||||||
name: "",
|
|
||||||
color: 0,
|
|
||||||
templateType: AvailabilityTemplateType.week,
|
|
||||||
templateData: WeekTemplateData.forDays(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -59,11 +53,31 @@ class _WeekTemplateModificationScreenState
|
||||||
var translations = options.translations;
|
var translations = options.translations;
|
||||||
var spacing = options.spacing;
|
var spacing = options.spacing;
|
||||||
|
|
||||||
var weekTemplateDate = _template.templateData as WeekTemplateData;
|
var weekTemplateDate = _viewModel.data;
|
||||||
var selectedDayData = weekTemplateDate.data[_selectedDay];
|
var selectedDayData = weekTemplateDate[_selectedDay];
|
||||||
|
|
||||||
|
void onDayDataChanged(DayTemplateDataViewModel data) {
|
||||||
|
setState(() {
|
||||||
|
// create a new copy of an unmodifiable map that can be modified
|
||||||
|
var updatedDays =
|
||||||
|
Map<WeekDay, DayTemplateDataViewModel>.from(weekTemplateDate);
|
||||||
|
if (data.isEmpty) {
|
||||||
|
updatedDays.remove(_selectedDay);
|
||||||
|
} else {
|
||||||
|
updatedDays[_selectedDay] = data;
|
||||||
|
}
|
||||||
|
_viewModel = _viewModel.copyWith(data: updatedDays);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDaySelected(int day) {
|
||||||
|
setState(() {
|
||||||
|
_selectedDay = WeekDay.values[day];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> onDeletePressed() async {
|
Future<void> onDeletePressed() async {
|
||||||
await service.deleteTemplate(_template);
|
await service.deleteTemplate(widget.template!);
|
||||||
widget.onExit();
|
widget.onExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,15 +98,20 @@ class _WeekTemplateModificationScreenState
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onSavePressed() async {
|
Future<void> onSavePressed() async {
|
||||||
|
if (!_viewModel.isValid) {
|
||||||
|
// TODO(freek): show error message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var template = _viewModel.toTemplate();
|
||||||
if (widget.template == null) {
|
if (widget.template == null) {
|
||||||
await service.createTemplate(_template);
|
await service.createTemplate(template);
|
||||||
} else {
|
} else {
|
||||||
await service.updateTemplate(_template);
|
await service.updateTemplate(template);
|
||||||
}
|
}
|
||||||
widget.onExit();
|
widget.onExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var canSave = _template.name.isNotEmpty && _selectedColor != null;
|
var canSave = _viewModel.canSave;
|
||||||
var nextButton = options.primaryButtonBuilder(
|
var nextButton = options.primaryButtonBuilder(
|
||||||
context,
|
context,
|
||||||
canSave ? onNextPressed : null,
|
canSave ? onNextPressed : null,
|
||||||
|
@ -125,20 +144,19 @@ class _WeekTemplateModificationScreenState
|
||||||
);
|
);
|
||||||
|
|
||||||
var templateTitleSection = TemplateNameInput(
|
var templateTitleSection = TemplateNameInput(
|
||||||
initialValue: _template.name,
|
initialValue: _viewModel.name,
|
||||||
onNameChanged: (name) {
|
onNameChanged: (name) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_template = _template.copyWith(name: name);
|
_viewModel = _viewModel.copyWith(name: name);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
var colorSection = TemplateColorSelection(
|
var colorSection = TemplateColorSelection(
|
||||||
selectedColor: _selectedColor,
|
selectedColor: _viewModel.color,
|
||||||
onColorSelected: (color) {
|
onColorSelected: (color) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedColor = color;
|
_viewModel = _viewModel.copyWith(color: color);
|
||||||
_template = _template.copyWith(color: color);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -148,37 +166,13 @@ class _WeekTemplateModificationScreenState
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: spacing.sidePadding),
|
padding: EdgeInsets.only(left: spacing.sidePadding),
|
||||||
child: TemplateWeekDaySelection(
|
child: TemplateWeekDaySelection(onDaySelected: onDaySelected),
|
||||||
onDaySelected: (day) {
|
|
||||||
setState(() {
|
|
||||||
_selectedDay = WeekDay.values[day];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
_WeekTemplateSidePadding(
|
_WeekTemplateSidePadding(
|
||||||
child: TemplateTimeAndBreakSection(
|
child: TemplateTimeAndBreakSection(
|
||||||
dayData: selectedDayData != null
|
dayData: selectedDayData ?? const DayTemplateDataViewModel(),
|
||||||
? ViewDayTemplateData.fromDayTemplateData(
|
onDayDataChanged: onDayDataChanged,
|
||||||
selectedDayData,
|
|
||||||
)
|
|
||||||
: const ViewDayTemplateData(),
|
|
||||||
onDayDataChanged: (data) {
|
|
||||||
setState(() {
|
|
||||||
_template = _template.copyWith(
|
|
||||||
templateData:
|
|
||||||
// create a copy of the week template data
|
|
||||||
WeekTemplateData(
|
|
||||||
data: {
|
|
||||||
for (var entry in weekTemplateDate.data.entries)
|
|
||||||
entry.key: entry.value,
|
|
||||||
_selectedDay: data.toDayTemplateData(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
@ -203,20 +197,20 @@ class _WeekTemplateModificationScreenState
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(_template.color),
|
color: Color(_viewModel.color ?? 0),
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
),
|
),
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(_template.name, style: textTheme.bodyLarge),
|
Text(_viewModel.name ?? "", style: textTheme.bodyLarge),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
TemplateWeekOverview(
|
TemplateWeekOverview(
|
||||||
template: _template,
|
template: _viewModel,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
|
||||||
|
/// View model to represent the data during the modification of a break
|
||||||
|
class BreakViewModel {
|
||||||
|
/// Constructor
|
||||||
|
const BreakViewModel({
|
||||||
|
this.startTime,
|
||||||
|
this.endTime,
|
||||||
|
this.duration,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [BreakViewModel] from a [AvailabilityBreakModel]
|
||||||
|
factory BreakViewModel.fromAvailabilityBreakModel(
|
||||||
|
AvailabilityBreakModel data,
|
||||||
|
) =>
|
||||||
|
BreakViewModel(
|
||||||
|
startTime: TimeOfDay.fromDateTime(data.startTime),
|
||||||
|
endTime: TimeOfDay.fromDateTime(data.endTime),
|
||||||
|
duration: data.duration,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// The start time for this break
|
||||||
|
final TimeOfDay? startTime;
|
||||||
|
|
||||||
|
/// The end time for this break
|
||||||
|
final TimeOfDay? endTime;
|
||||||
|
|
||||||
|
/// The full duration of the actual break.
|
||||||
|
///
|
||||||
|
/// This is allowed to diverge from the difference between [startTime] and
|
||||||
|
/// [endTime] to indicate that the break is somewhere between [startTime] and
|
||||||
|
/// [endTime]
|
||||||
|
final Duration? duration;
|
||||||
|
|
||||||
|
/// Returns true if the break is valid
|
||||||
|
/// The start is before the end and the duration is equal or lower than the
|
||||||
|
/// difference between the start and end
|
||||||
|
bool get isValid {
|
||||||
|
if (startTime == null || endTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var startDateTime = DateTime(0, 1, 1, startTime!.hour, startTime!.minute);
|
||||||
|
var endDateTime = DateTime(0, 1, 1, endTime!.hour, endTime!.minute);
|
||||||
|
|
||||||
|
if (startDateTime.isAfter(endDateTime)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (duration == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var actualDuration = endDateTime.difference(startDateTime);
|
||||||
|
return duration! <= actualDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the save/next button should be enabled
|
||||||
|
bool get canSave => startTime != null && endTime != null;
|
||||||
|
|
||||||
|
/// Convert to [AvailabilityBreakModel] for saving
|
||||||
|
AvailabilityBreakModel toBreak() => AvailabilityBreakModel(
|
||||||
|
startTime: DateTime(0, 0, 0, startTime!.hour, startTime!.minute),
|
||||||
|
endTime: DateTime(0, 0, 0, endTime!.hour, endTime!.minute),
|
||||||
|
duration: duration,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Create a copy with new values
|
||||||
|
BreakViewModel copyWith({
|
||||||
|
TimeOfDay? startTime,
|
||||||
|
TimeOfDay? endTime,
|
||||||
|
Duration? duration,
|
||||||
|
}) =>
|
||||||
|
BreakViewModel(
|
||||||
|
startTime: startTime ?? this.startTime,
|
||||||
|
endTime: endTime ?? this.endTime,
|
||||||
|
duration: duration ?? this.duration,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// compareto method to order two breaks based on their start time
|
||||||
|
/// multiples hours are converted to minutes and added to the minutes
|
||||||
|
int compareTo(BreakViewModel other) {
|
||||||
|
var difference = startTime!.hour * 60 +
|
||||||
|
startTime!.minute -
|
||||||
|
other.startTime!.hour * 60 -
|
||||||
|
other.startTime!.minute;
|
||||||
|
return difference;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||||
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
|
||||||
|
/// View model to represent the data during the modification of a day template
|
||||||
|
class DayTemplateViewModel {
|
||||||
|
/// Constructor
|
||||||
|
const DayTemplateViewModel({
|
||||||
|
this.data = const DayTemplateDataViewModel(),
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.color,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [WeekTemplateViewModel] from a [AvailabilityTemplateModel]
|
||||||
|
factory DayTemplateViewModel.fromTemplate(
|
||||||
|
AvailabilityTemplateModel template,
|
||||||
|
) {
|
||||||
|
var data = template.templateData as DayTemplateData;
|
||||||
|
return DayTemplateViewModel(
|
||||||
|
id: template.id,
|
||||||
|
name: template.name,
|
||||||
|
color: template.color,
|
||||||
|
data: DayTemplateDataViewModel.fromDayTemplateData(data),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The identifier for this template
|
||||||
|
final String? id;
|
||||||
|
|
||||||
|
/// The name by which the template can be visually identified
|
||||||
|
final String? name;
|
||||||
|
|
||||||
|
/// The color by which the template can be visually identified
|
||||||
|
final int? color;
|
||||||
|
|
||||||
|
/// The data for the template day
|
||||||
|
final DayTemplateDataViewModel data;
|
||||||
|
|
||||||
|
/// Whether the data is valid for saving
|
||||||
|
bool get isValid => data.isValid;
|
||||||
|
|
||||||
|
/// Whether the save/next button should be enabled
|
||||||
|
bool get canSave =>
|
||||||
|
color != null && (name?.isNotEmpty ?? false) && data.canSave;
|
||||||
|
|
||||||
|
/// Convert to [AvailabilityTemplateModel] for saving
|
||||||
|
AvailabilityTemplateModel toTemplate() => AvailabilityTemplateModel(
|
||||||
|
id: id,
|
||||||
|
userId: "",
|
||||||
|
name: name!,
|
||||||
|
color: color!,
|
||||||
|
templateType: AvailabilityTemplateType.day,
|
||||||
|
templateData: data.toDayTemplateData(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Create a copy with new values
|
||||||
|
DayTemplateViewModel copyWith({
|
||||||
|
String? id,
|
||||||
|
String? name,
|
||||||
|
int? color,
|
||||||
|
DayTemplateDataViewModel? data,
|
||||||
|
}) =>
|
||||||
|
DayTemplateViewModel(
|
||||||
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
color: color ?? this.color,
|
||||||
|
data: data ?? this.data,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,21 +1,23 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
|
||||||
/// The data for creating or editing a day template
|
/// The data for creating or editing a day template
|
||||||
class ViewDayTemplateData {
|
class DayTemplateDataViewModel {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
const ViewDayTemplateData({
|
const DayTemplateDataViewModel({
|
||||||
this.startTime,
|
this.startTime,
|
||||||
this.endTime,
|
this.endTime,
|
||||||
this.breaks = const [],
|
this.breaks = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Create a new instance from a [DayTemplateData]
|
/// Create a new instance from a [DayTemplateData]
|
||||||
factory ViewDayTemplateData.fromDayTemplateData(DayTemplateData data) =>
|
factory DayTemplateDataViewModel.fromDayTemplateData(DayTemplateData data) =>
|
||||||
ViewDayTemplateData(
|
DayTemplateDataViewModel(
|
||||||
startTime: TimeOfDay.fromDateTime(data.startTime),
|
startTime: TimeOfDay.fromDateTime(data.startTime),
|
||||||
endTime: TimeOfDay.fromDateTime(data.endTime),
|
endTime: TimeOfDay.fromDateTime(data.endTime),
|
||||||
breaks: data.breaks,
|
breaks:
|
||||||
|
data.breaks.map(BreakViewModel.fromAvailabilityBreakModel).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The start time to apply on a new availability
|
/// The start time to apply on a new availability
|
||||||
|
@ -25,18 +27,28 @@ class ViewDayTemplateData {
|
||||||
final TimeOfDay? endTime;
|
final TimeOfDay? endTime;
|
||||||
|
|
||||||
/// A list of breaks to apply to every new availability
|
/// A list of breaks to apply to every new availability
|
||||||
final List<AvailabilityBreakModel> breaks;
|
final List<BreakViewModel> breaks;
|
||||||
|
|
||||||
/// Whether the data is valid for saving
|
/// Whether the data is valid
|
||||||
bool get isValid => startTime != null && endTime != null;
|
/// The start is before the end
|
||||||
|
/// There are no breaks that are invalid
|
||||||
|
/// The breaks are not outside the start and end time
|
||||||
|
/// The breaks are not overlapping
|
||||||
|
bool get isValid => canSave && breaks.every((b) => b.isValid);
|
||||||
|
|
||||||
|
/// Whether the save/next button should be enabled
|
||||||
|
bool get canSave => startTime != null && endTime != null;
|
||||||
|
|
||||||
|
/// Whether the day is empty and can be removed from the template when saving
|
||||||
|
bool get isEmpty => startTime == null && endTime == null && breaks.isEmpty;
|
||||||
|
|
||||||
/// Create a copy with new values
|
/// Create a copy with new values
|
||||||
ViewDayTemplateData copyWith({
|
DayTemplateDataViewModel copyWith({
|
||||||
TimeOfDay? startTime,
|
TimeOfDay? startTime,
|
||||||
TimeOfDay? endTime,
|
TimeOfDay? endTime,
|
||||||
List<AvailabilityBreakModel>? breaks,
|
List<BreakViewModel>? breaks,
|
||||||
}) =>
|
}) =>
|
||||||
ViewDayTemplateData(
|
DayTemplateDataViewModel(
|
||||||
startTime: startTime ?? this.startTime,
|
startTime: startTime ?? this.startTime,
|
||||||
endTime: endTime ?? this.endTime,
|
endTime: endTime ?? this.endTime,
|
||||||
breaks: breaks ?? this.breaks,
|
breaks: breaks ?? this.breaks,
|
||||||
|
@ -47,6 +59,6 @@ class ViewDayTemplateData {
|
||||||
startTime:
|
startTime:
|
||||||
DateTime(0, 0, 0, startTime?.hour ?? 0, startTime?.minute ?? 0),
|
DateTime(0, 0, 0, startTime?.hour ?? 0, startTime?.minute ?? 0),
|
||||||
endTime: DateTime(0, 0, 0, endTime?.hour ?? 0, endTime?.minute ?? 0),
|
endTime: DateTime(0, 0, 0, endTime?.hour ?? 0, endTime?.minute ?? 0),
|
||||||
breaks: breaks,
|
breaks: breaks.map((b) => b.toBreak()).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||||
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
|
||||||
|
/// View model to represent the data during the modification of a week template
|
||||||
|
class WeekTemplateViewModel {
|
||||||
|
/// Constructor
|
||||||
|
const WeekTemplateViewModel({
|
||||||
|
this.data = const {},
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.color,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a [WeekTemplateViewModel] from a [AvailabilityTemplateModel]
|
||||||
|
factory WeekTemplateViewModel.fromTemplate(
|
||||||
|
AvailabilityTemplateModel template,
|
||||||
|
) {
|
||||||
|
var data = template.templateData as WeekTemplateData;
|
||||||
|
return WeekTemplateViewModel(
|
||||||
|
id: template.id,
|
||||||
|
name: template.name,
|
||||||
|
color: template.color,
|
||||||
|
data: {
|
||||||
|
for (var day in WeekDay.values)
|
||||||
|
day: data.data.containsKey(day)
|
||||||
|
? DayTemplateDataViewModel.fromDayTemplateData(
|
||||||
|
data.data[day]!,
|
||||||
|
)
|
||||||
|
: const DayTemplateDataViewModel(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The identifier for this template
|
||||||
|
final String? id;
|
||||||
|
|
||||||
|
/// The name by which the template can be visually identified
|
||||||
|
final String? name;
|
||||||
|
|
||||||
|
/// The color by which the template can be visually identified
|
||||||
|
final int? color;
|
||||||
|
|
||||||
|
/// The data for each day of the week
|
||||||
|
final Map<WeekDay, DayTemplateDataViewModel> data;
|
||||||
|
|
||||||
|
/// Whether the data is valid for saving
|
||||||
|
/// All days must be valid and there must be at least one day with data
|
||||||
|
bool get isValid =>
|
||||||
|
data.values.every((e) => e.isValid) && data.values.isNotEmpty;
|
||||||
|
|
||||||
|
/// Whether the save/next button should be enabled
|
||||||
|
bool get canSave =>
|
||||||
|
color != null && (name?.isNotEmpty ?? false) && data.values.isNotEmpty;
|
||||||
|
|
||||||
|
/// Convert to [AvailabilityTemplateModel] for saving
|
||||||
|
AvailabilityTemplateModel toTemplate() => AvailabilityTemplateModel(
|
||||||
|
id: id,
|
||||||
|
userId: "",
|
||||||
|
name: name!,
|
||||||
|
color: color!,
|
||||||
|
templateType: AvailabilityTemplateType.week,
|
||||||
|
templateData: WeekTemplateData(
|
||||||
|
data: {
|
||||||
|
for (var entry in data.entries)
|
||||||
|
entry.key: entry.value.toDayTemplateData(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Create a copy with new values
|
||||||
|
WeekTemplateViewModel copyWith({
|
||||||
|
String? id,
|
||||||
|
String? name,
|
||||||
|
int? color,
|
||||||
|
Map<WeekDay, DayTemplateDataViewModel>? data,
|
||||||
|
}) =>
|
||||||
|
WeekTemplateViewModel(
|
||||||
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
color: color ?? this.color,
|
||||||
|
data: data ?? this.data,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/flutter_availability.dart";
|
import "package:flutter_availability/flutter_availability.dart";
|
||||||
import "package:flutter_availability/src/service/availability_service.dart";
|
import "package:flutter_availability/src/service/availability_service.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/generic_time_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/generic_time_selection.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/input_fields.dart";
|
import "package:flutter_availability/src/ui/widgets/input_fields.dart";
|
||||||
import "package:flutter_availability/src/util/scope.dart";
|
import "package:flutter_availability/src/util/scope.dart";
|
||||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
|
||||||
|
|
||||||
///
|
///
|
||||||
class PauseSelection extends StatelessWidget {
|
class PauseSelection extends StatelessWidget {
|
||||||
|
@ -17,10 +17,10 @@ class PauseSelection extends StatelessWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The breaks that are currently set
|
/// The breaks that are currently set
|
||||||
final List<AvailabilityBreakModel> breaks;
|
final List<BreakViewModel> breaks;
|
||||||
|
|
||||||
/// Callback for when the breaks are changed
|
/// Callback for when the breaks are changed
|
||||||
final void Function(List<AvailabilityBreakModel>) onBreaksChanged;
|
final void Function(List<BreakViewModel>) onBreaksChanged;
|
||||||
|
|
||||||
/// Whether the pause selection is used for editing a template
|
/// Whether the pause selection is used for editing a template
|
||||||
final bool editingTemplate;
|
final bool editingTemplate;
|
||||||
|
@ -33,11 +33,12 @@ class PauseSelection extends StatelessWidget {
|
||||||
var options = availabilityScope.options;
|
var options = availabilityScope.options;
|
||||||
var translations = options.translations;
|
var translations = options.translations;
|
||||||
|
|
||||||
Future<AvailabilityBreakModel?> openBreakDialog(
|
Future<BreakViewModel?> openBreakDialog(
|
||||||
AvailabilityBreakModel? initialBreak,
|
BreakViewModel? initialBreak,
|
||||||
) async =>
|
) async =>
|
||||||
AvailabilityBreakSelectionDialog.show(
|
AvailabilityBreakSelectionDialog.show(
|
||||||
context,
|
context,
|
||||||
|
initialBreak: initialBreak,
|
||||||
userId: availabilityScope.userId,
|
userId: availabilityScope.userId,
|
||||||
options: options,
|
options: options,
|
||||||
service: availabilityScope.service,
|
service: availabilityScope.service,
|
||||||
|
@ -52,7 +53,7 @@ class PauseSelection extends StatelessWidget {
|
||||||
onBreaksChanged(updatedBreaks);
|
onBreaksChanged(updatedBreaks);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onEditBreak(AvailabilityBreakModel availabilityBreak) async {
|
Future<void> onEditBreak(BreakViewModel availabilityBreak) async {
|
||||||
var updatedBreak = await openBreakDialog(availabilityBreak);
|
var updatedBreak = await openBreakDialog(availabilityBreak);
|
||||||
if (updatedBreak == null) return;
|
if (updatedBreak == null) return;
|
||||||
|
|
||||||
|
@ -60,13 +61,12 @@ class PauseSelection extends StatelessWidget {
|
||||||
onBreaksChanged(updatedBreaks);
|
onBreaksChanged(updatedBreaks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDeleteBreak(AvailabilityBreakModel availabilityBreak) {
|
void onDeleteBreak(BreakViewModel availabilityBreak) {
|
||||||
var updatedBreaks = breaks.where((b) => b != availabilityBreak).toList();
|
var updatedBreaks = breaks.where((b) => b != availabilityBreak).toList();
|
||||||
onBreaksChanged(updatedBreaks);
|
onBreaksChanged(updatedBreaks);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortedBreaks = breaks.toList()
|
var sortedBreaks = breaks.toList()..sort((a, b) => a.compareTo(b));
|
||||||
..sort((a, b) => a.startTime.compareTo(b.startTime));
|
|
||||||
|
|
||||||
var addButton = options.bigTextButtonWrapperBuilder(
|
var addButton = options.bigTextButtonWrapperBuilder(
|
||||||
context,
|
context,
|
||||||
|
@ -120,7 +120,7 @@ class BreakDisplay extends StatelessWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The break to display
|
/// The break to display
|
||||||
final AvailabilityBreakModel breakModel;
|
final BreakViewModel breakModel;
|
||||||
|
|
||||||
/// Callback for when the minus button is clicked
|
/// Callback for when the minus button is clicked
|
||||||
final VoidCallback onRemove;
|
final VoidCallback onRemove;
|
||||||
|
@ -138,11 +138,11 @@ class BreakDisplay extends StatelessWidget {
|
||||||
|
|
||||||
var starTime = translations.timeFormatter(
|
var starTime = translations.timeFormatter(
|
||||||
context,
|
context,
|
||||||
TimeOfDay.fromDateTime(breakModel.startTime),
|
breakModel.startTime!,
|
||||||
);
|
);
|
||||||
var endTime = translations.timeFormatter(
|
var endTime = translations.timeFormatter(
|
||||||
context,
|
context,
|
||||||
TimeOfDay.fromDateTime(breakModel.endTime),
|
breakModel.endTime!,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO(Joey): Watch out with gesture detectors
|
// TODO(Joey): Watch out with gesture detectors
|
||||||
|
@ -158,7 +158,7 @@ class BreakDisplay extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${breakModel.duration.inMinutes} "
|
"${breakModel.duration!.inMinutes} "
|
||||||
"${translations.timeMinutes} | "
|
"${translations.timeMinutes} | "
|
||||||
"$starTime - "
|
"$starTime - "
|
||||||
"$endTime",
|
"$endTime",
|
||||||
|
@ -183,22 +183,22 @@ class AvailabilityBreakSelectionDialog extends StatefulWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The initial break to show in the dialog if any
|
/// The initial break to show in the dialog if any
|
||||||
final AvailabilityBreakModel? initialBreak;
|
final BreakViewModel? initialBreak;
|
||||||
|
|
||||||
/// Whether the dialog is used to edit a template
|
/// Whether the dialog is used to edit a template
|
||||||
/// This will change the description of the dialog
|
/// This will change the description of the dialog
|
||||||
final bool editingTemplate;
|
final bool editingTemplate;
|
||||||
|
|
||||||
/// Opens the dialog to add a break
|
/// Opens the dialog to add a break
|
||||||
static Future<AvailabilityBreakModel?> show(
|
static Future<BreakViewModel?> show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required AvailabilityOptions options,
|
required AvailabilityOptions options,
|
||||||
required String userId,
|
required String userId,
|
||||||
required AvailabilityService service,
|
required AvailabilityService service,
|
||||||
required bool editingTemplate,
|
required bool editingTemplate,
|
||||||
AvailabilityBreakModel? initialBreak,
|
BreakViewModel? initialBreak,
|
||||||
}) async =>
|
}) async =>
|
||||||
showModalBottomSheet<AvailabilityBreakModel>(
|
showModalBottomSheet<BreakViewModel>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
|
@ -225,20 +225,12 @@ class AvailabilityBreakSelectionDialog extends StatefulWidget {
|
||||||
|
|
||||||
class _AvailabilityBreakSelectionDialogState
|
class _AvailabilityBreakSelectionDialogState
|
||||||
extends State<AvailabilityBreakSelectionDialog> {
|
extends State<AvailabilityBreakSelectionDialog> {
|
||||||
late TimeOfDay? _startTime;
|
late BreakViewModel _breakViewModel;
|
||||||
late TimeOfDay? _endTime;
|
|
||||||
late Duration? _duration;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_startTime = widget.initialBreak != null
|
_breakViewModel = widget.initialBreak ?? const BreakViewModel();
|
||||||
? TimeOfDay.fromDateTime(widget.initialBreak!.startTime)
|
|
||||||
: null;
|
|
||||||
_endTime = widget.initialBreak != null
|
|
||||||
? TimeOfDay.fromDateTime(widget.initialBreak!.endTime)
|
|
||||||
: null;
|
|
||||||
_duration = widget.initialBreak?.duration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -252,44 +244,31 @@ class _AvailabilityBreakSelectionDialogState
|
||||||
|
|
||||||
void onUpdateDuration(Duration duration) {
|
void onUpdateDuration(Duration duration) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_duration = duration;
|
_breakViewModel = _breakViewModel.copyWith(duration: duration);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdateStart(TimeOfDay start) {
|
void onUpdateStart(TimeOfDay start) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_startTime = start;
|
_breakViewModel = _breakViewModel.copyWith(startTime: start);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdateEnd(TimeOfDay end) {
|
void onUpdateEnd(TimeOfDay end) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_endTime = end;
|
_breakViewModel = _breakViewModel.copyWith(endTime: end);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var canSave = _startTime != null && _endTime != null;
|
var canSave = _breakViewModel.canSave;
|
||||||
|
|
||||||
var onSaveButtonPress = canSave
|
var onSaveButtonPress = canSave
|
||||||
? () {
|
? () {
|
||||||
var breakModel = AvailabilityBreakModel(
|
if (_breakViewModel.isValid) {
|
||||||
startTime: DateTime(
|
Navigator.of(context).pop(_breakViewModel);
|
||||||
DateTime.now().year,
|
}
|
||||||
DateTime.now().month,
|
debugPrint("Break is not valid");
|
||||||
DateTime.now().day,
|
// TODO(freek): show error message
|
||||||
_startTime!.hour,
|
|
||||||
_startTime!.minute,
|
|
||||||
),
|
|
||||||
endTime: DateTime(
|
|
||||||
DateTime.now().year,
|
|
||||||
DateTime.now().month,
|
|
||||||
DateTime.now().day,
|
|
||||||
_endTime!.hour,
|
|
||||||
_endTime!.minute,
|
|
||||||
),
|
|
||||||
duration: _duration,
|
|
||||||
);
|
|
||||||
Navigator.of(context).pop(breakModel);
|
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
@ -333,7 +312,7 @@ class _AvailabilityBreakSelectionDialogState
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: DurationInputField(
|
child: DurationInputField(
|
||||||
initialValue: _duration,
|
initialValue: _breakViewModel.duration,
|
||||||
onDurationChanged: onUpdateDuration,
|
onDurationChanged: onUpdateDuration,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -342,13 +321,15 @@ class _AvailabilityBreakSelectionDialogState
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
TimeSelection(
|
TimeSelection(
|
||||||
|
key: ValueKey(
|
||||||
|
[_breakViewModel.startTime, _breakViewModel.endTime],
|
||||||
|
),
|
||||||
// rebuild the widget when the start or end time changes
|
// rebuild the widget when the start or end time changes
|
||||||
key: ValueKey([_startTime, _endTime]),
|
|
||||||
title: translations.pauseDialogPeriodTitle,
|
title: translations.pauseDialogPeriodTitle,
|
||||||
description: translations.pauseDialogPeriodDescription,
|
description: translations.pauseDialogPeriodDescription,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
startTime: _startTime,
|
startTime: _breakViewModel.startTime,
|
||||||
endTime: _endTime,
|
endTime: _breakViewModel.endTime,
|
||||||
onStartChanged: onUpdateStart,
|
onStartChanged: onUpdateStart,
|
||||||
onEndChanged: onUpdateEnd,
|
onEndChanged: onUpdateEnd,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/ui/models/view_template_daydata.dart";
|
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/pause_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/pause_selection.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/template_time_selection.dart";
|
import "package:flutter_availability/src/ui/widgets/template_time_selection.dart";
|
||||||
|
|
||||||
|
@ -8,15 +8,15 @@ class TemplateTimeAndBreakSection extends StatelessWidget {
|
||||||
///
|
///
|
||||||
const TemplateTimeAndBreakSection({
|
const TemplateTimeAndBreakSection({
|
||||||
required this.onDayDataChanged,
|
required this.onDayDataChanged,
|
||||||
this.dayData = const ViewDayTemplateData(),
|
this.dayData = const DayTemplateDataViewModel(),
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The day data to display and edit
|
/// The day data to display and edit
|
||||||
final ViewDayTemplateData dayData;
|
final DayTemplateDataViewModel dayData;
|
||||||
|
|
||||||
/// Callback for when the day data changes
|
/// Callback for when the day data changes
|
||||||
final void Function(ViewDayTemplateData data) onDayDataChanged;
|
final void Function(DayTemplateDataViewModel data) onDayDataChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Column(
|
Widget build(BuildContext context) => Column(
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_availability/src/ui/models/view_template_daydata.dart";
|
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||||
|
import "package:flutter_availability/src/ui/view_models/week_template_view_models.dart";
|
||||||
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
|
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
|
||||||
import "package:flutter_availability/src/util/scope.dart";
|
import "package:flutter_availability/src/util/scope.dart";
|
||||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||||
|
@ -13,7 +15,7 @@ class TemplateWeekOverview extends StatelessWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The template to show
|
/// The template to show
|
||||||
final AvailabilityTemplateModel template;
|
final WeekTemplateViewModel template;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -26,7 +28,7 @@ class TemplateWeekOverview extends StatelessWidget {
|
||||||
|
|
||||||
var dayNames = getDaysOfTheWeekAsStrings(translations, context);
|
var dayNames = getDaysOfTheWeekAsStrings(translations, context);
|
||||||
|
|
||||||
var templateData = template.templateData as WeekTemplateData;
|
var templateData = template.data;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -50,11 +52,8 @@ class TemplateWeekOverview extends StatelessWidget {
|
||||||
for (var day in WeekDay.values) ...[
|
for (var day in WeekDay.values) ...[
|
||||||
_TemplateDayDetailRow(
|
_TemplateDayDetailRow(
|
||||||
dayName: dayNames[day.index],
|
dayName: dayNames[day.index],
|
||||||
dayData: templateData.data.containsKey(day)
|
dayData:
|
||||||
? ViewDayTemplateData.fromDayTemplateData(
|
templateData.containsKey(day) ? templateData[day] : null,
|
||||||
templateData.data[day]!,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
isOdd: day.index.isOdd,
|
isOdd: day.index.isOdd,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -81,7 +80,7 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
||||||
final bool isOdd;
|
final bool isOdd;
|
||||||
|
|
||||||
/// The data of the day
|
/// The data of the day
|
||||||
final ViewDayTemplateData? dayData;
|
final DayTemplateDataViewModel? dayData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -102,7 +101,7 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
||||||
dayPeriod = translations.unavailable;
|
dayPeriod = translations.unavailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
var breaks = dayData?.breaks ?? <AvailabilityBreakModel>[];
|
var breaks = dayData?.breaks ?? <BreakViewModel>[];
|
||||||
|
|
||||||
BoxDecoration? boxDecoration;
|
BoxDecoration? boxDecoration;
|
||||||
if (isOdd) {
|
if (isOdd) {
|
||||||
|
@ -134,7 +133,7 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
||||||
// for each break add a line
|
// for each break add a line
|
||||||
for (var dayBreak in breaks) ...[
|
for (var dayBreak in breaks) ...[
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
_TemplateDayDetailPauseRow(dayBreak: dayBreak),
|
_TemplateDayDetailPauseRow(dayBreakViewModel: dayBreak),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -144,10 +143,10 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
||||||
|
|
||||||
class _TemplateDayDetailPauseRow extends StatelessWidget {
|
class _TemplateDayDetailPauseRow extends StatelessWidget {
|
||||||
const _TemplateDayDetailPauseRow({
|
const _TemplateDayDetailPauseRow({
|
||||||
required this.dayBreak,
|
required this.dayBreakViewModel,
|
||||||
});
|
});
|
||||||
|
|
||||||
final AvailabilityBreakModel dayBreak;
|
final BreakViewModel dayBreakViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -157,6 +156,7 @@ class _TemplateDayDetailPauseRow extends StatelessWidget {
|
||||||
var options = availabilityScope.options;
|
var options = availabilityScope.options;
|
||||||
var translations = options.translations;
|
var translations = options.translations;
|
||||||
|
|
||||||
|
var dayBreak = dayBreakViewModel.toBreak();
|
||||||
var startTime = TimeOfDay.fromDateTime(dayBreak.startTime);
|
var startTime = TimeOfDay.fromDateTime(dayBreak.startTime);
|
||||||
var endTime = TimeOfDay.fromDateTime(dayBreak.endTime);
|
var endTime = TimeOfDay.fromDateTime(dayBreak.endTime);
|
||||||
var startTimeString = translations.timeFormatter(context, startTime);
|
var startTimeString = translations.timeFormatter(context, startTime);
|
||||||
|
|
Loading…
Reference in a new issue