Task item details
This commit is contained in:
parent
cd826cd709
commit
b0886f5ccd
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,6 +304,7 @@ 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: [
|
||||||
|
if (!settings.showTaskItemDescription)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: Text(localization.startDate)),
|
Expanded(child: Text(localization.startDate)),
|
||||||
|
|
@ -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,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue