diff --git a/lib/data/models/task_model.dart b/lib/data/models/task_model.dart index 23b1629e0..94e527402 100644 --- a/lib/data/models/task_model.dart +++ b/lib/data/models/task_model.dart @@ -74,9 +74,13 @@ abstract class TaskTime implements Built { endDate != null ? (endDate.millisecondsSinceEpoch / 1000).floor() : 0 ]; + TaskTime get stop => rebuild((b) => b..endDate = DateTime.now().toUtc()); + bool equalTo(TaskTime taskTime) => startDate == taskTime.startDate && endDate == taskTime.endDate; + bool get isRunning => endDate == null; + static Serializer get serializer => _$taskTimeSerializer; } @@ -94,7 +98,7 @@ abstract class TaskEntity extends Object timeLog: isRunning ? '[[${(DateTime.now().millisecondsSinceEpoch / 1000).floor()},0]]' : '', - isRunning: false, + isRunning: isRunning, customValue1: '', customValue2: '', updatedAt: 0, @@ -132,7 +136,8 @@ abstract class TaskEntity extends Object final taskTime = TaskTime( startDate: convertTimestampToDate(startDate).toUtc(), - endDate: endDate > 0 ? convertTimestampToDate(endDate).toUtc() : null); + endDate: + endDate > 0 ? convertTimestampToDate(endDate).toUtc() : null); details.add(taskTime); }); @@ -140,31 +145,43 @@ abstract class TaskEntity extends Object return details; } - String addTaskTime(TaskTime time) { + TaskEntity addTaskTime(TaskTime time) { final List taskTimes = - timeLog.isNotEmpty ? jsonDecode(timeLog) : []; + timeLog.isNotEmpty ? jsonDecode(timeLog) : []; taskTimes.add(time.asList); - return jsonEncode(taskTimes); + return rebuild((b) => b + ..timeLog = jsonEncode(taskTimes) + ..isRunning = time.isRunning); } - String updateTaskTime(TaskTime time, int index) { + TaskEntity updateTaskTime(TaskTime time, int index) { final List taskTimes = - timeLog.isNotEmpty ? jsonDecode(timeLog) : []; + timeLog.isNotEmpty ? jsonDecode(timeLog) : []; taskTimes[index] = time.asList; - return jsonEncode(taskTimes); + final bool isRunning = + taskTimes.last != null && taskTimes.length > 1 && taskTimes.last > 0; + + return rebuild((b) => b + ..timeLog = jsonEncode(taskTimes) + ..isRunning = isRunning); } - String deleteTaskTime(int index) { + TaskEntity deleteTaskTime(int index) { final List taskTimes = - timeLog.isNotEmpty ? jsonDecode(timeLog) : []; + timeLog.isNotEmpty ? jsonDecode(timeLog) : []; taskTimes.removeAt(index); - return jsonEncode(taskTimes); + final bool isRunning = + taskTimes.last != null && taskTimes.length > 1 && taskTimes.last > 0; + + return rebuild((b) => b + ..timeLog = jsonEncode(taskTimes) + ..isRunning = isRunning); } double calculateAmount(double taskRate) => diff --git a/lib/redux/task/task_reducer.dart b/lib/redux/task/task_reducer.dart index 44ffbdde9..7817fa18b 100644 --- a/lib/redux/task/task_reducer.dart +++ b/lib/redux/task/task_reducer.dart @@ -106,16 +106,15 @@ ListUIState _sortTasks(ListUIState taskListState, SortTasks action) { } TaskEntity _addTaskTime(TaskEntity task, AddTaskTime action) { - return task.rebuild((b) => b..timeLog = task.addTaskTime(action.taskTime)); + return task.addTaskTime(action.taskTime); } TaskEntity _removeTaskTime(TaskEntity task, DeleteTaskTime action) { - return task.rebuild((b) => b..timeLog = task.deleteTaskTime(action.index)); + return task.deleteTaskTime(action.index); } TaskEntity _updateTaskTime(TaskEntity task, UpdateTaskTime action) { - return task.rebuild( - (b) => b..timeLog = task.updateTaskTime(action.taskTime, action.index)); + return task.updateTaskTime(action.taskTime, action.index); } final tasksReducer = combineReducers([ diff --git a/lib/ui/task/view/task_view.dart b/lib/ui/task/view/task_view.dart index d0be2b38c..1645f0bfd 100644 --- a/lib/ui/task/view/task_view.dart +++ b/lib/ui/task/view/task_view.dart @@ -58,6 +58,7 @@ class _TaskViewState extends State { List _buildView() { final widgets = [ TwoValueHeader( + backgroundColor: task.isRunning ? Colors.green : null, label1: localization.duration, value1: formatDuration(task.calculateDuration), label2: localization.amount, @@ -166,10 +167,10 @@ class _TaskViewState extends State { }, ), floatingActionButton: FloatingActionButton( - backgroundColor: Theme.of(context).primaryColorDark, - onPressed: () => null, + backgroundColor: task.isRunning ? Colors.red : Colors.green, + onPressed: () => viewModel.onFabPressed(), child: Icon( - Icons.add, + task.isRunning ? Icons.stop : Icons.play_arrow, color: Colors.white, ), tooltip: localization.newTask, diff --git a/lib/ui/task/view/task_view_vm.dart b/lib/ui/task/view/task_view_vm.dart index 00d276a27..84c597bf6 100644 --- a/lib/ui/task/view/task_view_vm.dart +++ b/lib/ui/task/view/task_view_vm.dart @@ -38,6 +38,7 @@ class TaskViewScreen extends StatelessWidget { class TaskViewVM { TaskViewVM({ + @required this.onFabPressed, @required this.task, @required this.client, @required this.project, @@ -76,6 +77,16 @@ class TaskViewVM { task: task, client: client, project: project, + onFabPressed: () { + if (task.isRunning) { + final taskTimes = task.taskTimes; + final taskTime = taskTimes.last.stop; + store.dispatch(UpdateTaskTime( + index: taskTimes.length - 1, taskTime: taskTime)); + } else { + store.dispatch(AddTaskTime(TaskTime())); + } + }, onClientPressed: (context, [longPress = false]) { if (longPress) { store.dispatch(EditClient(client: client, context: context)); @@ -92,18 +103,18 @@ class TaskViewVM { } }, onEditPressed: (BuildContext context, [TaskTime taskItem]) { - final Completer completer = - new Completer(); + final Completer completer = new Completer(); store.dispatch(EditTask( - task: task, - taskTime: taskItem, - context: context, - completer: completer,)); + task: task, + taskTime: taskItem, + context: context, + completer: completer, + )); completer.future.then((task) { Scaffold.of(context).showSnackBar(SnackBar( content: SnackBarRow( - message: AppLocalization.of(context).updatedTask, - ))); + message: AppLocalization.of(context).updatedTask, + ))); }); }, onRefreshed: (context) => _handleRefresh(context), @@ -140,6 +151,7 @@ class TaskViewVM { final Function(BuildContext, EntityAction) onActionSelected; final Function(BuildContext, [TaskTime]) onEditPressed; final Function onBackPressed; + final Function onFabPressed; final Function(BuildContext) onRefreshed; final Function(BuildContext, [bool]) onClientPressed; final Function(BuildContext, [bool]) onProjectPressed;