Feature/Fix-Invalid-TimeProgress-Name (#3)

Throw Exception when creating time progress with empty or null name.
Handle Exception when user creates new time progress or changes name.

Signed-off-by Andreas Fahrecker <AndreasFahrecker@gmail.com>
This commit is contained in:
Andreas Fahrecker 2020-11-21 19:57:47 +01:00 committed by GitHub
parent f43edc1ea7
commit 7cbd2eff40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 17 deletions

View File

@ -0,0 +1,7 @@
class TimeProgressInvalidNameException implements Exception {
final invalidName;
TimeProgressInvalidNameException(this.invalidName);
String errMsg() => "The name of a TimeProgress can't be: $invalidName";
}

View File

@ -1,4 +1,5 @@
import 'package:meta/meta.dart'; 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/persistence/time_progress_entity.dart';
import 'package:time_progress_tracker/uuid.dart'; import 'package:time_progress_tracker/uuid.dart';
@ -10,11 +11,15 @@ class TimeProgress {
final DateTime endTime; final DateTime endTime;
TimeProgress(this.name, this.startTime, this.endTime, {String id}) 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() { factory TimeProgress.initialDefault() {
int thisYear = DateTime.now().year; 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( TimeProgress copyWith(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:time_progress_tracker/actions/actions.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/app_state.dart';
import 'package:time_progress_tracker/models/time_progress.dart'; import 'package:time_progress_tracker/models/time_progress.dart';
import 'package:time_progress_tracker/screens/progress_dashboard_screen.dart'; import 'package:time_progress_tracker/screens/progress_dashboard_screen.dart';
@ -22,6 +23,8 @@ class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
DateTime pickedEndTime = DateTime( DateTime pickedEndTime = DateTime(
DateTime.now().year + 1, DateTime.now().month, DateTime.now().day); DateTime.now().year + 1, DateTime.now().month, DateTime.now().day);
bool _validName = true;
Future<DateTime> _selectDate( Future<DateTime> _selectDate(
BuildContext context, DateTime initialDate) async { BuildContext context, DateTime initialDate) async {
return await showDatePicker( return await showDatePicker(
@ -32,10 +35,17 @@ class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
} }
void _createTimeProgress(BuildContext context) { void _createTimeProgress(BuildContext context) {
StoreProvider.of<AppState>(context).dispatch(AddTimeProgressAction( try {
TimeProgress(_nameController.text, pickedStartTime, pickedEndTime), TimeProgress tpToCreate =
)); TimeProgress(_nameController.text, pickedStartTime, pickedEndTime);
Navigator.pushNamed(context, ProgressDashboardScreen.routeName); StoreProvider.of<AppState>(context)
.dispatch(AddTimeProgressAction(tpToCreate));
Navigator.pushNamed(context, ProgressDashboardScreen.routeName);
} on TimeProgressInvalidNameException catch (e) {
setState(() {
_validName = false;
});
}
} }
@override @override
@ -60,7 +70,12 @@ class _ProgressCreationScreenState extends State<ProgressCreationScreen> {
child: TextField( child: TextField(
controller: _nameController, controller: _nameController,
decoration: InputDecoration( 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( Expanded(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
import 'package:time_progress_tracker/actions/actions.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/app_state.dart';
import 'package:time_progress_tracker/models/time_progress.dart'; import 'package:time_progress_tracker/models/time_progress.dart';
import 'package:time_progress_tracker/screens/progress_dashboard_screen.dart'; import 'package:time_progress_tracker/screens/progress_dashboard_screen.dart';
@ -30,10 +31,13 @@ class ProgressDetailScreen extends StatefulWidget {
} }
class _ProgressDetailScreenState extends State<ProgressDetailScreen> { class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
final TextEditingController _nameController = TextEditingController();
bool _isBeingEdited = false; bool _isBeingEdited = false;
final TextEditingController _nameController = TextEditingController();
TimeProgress _editedProgress = TimeProgress.initialDefault(); TimeProgress _editedProgress = TimeProgress.initialDefault();
bool _validName = true;
void _onStartDateChanged(DateTime picked) { void _onStartDateChanged(DateTime picked) {
if (picked != null) { if (picked != null) {
setState(() { setState(() {
@ -118,10 +122,18 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
void initState() { void initState() {
super.initState(); super.initState();
_nameController.addListener(() { _nameController.addListener(() {
this.setState(() { try {
this._editedProgress = TimeProgress editedProgress =
this._editedProgress.copyWith(name: _nameController.text); _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<ProgressDetailScreen> {
? TextField( ? TextField(
controller: _nameController, controller: _nameController,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder(), border: OutlineInputBorder(),
labelText: "Progress Name"), labelText: "Progress Name",
errorText: _validName
? null
: "The Name of the Time Progress has to be set.",
),
) )
: FittedBox( : FittedBox(
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
@ -205,7 +221,8 @@ class _ProgressDetailScreenState extends State<ProgressDetailScreen> {
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: _isBeingEdited floatingActionButton: _isBeingEdited
? ProgressDetailFabEditingRow( ? ProgressDetailFabEditingRow(
onSave: () => _onSaveTimeProgress(store, args.id), onSave: () =>
_validName ? _onSaveTimeProgress(store, args.id) : null,
onCancelEdit: () => onCancelEdit: () =>
_showCancelEditTimeProgressDialog(store.state, args.id), _showCancelEditTimeProgressDialog(store.state, args.id),
) )

View File

@ -4,5 +4,8 @@ import 'package:time_progress_tracker/models/time_progress.dart';
List<TimeProgress> timeProgressListSelector(AppState state) => List<TimeProgress> timeProgressListSelector(AppState state) =>
state.timeProgressList; state.timeProgressList;
TimeProgress timeProgressByIdSelector(AppState state, String id) => TimeProgress timeProgressByIdSelector(AppState state, String id) {
state.timeProgressList.firstWhere((timeProgress) => timeProgress.id == id); if (state.timeProgressList.length < 1) return null;
return state.timeProgressList
.firstWhere((timeProgress) => timeProgress.id == id);
}