Task item details

This commit is contained in:
Hillel Coren 2023-03-22 17:17:13 +02:00
parent cd826cd709
commit b0886f5ccd
3 changed files with 94 additions and 166 deletions

View File

@ -85,13 +85,20 @@ class TaskFields {
} }
abstract class TaskTime implements Built<TaskTime, TaskTimeBuilder> { abstract class TaskTime implements Built<TaskTime, TaskTimeBuilder> {
factory TaskTime({DateTime startDate, DateTime endDate}) { factory TaskTime({
DateTime startDate,
DateTime endDate,
String description,
bool isBillable,
}) {
return _$TaskTime._( return _$TaskTime._(
startDate: startDate ?? startDate: startDate ??
DateTime.fromMillisecondsSinceEpoch( DateTime.fromMillisecondsSinceEpoch(
(DateTime.now().millisecondsSinceEpoch / 1000).floor() * 1000, (DateTime.now().millisecondsSinceEpoch / 1000).floor() * 1000,
isUtc: true), isUtc: true),
endDate: endDate, endDate: endDate,
description: description ?? '',
isBillable: isBillable ?? true,
); );
} }
@ -107,6 +114,10 @@ abstract class TaskTime implements Built<TaskTime, TaskTimeBuilder> {
@nullable @nullable
DateTime get endDate; DateTime get endDate;
String get description;
bool get isBillable;
Duration get duration => (endDate ?? DateTime.now()).difference(startDate); Duration get duration => (endDate ?? DateTime.now()).difference(startDate);
List<dynamic> get asList { List<dynamic> get asList {

View File

@ -109,7 +109,14 @@ class _$TaskTimeSerializer implements StructuredSerializer<TaskTime> {
@override @override
Iterable<Object> serialize(Serializers serializers, TaskTime object, Iterable<Object> serialize(Serializers serializers, TaskTime object,
{FullType specifiedType = FullType.unspecified}) { {FullType specifiedType = FullType.unspecified}) {
final result = <Object>[]; final result = <Object>[
'description',
serializers.serialize(object.description,
specifiedType: const FullType(String)),
'isBillable',
serializers.serialize(object.isBillable,
specifiedType: const FullType(bool)),
];
Object value; Object value;
value = object.startDate; value = object.startDate;
if (value != null) { if (value != null) {
@ -147,6 +154,14 @@ class _$TaskTimeSerializer implements StructuredSerializer<TaskTime> {
result.endDate = serializers.deserialize(value, result.endDate = serializers.deserialize(value,
specifiedType: const FullType(DateTime)) as DateTime; specifiedType: const FullType(DateTime)) as DateTime;
break; break;
case 'description':
result.description = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'isBillable':
result.isBillable = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
} }
} }
@ -559,11 +574,22 @@ class _$TaskTime extends TaskTime {
final DateTime startDate; final DateTime startDate;
@override @override
final DateTime endDate; final DateTime endDate;
@override
final String description;
@override
final bool isBillable;
factory _$TaskTime([void Function(TaskTimeBuilder) updates]) => factory _$TaskTime([void Function(TaskTimeBuilder) updates]) =>
(new TaskTimeBuilder()..update(updates))._build(); (new TaskTimeBuilder()..update(updates))._build();
_$TaskTime._({this.startDate, this.endDate}) : super._(); _$TaskTime._(
{this.startDate, this.endDate, this.description, this.isBillable})
: super._() {
BuiltValueNullFieldError.checkNotNull(
description, r'TaskTime', 'description');
BuiltValueNullFieldError.checkNotNull(
isBillable, r'TaskTime', 'isBillable');
}
@override @override
TaskTime rebuild(void Function(TaskTimeBuilder) updates) => TaskTime rebuild(void Function(TaskTimeBuilder) updates) =>
@ -577,7 +603,9 @@ class _$TaskTime extends TaskTime {
if (identical(other, this)) return true; if (identical(other, this)) return true;
return other is TaskTime && return other is TaskTime &&
startDate == other.startDate && startDate == other.startDate &&
endDate == other.endDate; endDate == other.endDate &&
description == other.description &&
isBillable == other.isBillable;
} }
int __hashCode; int __hashCode;
@ -587,6 +615,8 @@ class _$TaskTime extends TaskTime {
var _$hash = 0; var _$hash = 0;
_$hash = $jc(_$hash, startDate.hashCode); _$hash = $jc(_$hash, startDate.hashCode);
_$hash = $jc(_$hash, endDate.hashCode); _$hash = $jc(_$hash, endDate.hashCode);
_$hash = $jc(_$hash, description.hashCode);
_$hash = $jc(_$hash, isBillable.hashCode);
_$hash = $jf(_$hash); _$hash = $jf(_$hash);
return __hashCode ??= _$hash; return __hashCode ??= _$hash;
} }
@ -595,7 +625,9 @@ class _$TaskTime extends TaskTime {
String toString() { String toString() {
return (newBuiltValueToStringHelper(r'TaskTime') return (newBuiltValueToStringHelper(r'TaskTime')
..add('startDate', startDate) ..add('startDate', startDate)
..add('endDate', endDate)) ..add('endDate', endDate)
..add('description', description)
..add('isBillable', isBillable))
.toString(); .toString();
} }
} }
@ -611,6 +643,14 @@ class TaskTimeBuilder implements Builder<TaskTime, TaskTimeBuilder> {
DateTime get endDate => _$this._endDate; DateTime get endDate => _$this._endDate;
set endDate(DateTime endDate) => _$this._endDate = endDate; set endDate(DateTime endDate) => _$this._endDate = endDate;
String _description;
String get description => _$this._description;
set description(String description) => _$this._description = description;
bool _isBillable;
bool get isBillable => _$this._isBillable;
set isBillable(bool isBillable) => _$this._isBillable = isBillable;
TaskTimeBuilder(); TaskTimeBuilder();
TaskTimeBuilder get _$this { TaskTimeBuilder get _$this {
@ -618,6 +658,8 @@ class TaskTimeBuilder implements Builder<TaskTime, TaskTimeBuilder> {
if ($v != null) { if ($v != null) {
_startDate = $v.startDate; _startDate = $v.startDate;
_endDate = $v.endDate; _endDate = $v.endDate;
_description = $v.description;
_isBillable = $v.isBillable;
_$v = null; _$v = null;
} }
return this; return this;
@ -638,8 +680,14 @@ class TaskTimeBuilder implements Builder<TaskTime, TaskTimeBuilder> {
TaskTime build() => _build(); TaskTime build() => _build();
_$TaskTime _build() { _$TaskTime _build() {
final _$result = final _$result = _$v ??
_$v ?? new _$TaskTime._(startDate: startDate, endDate: endDate); new _$TaskTime._(
startDate: startDate,
endDate: endDate,
description: BuiltValueNullFieldError.checkNotNull(
description, r'TaskTime', 'description'),
isBillable: BuiltValueNullFieldError.checkNotNull(
isBillable, r'TaskTime', 'isBillable'));
replace(_$result); replace(_$result);
return _$result; return _$result;
} }

View File

@ -125,6 +125,7 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
final state = viewModel.state; final state = viewModel.state;
final company = state.company; final company = state.company;
final settings = company.settings;
final client = state.clientState.get(task.clientId); final client = state.clientState.get(task.clientId);
final showEndDate = company.showTaskEndDate; final showEndDate = company.showTaskEndDate;
final taskTimes = task.getTaskTimes(sort: false); final taskTimes = task.getTaskTimes(sort: false);
@ -303,16 +304,17 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
key: ValueKey('__table_${_updatedAt}__'), key: ValueKey('__table_${_updatedAt}__'),
padding: const EdgeInsets.symmetric(horizontal: kMobileDialogPadding), padding: const EdgeInsets.symmetric(horizontal: kMobileDialogPadding),
children: [ children: [
Row( if (!settings.showTaskItemDescription)
children: [ Row(
Expanded(child: Text(localization.startDate)), children: [
Expanded(child: Text(localization.startTime)), Expanded(child: Text(localization.startDate)),
if (showEndDate) Expanded(child: Text(localization.endDate)), Expanded(child: Text(localization.startTime)),
Expanded(child: Text(localization.endTime)), if (showEndDate) Expanded(child: Text(localization.endDate)),
Expanded(child: Text(localization.duration)), Expanded(child: Text(localization.endTime)),
SizedBox(width: 40), Expanded(child: Text(localization.duration)),
], SizedBox(width: 40),
), ],
),
...taskTimes.map((taskTime) { ...taskTimes.map((taskTime) {
final index = taskTimes.indexOf(taskTime); final index = taskTimes.indexOf(taskTime);
return Row( return Row(
@ -331,6 +333,9 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
child: DatePicker( child: DatePicker(
key: ValueKey( key: ValueKey(
'__${_startTimeUpdatedAt}_${_durationUpdateAt}_${index}__'), '__${_startTimeUpdatedAt}_${_durationUpdateAt}_${index}__'),
labelText: settings.showTaskItemDescription
? localization.startDate
: null,
selectedDate: taskTimes[index].startDate == selectedDate: taskTimes[index].startDate ==
null null
? null ? null
@ -357,6 +362,9 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
child: TimePicker( child: TimePicker(
key: ValueKey( key: ValueKey(
'__${_durationUpdateAt}_${index}__'), '__${_durationUpdateAt}_${index}__'),
labelText: settings.showTaskItemDescription
? localization.startTime
: null,
selectedDateTime: taskTimes[index].startDate, selectedDateTime: taskTimes[index].startDate,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
final taskTime = taskTimes[index] final taskTime = taskTimes[index]
@ -379,6 +387,9 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
child: DatePicker( child: DatePicker(
key: ValueKey( key: ValueKey(
'__${_startDateUpdatedAt}_${_durationUpdateAt}_${_endTimeUpdatedAt}_${index}__'), '__${_startDateUpdatedAt}_${_durationUpdateAt}_${_endTimeUpdatedAt}_${index}__'),
labelText: settings.showTaskItemDescription
? localization.endDate
: null,
selectedDate: taskTimes[index].endDate == selectedDate: taskTimes[index].endDate ==
null null
? null ? null
@ -404,6 +415,9 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
child: TimePicker( child: TimePicker(
key: ValueKey( key: ValueKey(
'__${_endDateUpdatedAt}_${_durationUpdateAt}_${index}__'), '__${_endDateUpdatedAt}_${_durationUpdateAt}_${index}__'),
labelText: settings.showTaskItemDescription
? localization.endTime
: null,
selectedDateTime: taskTimes[index].endDate, selectedDateTime: taskTimes[index].endDate,
isEndTime: true, isEndTime: true,
onSelected: (timeOfDay) { onSelected: (timeOfDay) {
@ -426,6 +440,9 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
child: DurationPicker( child: DurationPicker(
key: ValueKey( key: ValueKey(
'__${_startTimeUpdatedAt}_${_endTimeUpdatedAt}_${_startDateUpdatedAt}_${_endDateUpdatedAt}_${index}__'), '__${_startTimeUpdatedAt}_${_endTimeUpdatedAt}_${_startDateUpdatedAt}_${_endDateUpdatedAt}_${index}__'),
labelText: settings.showTaskItemDescription
? localization.duration
: null,
onSelected: (Duration duration) { onSelected: (Duration duration) {
final taskTime = taskTimes[index] final taskTime = taskTimes[index]
.copyWithDuration(duration); .copyWithDuration(duration);
@ -446,7 +463,7 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
), ),
], ],
), ),
if (company.settings.showTaskItemDescription) if (settings.showTaskItemDescription)
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 16, right: 16), const EdgeInsets.only(bottom: 16, right: 16),
@ -484,154 +501,6 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
}).toList(), }).toList(),
], ],
), ),
/*
FormCard(
padding: const EdgeInsets.symmetric(horizontal: kMobileDialogPadding),
child: Table(
key: ValueKey('__table_old_${_updatedAt}__'),
columnWidths: {
showEndDate ? 5 : 4: FixedColumnWidth(kMinInteractiveDimension),
},
children: [
TableRow(
children: [
TableHeader(localization.startDate, isFirst: true),
TableHeader(localization.startTime),
if (showEndDate) TableHeader(localization.endDate),
TableHeader(localization.endTime),
TableHeader(localization.duration),
TableHeader(''),
],
decoration: tableHeaderColor.isNotEmpty
? BoxDecoration(
color: convertHexStringToColor(tableHeaderColor),
)
: null,
),
for (var index = 0; index < taskTimes.length; index++) ...[
TableRow(children: [
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: DatePicker(
key: ValueKey(
'__${_startTimeUpdatedAt}_${_durationUpdateAt}_${index}__'),
selectedDate: taskTimes[index].startDate == null
? null
: convertDateTimeToSqlDate(
taskTimes[index].startDate.toLocal()),
onSelected: (date, _) {
final taskTime = taskTimes[index]
.copyWithStartDate(date, syncDates: !showEndDate);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_startDateUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TimePicker(
key: ValueKey('__${_durationUpdateAt}_${index}__'),
selectedDateTime: taskTimes[index].startDate,
onSelected: (timeOfDay) {
final taskTime =
taskTimes[index].copyWithStartTime(timeOfDay);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_startTimeUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
if (showEndDate)
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: DatePicker(
key: ValueKey(
'__${_startDateUpdatedAt}_${_durationUpdateAt}_${_endTimeUpdatedAt}_${index}__'),
selectedDate: taskTimes[index].endDate == null
? null
: convertDateTimeToSqlDate(
taskTimes[index].endDate.toLocal()),
onSelected: (date, _) {
final taskTime =
taskTimes[index].copyWithEndDate(date);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_endDateUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TimePicker(
key: ValueKey(
'__${_endDateUpdatedAt}_${_durationUpdateAt}_${index}__'),
selectedDateTime: taskTimes[index].endDate,
isEndTime: true,
onSelected: (timeOfDay) {
final taskTime =
taskTimes[index].copyWithEndTime(timeOfDay);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_endTimeUpdatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: DurationPicker(
key: ValueKey(
'__${_startTimeUpdatedAt}_${_endTimeUpdatedAt}_${_startDateUpdatedAt}_${_endDateUpdatedAt}_${index}__'),
onSelected: (Duration duration) {
final taskTime =
taskTimes[index].copyWithDuration(duration);
viewModel.onUpdatedTaskTime(taskTime, index);
setState(() {
_durationUpdateAt =
DateTime.now().millisecondsSinceEpoch;
});
},
selectedDuration: (taskTimes[index].startDate == null ||
taskTimes[index].endDate == null)
? null
: taskTimes[index].duration,
),
),
Padding(
padding: const EdgeInsets.only(top: 4),
child: IconButton(
icon: Icon(
Icons.clear,
color: overlapping.contains(index) ? Colors.red : null,
),
tooltip: overlapping.contains(index)
? localization.invalidTime
: localization.remove,
onPressed: taskTimes[index].isEmpty
? null
: () {
viewModel.onRemoveTaskTime(index);
setState(() {
_updatedAt =
DateTime.now().millisecondsSinceEpoch;
});
},
),
),
]),
],
],
),
),
*/
SizedBox( SizedBox(
height: kMobileDialogPadding, height: kMobileDialogPadding,
), ),