diff --git a/lib/models/app_exceptions.dart b/lib/models/app_exceptions.dart new file mode 100644 index 0000000..5272e46 --- /dev/null +++ b/lib/models/app_exceptions.dart @@ -0,0 +1,7 @@ +class TimeProgressInvalidNameException implements Exception { + final invalidName; + + TimeProgressInvalidNameException(this.invalidName); + + String errMsg() => "The name of a TimeProgress can't be: $invalidName"; +} diff --git a/lib/models/time_progress.dart b/lib/models/time_progress.dart index ebde421..8675720 100644 --- a/lib/models/time_progress.dart +++ b/lib/models/time_progress.dart @@ -1,4 +1,5 @@ import 'package:meta/meta.dart'; +import 'package:time_progress_tracker/models/app_exceptions.dart'; import 'package:time_progress_tracker/persistence/time_progress_entity.dart'; import 'package:time_progress_tracker/uuid.dart'; @@ -10,11 +11,15 @@ class TimeProgress { final DateTime endTime; TimeProgress(this.name, this.startTime, this.endTime, {String id}) - : id = id ?? Uuid().generateV4(); + : id = id ?? Uuid().generateV4() { + if (this.name == null || this.name == "") { + throw new TimeProgressInvalidNameException(this.name); + } + } factory TimeProgress.initialDefault() { int thisYear = DateTime.now().year; - return TimeProgress("", DateTime(thisYear - 1), DateTime(thisYear + 1)); + return TimeProgress("Initial Name", DateTime(thisYear - 1), DateTime(thisYear + 1)); } TimeProgress copyWith( diff --git a/lib/screens/progress_creation_screen.dart b/lib/screens/progress_creation_screen.dart index 07b801a..bf69031 100644 --- a/lib/screens/progress_creation_screen.dart +++ b/lib/screens/progress_creation_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:time_progress_tracker/actions/actions.dart'; +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/screens/progress_dashboard_screen.dart'; @@ -22,6 +23,8 @@ class _ProgressCreationScreenState extends State { DateTime pickedEndTime = DateTime( DateTime.now().year + 1, DateTime.now().month, DateTime.now().day); + bool _validName = true; + Future _selectDate( BuildContext context, DateTime initialDate) async { return await showDatePicker( @@ -32,10 +35,17 @@ class _ProgressCreationScreenState extends State { } void _createTimeProgress(BuildContext context) { - StoreProvider.of(context).dispatch(AddTimeProgressAction( - TimeProgress(_nameController.text, pickedStartTime, pickedEndTime), - )); - Navigator.pushNamed(context, ProgressDashboardScreen.routeName); + try { + TimeProgress tpToCreate = + TimeProgress(_nameController.text, pickedStartTime, pickedEndTime); + StoreProvider.of(context) + .dispatch(AddTimeProgressAction(tpToCreate)); + Navigator.pushNamed(context, ProgressDashboardScreen.routeName); + } on TimeProgressInvalidNameException catch (e) { + setState(() { + _validName = false; + }); + } } @override @@ -60,7 +70,12 @@ class _ProgressCreationScreenState extends State { child: TextField( controller: _nameController, decoration: InputDecoration( - border: OutlineInputBorder(), labelText: "Progress Name"), + border: OutlineInputBorder(), + labelText: "Progress Name", + errorText: _validName + ? null + : "The Name of the Time Progress has to be set.", + ), ), ), Expanded( diff --git a/lib/screens/progress_detail_screen.dart b/lib/screens/progress_detail_screen.dart index 206fdf3..949c6cd 100644 --- a/lib/screens/progress_detail_screen.dart +++ b/lib/screens/progress_detail_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:time_progress_tracker/actions/actions.dart'; +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/screens/progress_dashboard_screen.dart'; @@ -30,10 +31,13 @@ class ProgressDetailScreen extends StatefulWidget { } class _ProgressDetailScreenState extends State { - final TextEditingController _nameController = TextEditingController(); bool _isBeingEdited = false; + final TextEditingController _nameController = TextEditingController(); + TimeProgress _editedProgress = TimeProgress.initialDefault(); + bool _validName = true; + void _onStartDateChanged(DateTime picked) { if (picked != null) { setState(() { @@ -118,10 +122,18 @@ class _ProgressDetailScreenState extends State { void initState() { super.initState(); _nameController.addListener(() { - this.setState(() { - this._editedProgress = - this._editedProgress.copyWith(name: _nameController.text); - }); + try { + TimeProgress editedProgress = + _editedProgress.copyWith(name: _nameController.text); + setState(() { + _editedProgress = editedProgress; + _validName = true; + }); + } on TimeProgressInvalidNameException catch (e) { + setState(() { + _validName = false; + }); + } }); } @@ -151,8 +163,12 @@ class _ProgressDetailScreenState extends State { ? TextField( controller: _nameController, decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: "Progress Name"), + border: OutlineInputBorder(), + labelText: "Progress Name", + errorText: _validName + ? null + : "The Name of the Time Progress has to be set.", + ), ) : FittedBox( fit: BoxFit.fitWidth, @@ -205,7 +221,8 @@ class _ProgressDetailScreenState extends State { floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: _isBeingEdited ? ProgressDetailFabEditingRow( - onSave: () => _onSaveTimeProgress(store, args.id), + onSave: () => + _validName ? _onSaveTimeProgress(store, args.id) : null, onCancelEdit: () => _showCancelEditTimeProgressDialog(store.state, args.id), ) diff --git a/lib/selectors/time_progress_selectors.dart b/lib/selectors/time_progress_selectors.dart index e9681c7..ae81e7b 100644 --- a/lib/selectors/time_progress_selectors.dart +++ b/lib/selectors/time_progress_selectors.dart @@ -4,5 +4,8 @@ import 'package:time_progress_tracker/models/time_progress.dart'; List timeProgressListSelector(AppState state) => state.timeProgressList; -TimeProgress timeProgressByIdSelector(AppState state, String id) => - state.timeProgressList.firstWhere((timeProgress) => timeProgress.id == id); +TimeProgress timeProgressByIdSelector(AppState state, String id) { + if (state.timeProgressList.length < 1) return null; + return state.timeProgressList + .firstWhere((timeProgress) => timeProgress.id == id); +}