diff --git a/lib/models/time_progress.dart b/lib/models/time_progress.dart index 2da564e..625fb69 100644 --- a/lib/models/time_progress.dart +++ b/lib/models/time_progress.dart @@ -98,7 +98,7 @@ class TimeProgress { } static bool isNameValid(String name) { - return name != null && name != "" && name.length > 3 && name.length < 20; + return name != null && name != "" && name.length > 2 && name.length < 21; } static bool areTimesValid(DateTime startTime, DateTime endTime) { diff --git a/lib/screens/progress_creation_screen.dart b/lib/screens/progress_creation_screen.dart index c539c20..d034f5f 100644 --- a/lib/screens/progress_creation_screen.dart +++ b/lib/screens/progress_creation_screen.dart @@ -2,10 +2,8 @@ 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/widgets/date_picker_btn.dart'; import 'package:time_progress_tracker/widgets/progress_editor_widget.dart'; class ProgressCreationScreen extends StatefulWidget { diff --git a/lib/screens/progress_detail_screen.dart b/lib/screens/progress_detail_screen.dart index 737b85b..20db694 100644 --- a/lib/screens/progress_detail_screen.dart +++ b/lib/screens/progress_detail_screen.dart @@ -1,20 +1,16 @@ -import 'dart:io'; - 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/home_screen.dart'; import 'package:time_progress_tracker/selectors/time_progress_selectors.dart'; import 'package:time_progress_tracker/widgets/app_yes_no_dialog_widget.dart'; -import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_circular_percent_widget.dart'; -import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_edit_dates_row_widget.dart'; import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_fab_editing_row_widget.dart'; import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_fab_row_widget.dart'; -import 'package:time_progress_tracker/widgets/progress_detail_widgets/progress_detail_linear_percent_widget.dart'; +import 'package:time_progress_tracker/widgets/progress_editor_widget.dart'; +import 'package:time_progress_tracker/widgets/progress_view_widget.dart'; class ProgressDetailScreenArguments { final String id; @@ -32,69 +28,55 @@ class ProgressDetailScreen extends StatefulWidget { } class _ProgressDetailScreenState extends State { - bool _isBeingEdited = false; - final TextEditingController _nameController = TextEditingController(); - + bool _editMode = false; TimeProgress _editedProgress = TimeProgress.initialDefault(); - bool _validName = true; - - void _onStartDateChanged(DateTime picked) { - if (picked != null) { - setState(() { - _editedProgress = _editedProgress.copyWith(startTime: picked); - }); - } - } - - void _onEndDateChanged(DateTime picked) { - if (picked != null) { - setState(() { - _editedProgress = _editedProgress.copyWith(endTime: picked); - }); - } + void _onEditedProgressChanged(TimeProgress newProgress) { + setState(() { + _editedProgress = newProgress; + }); } void _onSaveTimeProgress(Store store, id) { + if (!TimeProgress.isValid(_editedProgress)) return; store.dispatch(UpdateTimeProgressAction(id, _editedProgress)); setState(() { - _isBeingEdited = false; + _editMode = false; }); } void _showCancelEditTimeProgressDialog(AppState state, id) { TimeProgress originalTp = timeProgressByIdSelector(state, id); if (originalTp != _editedProgress) { - String originalName = timeProgressByIdSelector(state, id).name; + String originalName = originalTp.name; showDialog( context: context, builder: (_) => AppYesNoDialog( titleText: "Cancel Editing of $originalName", contentText: "Are you sure that you want to discard the changes done to $originalName", - onYesPressed: _onCancelEditTimeProgress, + onYesPressed: () { + _cancelEditMode(); + Navigator.pop(context); + }, onNoPressed: _onCloseDialog, ), ); } else { - setState(() { - _isBeingEdited = false; - }); + _cancelEditMode(); } } - void _onCancelEditTimeProgress() { + void _cancelEditMode() { setState(() { - _isBeingEdited = false; + _editMode = false; }); - Navigator.pop(context); } - void _onEditTimeProgress(Store store, id) { + void _onEditTimeProgress(AppState state, id) { setState(() { - _isBeingEdited = true; - _editedProgress = timeProgressByIdSelector(store.state, id); - _nameController.text = _editedProgress.name; + _editMode = true; + _editedProgress = timeProgressByIdSelector(state, id); }); } @@ -119,38 +101,17 @@ class _ProgressDetailScreenState extends State { Navigator.pop(context); } - @override - void initState() { - super.initState(); - _nameController.addListener(() { - try { - TimeProgress editedProgress = - _editedProgress.copyWith(name: _nameController.text); - setState(() { - _editedProgress = editedProgress; - _validName = true; - }); - } on TimeProgressInvalidNameException catch (e) { - setState(() { - _validName = false; - }); - } - }); - } - @override Widget build(BuildContext context) { final ProgressDetailScreenArguments args = ModalRoute.of(context).settings.arguments; final Store store = StoreProvider.of(context); + final ThemeData appTheme = Theme.of(context); return Scaffold( appBar: AppBar( title: Text("Progress"), ), - /*drawer: AppDrawer( - appVersion: widget.appVersion, - ),*/ body: Container( margin: EdgeInsets.all(8), child: StoreConnector( @@ -162,119 +123,65 @@ class _ProgressDetailScreenState extends State { return Center( child: Text("Error Invalid Time Progress"), ); + List columnChildren = [ + Expanded( + child: ProgressViewWidget( + timeProgress: + _editMode ? _editedProgress : vm.timeProgress), + ) + ]; + if (_editMode) + columnChildren.add(Expanded( + child: ProgressEditorWidget( + timeProgress: _editedProgress, + onTimeProgressChanged: _onEditedProgressChanged, + ), + )); return Column( - children: [ - Expanded( - flex: 1, - child: _isBeingEdited - ? TextField( - controller: _nameController, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: "Progress Name", - errorText: _validName - ? null - : "The Name of the Time Progress has to be set.", - ), - ) - : (vm.timeProgress.hasStarted() && - !vm.timeProgress.hasEnded()) - ? FittedBox( - fit: BoxFit.fitWidth, - child: Text( - vm.timeProgress.name, - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - ) - : Center( - child: FittedBox( - fit: BoxFit.fitWidth, - child: Text( - vm.timeProgress.name, - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - ), - ), - ), - (vm.timeProgress.hasStarted() && !vm.timeProgress.hasEnded()) - ? Expanded( - flex: 2, - child: ProgressDetailCircularPercent( - percentDone: _isBeingEdited - ? _editedProgress.percentDone() - : vm.timeProgress.percentDone(), - ), - ) - : Expanded( - flex: 2, - child: !vm.timeProgress.hasEnded() - ? Text( - "Starts in ${vm.timeProgress.startTime.difference(DateTime.now()).inDays} Days.") - : Text( - "Ended ${DateTime.now().difference(vm.timeProgress.endTime).inDays} Days ago."), - ), - (vm.timeProgress.hasStarted() && !vm.timeProgress.hasEnded()) - ? Expanded( - flex: 1, - child: ProgressDetailLinearPercent( - timeProgress: _isBeingEdited - ? _editedProgress - : vm.timeProgress, - ), - ) - : Spacer( - flex: 1, - ), - Expanded( - flex: 1, - child: Text( - "${_isBeingEdited ? _editedProgress.allDays() : vm.timeProgress.allDays()} Days"), - ), - this._isBeingEdited - ? Expanded( - flex: 1, - child: ProgressDetailEditDatesRow( - startTime: _editedProgress.startTime, - endTime: _editedProgress.endTime, - onStartTimeChanged: _onStartDateChanged, - onEndTimeChanged: _onEndDateChanged, - ), - ) - : Spacer(flex: 1), - Spacer(flex: 1) - ], + children: columnChildren, ); }, ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: _isBeingEdited - ? ProgressDetailFabEditingRow( - onSave: () => - _validName ? _onSaveTimeProgress(store, args.id) : null, - onCancelEdit: () => - _showCancelEditTimeProgressDialog(store.state, args.id), - ) - : ProgressDetailFabRow( - onEdit: () => _onEditTimeProgress(store, args.id), - onDelete: () => _showDeleteTimeProgressDialog(store, args.id), + floatingActionButton: Row( + children: [ + Expanded( + child: FloatingActionButton( + heroTag: _editMode + ? "saveEditedTimeProgressBTN" + : "editTimeProgressBTN", + child: _editMode ? Icon(Icons.save) : Icon(Icons.edit), + backgroundColor: _editMode ? Colors.green : appTheme.accentColor, + onPressed: _editMode + ? () { + _onSaveTimeProgress(store, args.id); + } + : () { + _onEditTimeProgress(store.state, args.id); + }, ), + ), + Expanded( + child: FloatingActionButton( + heroTag: _editMode + ? "cancelEditTimeProgressBTN" + : "deleteTimeProgressBTN", + child: _editMode ? Icon(Icons.cancel) : Icon(Icons.delete), + backgroundColor: Colors.red, + onPressed: _editMode + ? () { + _showCancelEditTimeProgressDialog(store.state, args.id); + } + : () { + _showDeleteTimeProgressDialog(store, args.id); + }, + ), + ), + ], + ), ); } - - @override - void dispose() { - _nameController.dispose(); - super.dispose(); - } } class _ViewModel { diff --git a/lib/widgets/progress_editor_widget.dart b/lib/widgets/progress_editor_widget.dart index 552f4f6..1b15a3a 100644 --- a/lib/widgets/progress_editor_widget.dart +++ b/lib/widgets/progress_editor_widget.dart @@ -18,41 +18,53 @@ class ProgressEditorWidget extends StatefulWidget { } class _ProgressEditorWidgetState extends State { + final _nameTextController = TextEditingController(); bool _validName = true, _validDate = true; - void _onNameChanged(String newName) { - if (!TimeProgress.isNameValid(newName)) + void _onNameChanged() { + if (TimeProgress.isNameValid(_nameTextController.text)) { + widget.onTimeProgressChanged( + widget.timeProgress.copyWith(name: _nameTextController.text)); + setState(() { + _validName = true; + }); + } else setState(() { _validName = false; }); - - widget.onTimeProgressChanged(widget.timeProgress.copyWith(name: newName)); - setState(() { - _validName = true; - }); } void _onStartDateChanged(DateTime newStartDate) { - if (!TimeProgress.areTimesValid(newStartDate, widget.timeProgress.endTime)) + if (TimeProgress.areTimesValid(newStartDate, widget.timeProgress.endTime)) { + widget.onTimeProgressChanged( + widget.timeProgress.copyWith(startTime: newStartDate)); + setState(() { + _validDate = true; + }); + } else setState(() { _validDate = false; }); - - widget.onTimeProgressChanged( - widget.timeProgress.copyWith(startTime: newStartDate)); - setState(() { - _validDate = true; - }); } void _onEndDateChanged(DateTime newEndDate) { - if (!TimeProgress.areTimesValid(widget.timeProgress.startTime, newEndDate)) + if (TimeProgress.areTimesValid(widget.timeProgress.startTime, newEndDate)) { + widget.onTimeProgressChanged( + widget.timeProgress.copyWith(endTime: newEndDate)); + setState(() { + _validDate = true; + }); + } else setState(() { _validDate = false; }); + } - widget.onTimeProgressChanged( - widget.timeProgress.copyWith(endTime: newEndDate)); + @override + void initState() { + _nameTextController.text = widget.timeProgress.name; + _nameTextController.addListener(_onNameChanged); + super.initState(); } @override @@ -60,12 +72,13 @@ class _ProgressEditorWidgetState extends State { List columnChildren = [ Expanded( child: TextField( - onChanged: _onNameChanged, + controller: _nameTextController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: "Progress Name", - errorText: - _validName ? null : "The Name of the Progress can't be empty.", + errorText: _validName + ? null + : "The Name need to have at least 3 and at max 20 symbols.", ), ), ), @@ -102,7 +115,9 @@ class _ProgressEditorWidgetState extends State { Expanded( child: Center( child: Text( - "Invalid Dates. The Start Date has to be before the End Date"), + "Invalid Dates. The Start Date has to be before the End Date", + style: TextStyle(color: Colors.red), + ), ), ), ); diff --git a/lib/widgets/progress_view_widget.dart b/lib/widgets/progress_view_widget.dart new file mode 100644 index 0000000..58e2dde --- /dev/null +++ b/lib/widgets/progress_view_widget.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:percent_indicator/circular_percent_indicator.dart'; +import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'package:time_progress_tracker/models/time_progress.dart'; + +class ProgressViewWidget extends StatelessWidget { + final TimeProgress timeProgress; + + ProgressViewWidget({ + @required this.timeProgress, + }); + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Expanded( + child: FittedBox( + fit: BoxFit.fitWidth, + child: Text( + timeProgress.name, + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ), + ), + Expanded( + child: CircularPercentIndicator( + radius: 100, + lineWidth: 10, + percent: timeProgress.percentDone(), + progressColor: Colors.green, + backgroundColor: Colors.red, + center: Text("${(timeProgress.percentDone() * 100).floor()} %"), + ), + ), + Expanded( + child: LinearPercentIndicator( + padding: EdgeInsets.symmetric(horizontal: 15), + percent: timeProgress.percentDone(), + leading: Text("${timeProgress.daysBehind()} Days"), + center: Text("${(timeProgress.percentDone() * 100).floor()} %"), + trailing: Text("${timeProgress.daysLeft()} Days"), + progressColor: Colors.green, + backgroundColor: Colors.red, + lineHeight: 25, + ), + ), + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 5ff120a..a0dfce6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.0.10+10 +version: 0.0.11+11 environment: sdk: ">=2.7.0 <3.0.0"