1
0
mirror of https://github.com/go-vikunja/app synced 2024-06-19 10:54:17 +00:00
app-mirror-github/lib/components/BucketTaskCard.dart

193 lines
5.8 KiB
Dart
Raw Normal View History

2022-07-23 23:08:59 +00:00
import 'dart:math';
2022-07-15 14:25:16 +00:00
import 'package:flutter/material.dart';
import 'package:vikunja_app/models/task.dart';
2022-07-19 09:47:37 +00:00
import 'package:vikunja_app/pages/list/task_edit.dart';
2022-07-23 23:08:59 +00:00
import 'package:vikunja_app/utils/misc.dart';
2022-07-15 14:25:16 +00:00
import 'package:vikunja_app/theme/constants.dart';
class BucketTaskCard extends StatefulWidget {
final Task task;
const BucketTaskCard({Key key, @required this.task})
: assert(task != null),
super(key: key);
@override
State<BucketTaskCard> createState() => _BucketTaskCardState(this.task);
}
2022-07-27 18:48:16 +00:00
class _BucketTaskCardState extends State<BucketTaskCard> with AutomaticKeepAliveClientMixin {
2022-07-15 14:25:16 +00:00
Task _currentTask;
_BucketTaskCardState(this._currentTask)
: assert(_currentTask != null);
@override
Widget build(BuildContext context) {
2022-07-27 18:48:16 +00:00
super.build(context);
2022-07-23 23:08:59 +00:00
// default chip height: 32
const double chipHeight = 28;
final chipConstraints = BoxConstraints(maxHeight: chipHeight);
final theme = Theme.of(context);
2022-07-23 23:08:59 +00:00
2022-07-15 14:25:16 +00:00
final numRow = Row(
children: <Widget>[
2022-07-23 23:08:59 +00:00
Text(
'#${_currentTask.id}',
style: theme.textTheme.subtitle2.copyWith(
2022-07-23 23:08:59 +00:00
color: Colors.grey,
),
),
2022-07-15 14:25:16 +00:00
],
);
if (_currentTask.done) {
2022-07-23 23:08:59 +00:00
numRow.children.insert(0, Container(
constraints: chipConstraints,
padding: EdgeInsets.only(right: 4),
child: FittedBox(
child: Chip(
label: Text('Done'),
labelStyle: theme.textTheme.labelLarge.copyWith(
2022-07-23 23:08:59 +00:00
fontWeight: FontWeight.bold,
color: theme.brightness == Brightness.dark
2022-07-23 23:08:59 +00:00
? Colors.black : Colors.white,
),
backgroundColor: vGreen,
),
2022-07-15 14:25:16 +00:00
),
));
}
final titleRow = Row(
children: <Widget>[
2022-07-23 23:08:59 +00:00
Expanded(
child: Text(
_currentTask.title,
style: theme.textTheme.titleMedium.copyWith(
2022-07-23 23:08:59 +00:00
color: _currentTask.textColor,
),
),
),
2022-07-15 14:25:16 +00:00
],
);
2022-07-23 23:08:59 +00:00
final duration = _currentTask.dueDate.difference(DateTime.now());
if (_currentTask.dueDate.year > 2) {
titleRow.children.add(Container(
constraints: chipConstraints,
padding: EdgeInsets.only(left: 4),
child: FittedBox(
child: Chip(
avatar: Icon(
Icons.calendar_month,
color: duration.isNegative ? Colors.red : null,
),
label: Text(durationToHumanReadable(duration)),
labelStyle: theme.textTheme.labelLarge.copyWith(
color: duration.isNegative ? Colors.red : null,
),
2022-07-23 23:08:59 +00:00
backgroundColor: duration.isNegative ? Colors.red.withAlpha(20) : null,
),
),
));
}
2022-07-15 14:25:16 +00:00
2022-07-23 23:08:59 +00:00
final labelRow = Wrap(
children: <Widget>[],
spacing: 4,
runSpacing: 4,
);
_currentTask.labels?.sort((a, b) => a.title.compareTo(b.title));
_currentTask.labels?.asMap()?.forEach((i, label) {
labelRow.children.add(Chip(
label: Text(label.title),
labelStyle: theme.textTheme.labelLarge.copyWith(
color: label.textColor,
),
2022-07-23 23:08:59 +00:00
backgroundColor: label.color,
));
});
if (_currentTask.description.isNotEmpty) {
final uncompletedTaskCount = '* [ ]'.allMatches(_currentTask.description).length;
final completedTaskCount = '* [x]'.allMatches(_currentTask.description).length;
final taskCount = uncompletedTaskCount + completedTaskCount;
if (taskCount > 0) {
final iconSize = (theme.textTheme.labelLarge.fontSize ?? 14) + 2;
2022-07-23 23:08:59 +00:00
labelRow.children.add(Chip(
avatar: Container(
constraints: BoxConstraints(maxHeight: iconSize, maxWidth: iconSize),
2022-07-23 23:08:59 +00:00
child: CircularProgressIndicator(
value: uncompletedTaskCount == 0
? 1 : uncompletedTaskCount.toDouble() / taskCount.toDouble(),
backgroundColor: Colors.grey,
) ,
),
label: Text(
(uncompletedTaskCount == 0 ? '' : '$completedTaskCount of ')
+ '$taskCount tasks'
),
));
}
}
if (_currentTask.attachments != null && _currentTask.attachments.isNotEmpty) {
labelRow.children.add(Chip(
label: Transform.rotate(
angle: -pi / 4.0,
child: Icon(Icons.attachment),
),
));
}
if (_currentTask.description.isNotEmpty) {
labelRow.children.add(Chip(
label: Icon(Icons.notes),
));
}
2022-07-15 14:25:16 +00:00
2022-07-23 23:08:59 +00:00
final rowConstraints = BoxConstraints(minHeight: chipHeight);
2022-07-15 14:25:16 +00:00
return Card(
2022-07-23 23:08:59 +00:00
color: _currentTask.color,
2022-07-19 09:47:37 +00:00
child: InkWell(
2022-07-23 23:08:59 +00:00
child: Theme(
data: Theme.of(context).copyWith(
// Remove enforced margins
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: Padding(
padding: EdgeInsets.all(4),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
constraints: rowConstraints,
child: numRow,
),
Container(
constraints: rowConstraints,
child: titleRow,
),
Padding(
padding: labelRow.children.isNotEmpty
? EdgeInsets.only(top: 8) : EdgeInsets.zero,
child: labelRow,
),
],
),
),
2022-07-19 09:47:37 +00:00
),
onTap: () => Navigator.push<Task>(
2022-07-19 09:47:37 +00:00
context,
MaterialPageRoute(builder: (context) => TaskEditPage(
task: _currentTask,
)),
).then((task) => setState(() {
if (task != null) _currentTask = task;
})),
2022-07-15 14:25:16 +00:00
),
);
}
2022-07-27 18:48:16 +00:00
@override
bool get wantKeepAlive => _currentTask != widget.task;
2022-07-15 14:25:16 +00:00
}