1
0
mirror of https://github.com/go-vikunja/app synced 2024-06-01 02:06:51 +00:00

add buckets, add/edit tasks in buckets

This commit is contained in:
Paul Nettleton 2022-07-19 04:47:37 -05:00
parent ad665e68cc
commit b10a6577a1
5 changed files with 103 additions and 15 deletions

View File

@ -5,10 +5,9 @@ import 'package:vikunja_app/models/task.dart';
class BucketListView extends StatefulWidget {
final Bucket bucket;
final Function onEdit;
final Function onAddTask;
const BucketListView({Key key, @required this.bucket, this.onEdit, this.onAddTask})
const BucketListView({Key key, @required this.bucket, this.onAddTask})
: assert(bucket != null),
super(key: key);
@ -35,8 +34,14 @@ class _BucketListViewState extends State<BucketListView> {
final index = i - 1;
if (_currentBucket.tasks == null || index >= _currentBucket.tasks.length)
if (_currentBucket.tasks == null || index >= _currentBucket.tasks.length) {
if (index == 0 || index == _currentBucket.tasks?.length)
return TextButton(
onPressed: widget.onAddTask,
child: Text('+ Add Task'),
);
return null;
}
return index < _currentBucket.tasks.length
? _buildBucketTaskTile(_currentBucket.tasks[index])

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:vikunja_app/models/task.dart';
import 'package:vikunja_app/pages/list/task_edit.dart';
import 'package:vikunja_app/theme/constants.dart';
class BucketTaskCard extends StatefulWidget {
@ -51,9 +52,17 @@ class _BucketTaskCardState extends State<BucketTaskCard> {
// TODO: add labels, checklist completion, attachment icon, description icon
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[numRow, titleRow, labelRow],
child: InkWell(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[numRow, titleRow, labelRow],
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => TaskEditPage(
task: _currentTask,
)),
),
),
);
}

View File

@ -7,7 +7,7 @@ import 'package:vikunja_app/models/user.dart';
@JsonSerializable()
class Task {
int id, parentTaskId, priority, listId;
int id, parentTaskId, priority, listId, bucketId;
DateTime created, updated, dueDate, startDate, endDate;
List<DateTime> reminderDates;
String title, description;
@ -17,6 +17,7 @@ class Task {
List<Task> subtasks;
List<Label> labels;
bool loading = false;
// TODO: add kanbanPosition, position(?)
Task(
{@required this.id,
@ -35,7 +36,8 @@ class Task {
this.created,
this.updated,
this.createdBy,
this.listId});
this.listId,
this.bucketId});
Task.fromJson(Map<String, dynamic> json)
: id = json['id'],
@ -63,6 +65,7 @@ class Task {
updated = DateTime.parse(json['updated']),
created = DateTime.parse(json['created']),
listId = json['list_id'],
bucketId = json['bucket_id'],
createdBy = json['created_by'] == null
? null
: User.fromJson(json['created_by']);
@ -81,6 +84,7 @@ class Task {
'repeat_after': repeatAfter?.inSeconds,
'labels': labels?.map((label) => label.toJSON())?.toList(),
'subtasks': subtasks?.map((subtask) => subtask.toJSON())?.toList(),
'bucket_id': bucketId,
'created_by': createdBy?.toJSON(),
'updated': updated?.toUtc()?.toIso8601String(),
'created': created?.toUtc()?.toIso8601String(),

View File

@ -148,13 +148,19 @@ class _ListPageState extends State<ListPage> {
);
}
ListView _kanbanView(BuildContext context) {
ListView _kanbanView(BuildContext buildContext) {
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(vertical: 10),
itemBuilder: (context, i) {
if (taskState.maxPages == _currentPage && i == taskState.buckets.length)
if (taskState.maxPages == _currentPage && i >= taskState.buckets.length) {
if (i == taskState.buckets.length)
return TextButton(
onPressed: () => _addBucketDialog(buildContext),
child: Text('+ Create Bucket'),
);
return null;
}
if (i >= taskState.buckets.length && _currentPage < taskState.maxPages) {
_currentPage++;
@ -195,6 +201,7 @@ class _ListPageState extends State<ListPage> {
BucketListView _buildBucketTile(Bucket bucket) {
return BucketListView(
bucket: bucket,
onAddTask: () => _addItemDialog(context, bucket),
);
}
@ -250,11 +257,11 @@ class _ListPageState extends State<ListPage> {
);
}
_addItemDialog(BuildContext context) {
_addItemDialog(BuildContext context, [Bucket bucket]) {
showDialog(
context: context,
builder: (_) => AddDialog(
onAdd: (title) => _addItem(title, context),
onAdd: (title) => _addItem(title, context, bucket),
decoration: InputDecoration(
labelText: 'Task Name',
hintText: 'eg. Milk',
@ -263,13 +270,14 @@ class _ListPageState extends State<ListPage> {
);
}
_addItem(String title, BuildContext context) {
_addItem(String title, BuildContext context, [Bucket bucket]) {
var globalState = VikunjaGlobal.of(context);
var newTask = Task(
id: null,
title: title,
createdBy: globalState.currentUser,
done: false,
bucketId: bucket?.id,
);
setState(() => _loadingTasks.add(newTask));
Provider.of<ListProvider>(context, listen: false)
@ -280,11 +288,42 @@ class _ListPageState extends State<ListPage> {
)
.then((_) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The task was added successfully!'),
content: Text('The task was added successfully' + (bucket != null ? ' to ${bucket.title}' : '') + '!'),
));
setState(() {
_loadingTasks.remove(newTask);
});
});
}
_addBucketDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => AddDialog(
onAdd: (title) => _addBucket(title, context),
decoration: InputDecoration(
labelText: 'New Bucket Name',
hintText: 'eg. To Do',
),
)
);
}
_addBucket(String title, BuildContext context) {
Provider.of<ListProvider>(context, listen: false).addBucket(
context: context,
newBucket: Bucket(
id: null,
title: title,
createdBy: VikunjaGlobal.of(context).currentUser,
listId: _list.id,
),
listId: _list.id,
).then((_) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The bucket was added successfully!'),
));
setState(() {});
});
}
}

View File

@ -102,7 +102,16 @@ class ListProvider with ChangeNotifier {
notifyListeners();
return globalState.taskService.add(listId, newTask).then((task) {
_tasks.insert(0, task);
if (newTask.bucketId == null) {
_tasks.insert(0, task);
} else {
final bucket = _buckets[_buckets.indexWhere((b) => task.bucketId == b.id)];
if (bucket.tasks != null) {
bucket.tasks.add(task);
} else {
bucket.tasks = <Task>[task];
}
}
_isLoading = false;
notifyListeners();
});
@ -126,4 +135,26 @@ class ListProvider with ChangeNotifier {
notifyListeners();
});
}
Future<void> addBucket({BuildContext context, Bucket newBucket, int listId}) {
_isLoading = true;
notifyListeners();
return VikunjaGlobal.of(context).bucketService.add(listId, newBucket)
.then((bucket) {
_buckets.add(bucket);
_isLoading = false;
notifyListeners();
});
}
Future<void> updateBucket({BuildContext context, Bucket bucket}) {
_isLoading = true;
notifyListeners();
return VikunjaGlobal.of(context).bucketService.update(bucket)
.then((rBucket) {
_buckets[_buckets.indexWhere((b) => rBucket.id == b.id)] = rBucket;
_isLoading = false;
notifyListeners();
});
}
}