Task statuses

This commit is contained in:
Hillel Coren 2020-10-28 23:49:45 +02:00
parent 4f73e10874
commit 6fecfca836
7 changed files with 128 additions and 68 deletions

View File

@ -172,8 +172,8 @@ abstract class TaskEntity extends Object
createdAt: 0,
createdUserId: '',
vendorId: '',
taskStatusId: '',
taskStatusSortOrder: 0,
statusId: '',
statusSortOrder: 0,
documents: BuiltList<DocumentEntity>(),
);
}
@ -389,13 +389,11 @@ abstract class TaskEntity extends Object
@BuiltValueField(wireName: 'custom_value4')
String get customValue4;
@nullable
@BuiltValueField(wireName: 'task_status_id')
String get taskStatusId;
@BuiltValueField(wireName: 'status_id')
String get statusId;
@nullable
@BuiltValueField(wireName: 'task_status_sort_order')
int get taskStatusSortOrder;
@BuiltValueField(wireName: 'status_sort_order')
int get statusSortOrder;
@nullable
@BuiltValueField(wireName: 'vendor_id')

View File

@ -180,6 +180,12 @@ class _$TaskEntitySerializer implements StructuredSerializer<TaskEntity> {
'custom_value2',
serializers.serialize(object.customValue2,
specifiedType: const FullType(String)),
'status_id',
serializers.serialize(object.statusId,
specifiedType: const FullType(String)),
'status_sort_order',
serializers.serialize(object.statusSortOrder,
specifiedType: const FullType(int)),
'documents',
serializers.serialize(object.documents,
specifiedType: const FullType(
@ -226,18 +232,6 @@ class _$TaskEntitySerializer implements StructuredSerializer<TaskEntity> {
..add(serializers.serialize(object.customValue4,
specifiedType: const FullType(String)));
}
if (object.taskStatusId != null) {
result
..add('task_status_id')
..add(serializers.serialize(object.taskStatusId,
specifiedType: const FullType(String)));
}
if (object.taskStatusSortOrder != null) {
result
..add('task_status_sort_order')
..add(serializers.serialize(object.taskStatusSortOrder,
specifiedType: const FullType(int)));
}
if (object.vendorId != null) {
result
..add('vendor_id')
@ -330,12 +324,12 @@ class _$TaskEntitySerializer implements StructuredSerializer<TaskEntity> {
result.customValue4 = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'task_status_id':
result.taskStatusId = serializers.deserialize(value,
case 'status_id':
result.statusId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'task_status_sort_order':
result.taskStatusSortOrder = serializers.deserialize(value,
case 'status_sort_order':
result.statusSortOrder = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'vendor_id':
@ -690,9 +684,9 @@ class _$TaskEntity extends TaskEntity {
@override
final String customValue4;
@override
final String taskStatusId;
final String statusId;
@override
final int taskStatusSortOrder;
final int statusSortOrder;
@override
final String vendorId;
@override
@ -730,8 +724,8 @@ class _$TaskEntity extends TaskEntity {
this.customValue2,
this.customValue3,
this.customValue4,
this.taskStatusId,
this.taskStatusSortOrder,
this.statusId,
this.statusSortOrder,
this.vendorId,
this.documents,
this.isChanged,
@ -764,6 +758,12 @@ class _$TaskEntity extends TaskEntity {
if (customValue2 == null) {
throw new BuiltValueNullFieldError('TaskEntity', 'customValue2');
}
if (statusId == null) {
throw new BuiltValueNullFieldError('TaskEntity', 'statusId');
}
if (statusSortOrder == null) {
throw new BuiltValueNullFieldError('TaskEntity', 'statusSortOrder');
}
if (documents == null) {
throw new BuiltValueNullFieldError('TaskEntity', 'documents');
}
@ -804,8 +804,8 @@ class _$TaskEntity extends TaskEntity {
customValue2 == other.customValue2 &&
customValue3 == other.customValue3 &&
customValue4 == other.customValue4 &&
taskStatusId == other.taskStatusId &&
taskStatusSortOrder == other.taskStatusSortOrder &&
statusId == other.statusId &&
statusSortOrder == other.statusSortOrder &&
vendorId == other.vendorId &&
documents == other.documents &&
isChanged == other.isChanged &&
@ -847,8 +847,8 @@ class _$TaskEntity extends TaskEntity {
customValue2.hashCode),
customValue3.hashCode),
customValue4.hashCode),
taskStatusId.hashCode),
taskStatusSortOrder.hashCode),
statusId.hashCode),
statusSortOrder.hashCode),
vendorId.hashCode),
documents.hashCode),
isChanged.hashCode),
@ -876,8 +876,8 @@ class _$TaskEntity extends TaskEntity {
..add('customValue2', customValue2)
..add('customValue3', customValue3)
..add('customValue4', customValue4)
..add('taskStatusId', taskStatusId)
..add('taskStatusSortOrder', taskStatusSortOrder)
..add('statusId', statusId)
..add('statusSortOrder', statusSortOrder)
..add('vendorId', vendorId)
..add('documents', documents)
..add('isChanged', isChanged)
@ -943,14 +943,14 @@ class TaskEntityBuilder implements Builder<TaskEntity, TaskEntityBuilder> {
String get customValue4 => _$this._customValue4;
set customValue4(String customValue4) => _$this._customValue4 = customValue4;
String _taskStatusId;
String get taskStatusId => _$this._taskStatusId;
set taskStatusId(String taskStatusId) => _$this._taskStatusId = taskStatusId;
String _statusId;
String get statusId => _$this._statusId;
set statusId(String statusId) => _$this._statusId = statusId;
int _taskStatusSortOrder;
int get taskStatusSortOrder => _$this._taskStatusSortOrder;
set taskStatusSortOrder(int taskStatusSortOrder) =>
_$this._taskStatusSortOrder = taskStatusSortOrder;
int _statusSortOrder;
int get statusSortOrder => _$this._statusSortOrder;
set statusSortOrder(int statusSortOrder) =>
_$this._statusSortOrder = statusSortOrder;
String _vendorId;
String get vendorId => _$this._vendorId;
@ -1012,8 +1012,8 @@ class TaskEntityBuilder implements Builder<TaskEntity, TaskEntityBuilder> {
_customValue2 = _$v.customValue2;
_customValue3 = _$v.customValue3;
_customValue4 = _$v.customValue4;
_taskStatusId = _$v.taskStatusId;
_taskStatusSortOrder = _$v.taskStatusSortOrder;
_statusId = _$v.statusId;
_statusSortOrder = _$v.statusSortOrder;
_vendorId = _$v.vendorId;
_documents = _$v.documents?.toBuilder();
_isChanged = _$v.isChanged;
@ -1060,8 +1060,8 @@ class TaskEntityBuilder implements Builder<TaskEntity, TaskEntityBuilder> {
customValue2: customValue2,
customValue3: customValue3,
customValue4: customValue4,
taskStatusId: taskStatusId,
taskStatusSortOrder: taskStatusSortOrder,
statusId: statusId,
statusSortOrder: statusSortOrder,
vendorId: vendorId,
documents: documents.build(),
isChanged: isChanged,

View File

@ -74,6 +74,48 @@ List<String> filteredTaskStatusesSelector(
return list;
}
var memoizedCalculateTaskStatusAmount = memo2((String taskStatusId,
BuiltMap<String, TaskEntity> taskMap) =>
calculateTaskStatusAmount(taskStatusId: taskStatusId, taskMap: taskMap));
int calculateTaskStatusAmount({
String taskStatusId,
BuiltMap<String, TaskEntity> taskMap,
}) {
int total = 0;
taskMap.forEach((taskId, task) {
if (task.statusId == taskStatusId) {
total += task.calculateDuration.inSeconds;
}
});
return total;
}
var memoizedTaskStatsForTaskStatus = memo2(
(String companyGatewayId, BuiltMap<String, TaskEntity> taskMap) =>
taskStatsForTaskStatus(companyGatewayId, taskMap));
EntityStats taskStatsForTaskStatus(
String statusId,
BuiltMap<String, TaskEntity> taskMap,
) {
int countActive = 0;
int countArchived = 0;
taskMap.forEach((taskId, task) {
if (task.statusId == statusId) {
if (task.isActive) {
countActive++;
} else if (task.isArchived) {
countArchived++;
}
}
});
return EntityStats(countActive: countActive, countArchived: countArchived);
}
bool hasTaskStatusChanges(TaskStatusEntity taskStatus,
BuiltMap<String, TaskStatusEntity> taskStatusMap) =>
taskStatus.isNew

View File

@ -87,7 +87,6 @@ class _TaskEditDetailsState extends State<TaskEditDetails> {
final viewModel = widget.viewModel;
final localization = AppLocalization.of(context);
final task = viewModel.task;
final company = viewModel.company;
final state = viewModel.state;
return ListView(
@ -137,22 +136,20 @@ class _TaskEditDetailsState extends State<TaskEditDetails> {
.onChanged(task.rebuild((b) => b..assignedUserId = userId)),
),
// TODO Remove isNotEmpty check in v2
company.taskStatusMap.isNotEmpty
? EntityDropdown(
key: ValueKey('__task_status_${task.taskStatusId}__'),
allowClearing: false,
entityType: EntityType.taskStatus,
labelText: localization.status,
entityId: task.taskStatusId,
entityList: company.taskStatusMap.keys.toList(),
onSelected: (selected) {
final taskStatus = selected as TaskStatusEntity;
viewModel.onChanged(task.rebuild((b) => b
..taskStatusId = taskStatus?.id
..taskStatusSortOrder = 9999));
},
)
: SizedBox(),
EntityDropdown(
key: ValueKey('__task_status_${task.statusId}__'),
allowClearing: false,
entityType: EntityType.taskStatus,
labelText: localization.status,
entityId: task.statusId,
entityList: state.taskStatusState.list.toList(),
onSelected: (selected) {
final taskStatus = selected as TaskStatusEntity;
viewModel.onChanged(task.rebuild((b) => b
..statusId = taskStatus?.id
..statusSortOrder = 9999));
},
),
DecoratedFormField(
maxLines: 4,
controller: _descriptionController,

View File

@ -57,11 +57,9 @@ class _TaskOverviewState extends State<TaskOverview> {
final Map<String, String> fields = {};
// TODO Remove isNotEmpty check in v2
if (company.taskStatusMap.isNotEmpty &&
(task.taskStatusId ?? '').isNotEmpty) {
if ((task.statusId ?? '').isNotEmpty) {
fields[localization.status] =
company.taskStatusMap[task.taskStatusId]?.name ?? '';
company.taskStatusMap[task.statusId]?.name ?? '';
}
if (task.customValue1.isNotEmpty) {

View File

@ -31,7 +31,6 @@ class TaskStatusScreen extends StatelessWidget {
final userCompany = state.userCompany;
final localization = AppLocalization.of(context);
final listUIState = state.uiState.taskStatusUIState.listUIState;
final isInMultiselect = listUIState.isInMultiselect();
return ListScaffold(
entityType: EntityType.taskStatus,

View File

@ -1,7 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/task_status/task_status_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_list_tile.dart';
import 'package:invoiceninja_flutter/ui/app/entity_header.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
import 'package:invoiceninja_flutter/ui/task_status/view/task_status_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class TaskStatusView extends StatefulWidget {
const TaskStatusView({
@ -21,14 +28,33 @@ class _TaskStatusViewState extends State<TaskStatusView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final state = viewModel.state;
final taskStatus = viewModel.taskStatus;
final localization = AppLocalization.of(context);
final amount = memoizedCalculateTaskStatusAmount(
taskStatus.id, viewModel.state.taskState.map);
return ViewScaffold(
isFilter: widget.isFilter,
entity: taskStatus,
onBackPressed: () => viewModel.onBackPressed(),
body: ListView(
children: <Widget>[],
children: <Widget>[
EntityHeader(
entity: taskStatus,
label: localization.total,
value: formatDuration(Duration(seconds: amount))),
ListDivider(),
EntitiesListTile(
entity: taskStatus,
isFilter: widget.isFilter,
entityType: EntityType.task,
title: localization.tasks,
subtitle: memoizedTaskStatsForTaskStatus(
taskStatus.id, state.taskState.map)
.present(localization.active, localization.archived),
),
],
),
);
}