diff --git a/lib/models/time_progress.dart b/lib/models/time_progress.dart index e71ca16..2da564e 100644 --- a/lib/models/time_progress.dart +++ b/lib/models/time_progress.dart @@ -11,13 +11,7 @@ class TimeProgress { final DateTime endTime; TimeProgress(this.name, this.startTime, this.endTime, {String id}) - : id = id ?? Uuid().generateV4() { - if (this.name == null || this.name == "") - throw new TimeProgressInvalidNameException(this.name); - if (!this.startTime.isBefore(this.endTime)) - throw new TimeProgressStartTimeIsNotBeforeEndTimeException( - startTime, endTime); - } + : id = id ?? Uuid().generateV4(); factory TimeProgress.initialDefault() { int thisYear = DateTime.now().year; @@ -81,6 +75,11 @@ class TimeProgress { } TimeProgressEntity toEntity() { + if (!TimeProgress.isNameValid(name)) + throw new TimeProgressInvalidNameException(name); + if (!TimeProgress.areTimesValid(startTime, endTime)) + throw new TimeProgressStartTimeIsNotBeforeEndTimeException( + startTime, endTime); return TimeProgressEntity(id, name, startTime, endTime); } @@ -92,4 +91,17 @@ class TimeProgress { id: entity.id ?? Uuid().generateV4(), ); } + + static bool isValid(TimeProgress tp) { + return TimeProgress.isNameValid(tp.name) && + TimeProgress.areTimesValid(tp.startTime, tp.endTime); + } + + static bool isNameValid(String name) { + return name != null && name != "" && name.length > 3 && name.length < 20; + } + + static bool areTimesValid(DateTime startTime, DateTime endTime) { + return startTime.isBefore(endTime); + } } diff --git a/lib/screens/progress_creation_screen.dart b/lib/screens/progress_creation_screen.dart index a046642..c539c20 100644 --- a/lib/screens/progress_creation_screen.dart +++ b/lib/screens/progress_creation_screen.dart @@ -6,6 +6,7 @@ import 'package:time_progress_tracker/models/app_exceptions.dart'; import 'package:time_progress_tracker/models/app_state.dart'; import 'package:time_progress_tracker/models/time_progress.dart'; import 'package:time_progress_tracker/widgets/date_picker_btn.dart'; +import 'package:time_progress_tracker/widgets/progress_editor_widget.dart'; class ProgressCreationScreen extends StatefulWidget { static const routeName = "/progress-creation"; @@ -18,115 +19,26 @@ class ProgressCreationScreen extends StatefulWidget { } class _ProgressCreationScreenState extends State { - final TextEditingController _nameController = TextEditingController(); - DateTime pickedStartTime = DateTime.now(); - DateTime pickedEndTime = DateTime( - DateTime.now().year + 1, DateTime.now().month, DateTime.now().day); + TimeProgress timeProgressToCreate = + TimeProgress("", DateTime.now(), DateTime(DateTime.now().year + 1)); - bool _validName = true; - bool _validDates = true; - - void _createTimeProgress(BuildContext context) { - try { - TimeProgress tpToCreate = - TimeProgress(_nameController.text, pickedStartTime, pickedEndTime); - StoreProvider.of(context) - .dispatch(AddTimeProgressAction(tpToCreate)); - Navigator.pop(context); - } on TimeProgressInvalidNameException catch (e) { - setState(() { - _validName = false; - }); - } on TimeProgressStartTimeIsNotBeforeEndTimeException catch (e) { - setState(() { - _validDates = false; - }); - } - } - - @override - void dispose() { - _nameController.dispose(); - super.dispose(); + void onTimeProgressChanged(TimeProgress newTimeProgress) { + setState(() { + timeProgressToCreate = newTimeProgress; + }); } @override Widget build(BuildContext context) { - ThemeData appTheme = Theme.of(context); - return Scaffold( appBar: AppBar( title: Text(ProgressCreationScreen.title), ), body: Container( - padding: EdgeInsets.all(8), - child: Column( - children: [ - Expanded( - flex: 1, - child: TextField( - controller: _nameController, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: "Progress Name", - errorText: _validName - ? null - : "The Name of the Time Progress has to be set.", - ), - ), - ), - Expanded( - flex: 1, - child: Row( - children: [ - Expanded( - flex: 5, - child: DatePickerBtn( - leadingString: "Start Date:", - pickedDate: pickedStartTime, - onDatePicked: (DateTime startTime) { - if (startTime != null) { - setState(() { - pickedStartTime = startTime; - }); - } - }, - ), - ), - Spacer( - flex: 1, - ), - Expanded( - flex: 5, - child: DatePickerBtn( - leadingString: "EndDate:", - pickedDate: pickedEndTime, - onDatePicked: (DateTime endTime) { - if (endTime != null) { - setState(() { - pickedEndTime = endTime; - }); - } - }, - ), - ), - ], - ), - ), - _validDates - ? Spacer( - flex: 1, - ) - : Expanded( - child: Center( - child: Text( - "Your Picked Dates are invalid. The Start Date has to be before the end Date."), - ), - ), - Spacer( - flex: 4, - ) - ], + padding: EdgeInsets.all(12), + child: ProgressEditorWidget( + timeProgress: timeProgressToCreate, + onTimeProgressChanged: onTimeProgressChanged, ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, @@ -136,9 +48,13 @@ class _ProgressCreationScreenState extends State { child: FloatingActionButton( heroTag: "createTimeProgressBTN", child: Icon(Icons.save), - onPressed: () { - _createTimeProgress(context); - }, + onPressed: TimeProgress.isValid(timeProgressToCreate) + ? () { + StoreProvider.of(context).dispatch( + AddTimeProgressAction(timeProgressToCreate)); + Navigator.pop(context); + } + : null, ), ), Expanded( diff --git a/lib/widgets/progress_editor_widget.dart b/lib/widgets/progress_editor_widget.dart new file mode 100644 index 0000000..552f4f6 --- /dev/null +++ b/lib/widgets/progress_editor_widget.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import 'package:time_progress_tracker/models/time_progress.dart'; +import 'package:time_progress_tracker/widgets/date_picker_btn.dart'; + +class ProgressEditorWidget extends StatefulWidget { + final TimeProgress timeProgress; + final Function(TimeProgress) onTimeProgressChanged; + + ProgressEditorWidget({ + @required this.timeProgress, + @required this.onTimeProgressChanged, + }); + + @override + State createState() { + return _ProgressEditorWidgetState(); + } +} + +class _ProgressEditorWidgetState extends State { + bool _validName = true, _validDate = true; + + void _onNameChanged(String newName) { + if (!TimeProgress.isNameValid(newName)) + setState(() { + _validName = false; + }); + + widget.onTimeProgressChanged(widget.timeProgress.copyWith(name: newName)); + setState(() { + _validName = true; + }); + } + + void _onStartDateChanged(DateTime newStartDate) { + if (!TimeProgress.areTimesValid(newStartDate, widget.timeProgress.endTime)) + setState(() { + _validDate = false; + }); + + widget.onTimeProgressChanged( + widget.timeProgress.copyWith(startTime: newStartDate)); + setState(() { + _validDate = true; + }); + } + + void _onEndDateChanged(DateTime newEndDate) { + if (!TimeProgress.areTimesValid(widget.timeProgress.startTime, newEndDate)) + setState(() { + _validDate = false; + }); + + widget.onTimeProgressChanged( + widget.timeProgress.copyWith(endTime: newEndDate)); + } + + @override + Widget build(BuildContext context) { + List columnChildren = [ + Expanded( + child: TextField( + onChanged: _onNameChanged, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: "Progress Name", + errorText: + _validName ? null : "The Name of the Progress can't be empty.", + ), + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(right: 5), + child: DatePickerBtn( + leadingString: "Start Date:", + pickedDate: widget.timeProgress.startTime, + onDatePicked: _onStartDateChanged, + ), + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 5), + child: DatePickerBtn( + leadingString: "End Date:", + pickedDate: widget.timeProgress.endTime, + onDatePicked: _onEndDateChanged, + ), + ), + ), + ], + ), + ) + ]; + + if (!_validDate) + columnChildren.add( + Expanded( + child: Center( + child: Text( + "Invalid Dates. The Start Date has to be before the End Date"), + ), + ), + ); + + return Container( + child: Column( + children: columnChildren, + ), + ); + } +}