mirror of
https://github.com/go-vikunja/app
synced 2024-06-03 19:19:46 +00:00
056b2d72c9
This PR formats all code with dart format and adds a step to the CI so that it will be checked on every push and PR.
190 lines
5.5 KiB
Dart
190 lines
5.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:vikunja_app/components/TaskBottomSheet.dart';
|
|
import 'package:vikunja_app/models/task.dart';
|
|
import 'package:vikunja_app/utils/misc.dart';
|
|
import 'package:vikunja_app/pages/list/task_edit.dart';
|
|
import 'package:vikunja_app/utils/priority.dart';
|
|
|
|
import '../stores/project_store.dart';
|
|
|
|
class TaskTile extends StatefulWidget {
|
|
final Task task;
|
|
final Function onEdit;
|
|
final bool showInfo;
|
|
final bool loading;
|
|
final ValueSetter<bool>? onMarkedAsDone;
|
|
|
|
const TaskTile({
|
|
Key? key,
|
|
required this.task,
|
|
required this.onEdit,
|
|
this.loading = false,
|
|
this.showInfo = false,
|
|
this.onMarkedAsDone,
|
|
}) : super(key: key);
|
|
/*
|
|
@override
|
|
TaskTileState createState() {
|
|
return new TaskTileState(this.task, this.loading);
|
|
}
|
|
|
|
*/
|
|
@override
|
|
TaskTileState createState() => TaskTileState(this.task);
|
|
}
|
|
|
|
Widget? _buildTaskSubtitle(Task? task, bool showInfo, BuildContext context) {
|
|
Duration? durationUntilDue = task?.dueDate?.difference(DateTime.now());
|
|
|
|
if (task == null) return null;
|
|
|
|
List<TextSpan> texts = [];
|
|
|
|
if (showInfo && task.hasDueDate) {
|
|
texts.add(TextSpan(
|
|
text: "Due " + durationToHumanReadable(durationUntilDue!),
|
|
style: durationUntilDue.isNegative
|
|
? TextStyle(color: Colors.red)
|
|
: Theme.of(context).textTheme.bodyMedium));
|
|
}
|
|
if (task.priority != null && task.priority != 0) {
|
|
texts.add(TextSpan(
|
|
text: " !" + priorityToString(task.priority),
|
|
style: TextStyle(color: Colors.orange)));
|
|
}
|
|
|
|
//if(texts.isEmpty && task.description.isNotEmpty) {
|
|
// return HtmlWidget(task.description);
|
|
// }
|
|
|
|
if (texts.isNotEmpty) {
|
|
return RichText(text: TextSpan(children: texts));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
class TaskTileState extends State<TaskTile> with AutomaticKeepAliveClientMixin {
|
|
Task _currentTask;
|
|
|
|
TaskTileState(this._currentTask);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
super.build(context);
|
|
final taskState = Provider.of<ProjectProvider>(context);
|
|
if (_currentTask.loading) {
|
|
return ListTile(
|
|
leading: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: SizedBox(
|
|
height: Checkbox.width,
|
|
width: Checkbox.width,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2.0,
|
|
)),
|
|
),
|
|
title: Text(_currentTask.title),
|
|
subtitle: _currentTask.description.isEmpty
|
|
? null
|
|
: HtmlWidget(_currentTask.description),
|
|
trailing: IconButton(
|
|
icon: Icon(Icons.edit),
|
|
onPressed: () {},
|
|
),
|
|
);
|
|
}
|
|
return IntrinsicHeight(
|
|
child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
|
|
Container(
|
|
width: 4.0, // Adjust the width of the red line
|
|
color: widget.task.color,
|
|
//margin: EdgeInsets.only(left: 10.0),
|
|
),
|
|
Flexible(
|
|
child: ListTile(
|
|
onTap: () {
|
|
showModalBottomSheet<void>(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return TaskBottomSheet(
|
|
task: widget.task,
|
|
onEdit: widget.onEdit,
|
|
taskState: taskState);
|
|
});
|
|
},
|
|
title: widget.showInfo
|
|
? RichText(
|
|
text: TextSpan(
|
|
text: null,
|
|
children: <TextSpan>[
|
|
// TODO: get list name of task
|
|
//TextSpan(text: widget.task.list.title+" - ", style: TextStyle(color: Colors.grey)),
|
|
TextSpan(text: widget.task.title),
|
|
],
|
|
style: TextStyle(
|
|
color: Theme.of(context).brightness == Brightness.dark
|
|
? Colors.white
|
|
: Colors.black,
|
|
),
|
|
))
|
|
: Text(_currentTask.title),
|
|
subtitle: _buildTaskSubtitle(widget.task, widget.showInfo, context),
|
|
leading: Checkbox(
|
|
value: _currentTask.done,
|
|
onChanged: (bool? newValue) {
|
|
_change(newValue);
|
|
},
|
|
),
|
|
trailing: IconButton(
|
|
icon: Icon(Icons.edit),
|
|
onPressed: () {
|
|
Navigator.push<Task>(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (buildContext) => TaskEditPage(
|
|
task: _currentTask,
|
|
taskState: taskState,
|
|
),
|
|
),
|
|
)
|
|
.then((task) => setState(() {
|
|
if (task != null) _currentTask = task;
|
|
}))
|
|
.whenComplete(() => widget.onEdit());
|
|
}),
|
|
))
|
|
]));
|
|
}
|
|
|
|
void _change(bool? value) async {
|
|
value = value ?? false;
|
|
setState(() {
|
|
this._currentTask.loading = true;
|
|
});
|
|
Task? newTask = await _updateTask(_currentTask, value);
|
|
setState(() {
|
|
if (newTask != null) this._currentTask = newTask;
|
|
this._currentTask.loading = false;
|
|
});
|
|
widget.onEdit();
|
|
}
|
|
|
|
Future<Task?> _updateTask(Task task, bool checked) {
|
|
return Provider.of<ProjectProvider>(context, listen: false).updateTask(
|
|
context: context,
|
|
task: task.copyWith(
|
|
done: checked,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool get wantKeepAlive => _currentTask != widget.task;
|
|
}
|
|
|
|
typedef Future<void> TaskChanged(Task task, bool newValue);
|