chore: removed all references to namespaces and lists (old names for what projects are now)

This commit is contained in:
Benimautner 2024-04-29 16:45:42 +02:00
parent 828a57a642
commit 4e78b5615e
18 changed files with 10 additions and 1130 deletions

View File

@ -1,108 +0,0 @@
import 'dart:async';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:vikunja_app/api/client.dart';
import 'package:vikunja_app/api/service.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/service/services.dart';
class ListAPIService extends APIService implements ListService {
FlutterSecureStorage _storage;
ListAPIService(Client client, FlutterSecureStorage storage)
: _storage = storage,
super(client);
@override
Future<TaskList?> create(namespaceId, TaskList tl) {
tl.namespaceId = namespaceId;
return client
.put('/namespaces/$namespaceId/lists', body: tl.toJSON())
.then((response) {
if (response == null) return null;
return TaskList.fromJson(response.body);
});
}
@override
Future delete(int listId) {
return client.delete('/lists/$listId').then((_) {});
}
@override
Future<TaskList?> get(int listId) {
return client.get('/lists/$listId').then((response) {
if (response == null) return null;
final map = response.body;
if (map.containsKey('id')) {
return client.get("/lists/$listId/tasks").then((tasks) {
map['tasks'] = tasks?.body;
return TaskList.fromJson(map);
});
}
return TaskList.fromJson(map);
});
}
@override
Future<List<TaskList>?> getAll() {
return client.get('/lists').then((list) {
if (list == null || list.statusCode != 200) return null;
if (list.body.toString().isEmpty) return Future.value([]);
print(list.statusCode);
return convertList(list.body, (result) => TaskList.fromJson(result));
});
}
@override
Future<List<TaskList>?> getByNamespace(int namespaceId) {
// TODO there needs to be a better way for this. /namespaces/-2/lists should
// return favorite lists
if (namespaceId == -2) {
// Favourites.
return getAll().then((value) {
if (value == null) return null;
value.removeWhere((element) => !element.isFavorite);
return value;
});
}
return client.get('/namespaces/$namespaceId/lists').then((list) {
if (list == null || list.statusCode != 200) return null;
return convertList(list.body, (result) => TaskList.fromJson(result));
});
}
@override
Future<TaskList?> update(TaskList tl) {
return client.post('/lists/${tl.id}', body: tl.toJSON()).then((response) {
if (response == null) return null;
return TaskList.fromJson(response.body);
});
}
@override
Future<String> getDisplayDoneTasks(int listId) {
return _storage.read(key: "display_done_tasks_list_$listId").then((value) {
if (value == null) {
// TODO: implement default value
setDisplayDoneTasks(listId, "1");
return Future.value("1");
}
return value;
});
}
@override
void setDisplayDoneTasks(int listId, String value) {
_storage.write(key: "display_done_tasks_list_$listId", value: value);
}
@override
Future<String?> getDefaultList() {
return _storage.read(key: "default_list_id");
}
@override
void setDefaultList(int? listId) {
_storage.write(key: "default_list_id", value: listId.toString());
}
}

View File

@ -1,49 +0,0 @@
import 'dart:async';
import 'dart:developer';
import 'package:vikunja_app/api/client.dart';
import 'package:vikunja_app/api/service.dart';
import 'package:vikunja_app/models/namespace.dart';
import 'package:vikunja_app/service/services.dart';
class NamespaceAPIService extends APIService implements NamespaceService {
NamespaceAPIService(Client client) : super(client);
@override
Future<Namespace?> create(Namespace ns) {
return client.put('/namespaces', body: ns.toJSON()).then((response) {
if (response == null) return null;
return Namespace.fromJson(response.body);
});
}
@override
Future delete(int namespaceId) {
return client.delete('/namespaces/$namespaceId');
}
@override
Future<Namespace?> get(int namespaceId) {
return client.get('/namespaces/$namespaceId').then((response) {
if (response == null) return null;
return Namespace.fromJson(response.body);
});
}
@override
Future<List<Namespace>?> getAll() {
return client.get('/namespaces').then((response) {
if (response == null) return null;
return convertList(response.body, (result) => Namespace.fromJson(result));
});
}
@override
Future<Namespace?> update(Namespace ns) {
return client
.post('/namespaces/${ns.id}', body: ns.toJSON())
.then((response) {
if (response == null) return null;
return Namespace.fromJson(response.body);
});
}
}

View File

@ -5,7 +5,7 @@ import 'package:flutter/scheduler.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:provider/provider.dart';
import 'package:vikunja_app/models/task.dart';
import 'package:vikunja_app/pages/list/task_edit.dart';
import 'package:vikunja_app/pages/project/task_edit.dart';
import 'package:vikunja_app/utils/misc.dart';
import 'package:vikunja_app/theme/constants.dart';

View File

@ -7,9 +7,8 @@ import 'package:provider/provider.dart';
import '../global.dart';
import '../models/bucket.dart';
import '../models/list.dart';
import '../models/project.dart';
import '../pages/list/list.dart';
import '../pages/project/project_task_list.dart';
import '../stores/project_store.dart';
import '../utils/calculate_item_position.dart';
import 'AddDialog.dart';

View File

@ -7,7 +7,7 @@ import 'package:vikunja_app/utils/priority.dart';
import '../models/label.dart';
import '../models/task.dart';
import '../pages/list/task_edit.dart';
import '../pages/project/task_edit.dart';
import '../stores/project_store.dart';
import '../theme/constants.dart';
import 'label.dart';

View File

@ -6,7 +6,7 @@ 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/pages/project/task_edit.dart';
import 'package:vikunja_app/utils/priority.dart';
import '../stores/project_store.dart';

View File

@ -7,8 +7,6 @@ import 'package:vikunja_app/api/client.dart';
import 'package:vikunja_app/api/label_task.dart';
import 'package:vikunja_app/api/label_task_bulk.dart';
import 'package:vikunja_app/api/labels.dart';
import 'package:vikunja_app/api/list_implementation.dart';
import 'package:vikunja_app/api/namespace_implementation.dart';
import 'package:vikunja_app/api/server_implementation.dart';
import 'package:vikunja_app/api/task_implementation.dart';
import 'package:vikunja_app/api/user_implementation.dart';
@ -65,16 +63,12 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
VersionChecker get versionChecker => new VersionChecker(snackbarKey);
NamespaceService get namespaceService => new NamespaceAPIService(client);
ProjectService get projectService => new ProjectAPIService(client, _storage);
TaskService get taskService => new TaskAPIService(client);
BucketService get bucketService => new BucketAPIService(client);
ListService get listService => new ListAPIService(client, _storage);
TaskServiceOptions get taskServiceOptions => new TaskServiceOptions();
NotificationClass get notifications => _notificationClass;

View File

@ -2,18 +2,10 @@ import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:after_layout/after_layout.dart';
import 'package:provider/provider.dart';
import 'package:vikunja_app/components/AddDialog.dart';
import 'package:vikunja_app/components/ErrorDialog.dart';
import 'package:vikunja_app/models/project.dart';
import 'package:vikunja_app/pages/namespace/namespace.dart';
import 'package:vikunja_app/pages/namespace/namespace_edit.dart';
import 'package:vikunja_app/pages/landing_page.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/namespace.dart';
import 'package:vikunja_app/pages/namespace/overview.dart';
import 'package:vikunja_app/pages/project/overview.dart';
import 'package:vikunja_app/pages/settings.dart';

View File

@ -1,324 +0,0 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:vikunja_app/components/AddDialog.dart';
import 'package:vikunja_app/components/KanbanWidget.dart';
import 'package:vikunja_app/components/TaskTile.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/models/task.dart';
import 'package:vikunja_app/models/bucket.dart';
import 'package:vikunja_app/pages/list/list_edit.dart';
import 'package:vikunja_app/pages/list/task_edit.dart';
import 'package:vikunja_app/stores/list_store.dart';
import '../../components/pagestatus.dart';
enum BucketMenu { limit, done, delete }
class BucketProps {
final ScrollController controller = ScrollController();
final TextEditingController titleController = TextEditingController();
bool scrollable = false;
bool portrait = true;
int bucketLength = 0;
Size? taskDropSize;
}
class ListPage extends StatefulWidget {
final TaskList taskList;
//ListPage({this.taskList}) : super(key: Key(taskList.id.toString()));
ListPage({required this.taskList})
: super(key: Key(Random().nextInt(100000).toString()));
@override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
final _keyboardController = KeyboardVisibilityController();
int _viewIndex = 0;
late TaskList _list;
List<Task> _loadingTasks = [];
int _currentPage = 1;
bool displayDoneTasks = false;
late ListProvider taskState;
late KanbanClass _kanban;
@override
void initState() {
_list = widget.taskList;
_keyboardController.onChange.listen((visible) {
if (!visible && mounted) FocusScope.of(context).unfocus();
});
super.initState();
}
void nullSetState() {
setState(() {});
}
@override
Widget build(BuildContext context) {
taskState = Provider.of<ListProvider>(context);
//_kanban = KanbanClass(
// context, nullSetState, _onViewTapped, _addItemDialog, _list);
Widget body;
switch (taskState.pageStatus) {
case PageStatus.built:
Future.delayed(Duration.zero, _loadList);
body = new Stack(children: [
ListView(),
Center(
child: CircularProgressIndicator(),
)
]);
break;
case PageStatus.loading:
body = new Stack(children: [
ListView(),
Center(
child: CircularProgressIndicator(),
)
]);
break;
case PageStatus.error:
body = new Stack(children: [
ListView(),
Center(child: Text("There was an error loading this view"))
]);
break;
case PageStatus.success:
body = taskState.tasks.length > 0 || taskState.buckets.length > 0
? ListenableProvider.value(
value: taskState,
child: Theme(
data: (ThemeData base) {
return base.copyWith(
chipTheme: base.chipTheme.copyWith(
labelPadding: EdgeInsets.symmetric(horizontal: 2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
),
);
}(Theme.of(context)),
child: () {
switch (_viewIndex) {
case 0:
return _listView(context);
case 1:
return _kanban.kanbanView();
default:
return _listView(context);
}
}(),
),
)
: Stack(children: [
ListView(),
Center(child: Text('This list is empty.'))
]);
break;
case PageStatus.empty:
body = new Stack(
children: [ListView(), Center(child: Text("This view is empty"))]);
break;
}
return new Scaffold(
appBar: AppBar(
title: Text(_list.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.edit),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ListEditPage(
list: _list,
),
)).whenComplete(() => _loadList()),
),
],
),
body: RefreshIndicator(onRefresh: () => _loadList(), child: body),
floatingActionButton: _viewIndex == 1
? null
: Builder(
builder: (context) => FloatingActionButton(
onPressed: () => _addItemDialog(context),
child: Icon(Icons.add)),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.view_list),
label: 'List',
tooltip: 'List',
),
BottomNavigationBarItem(
icon: Icon(Icons.view_kanban),
label: 'Kanban',
tooltip: 'Kanban',
),
],
currentIndex: _viewIndex,
onTap: _onViewTapped,
),
);
}
void _onViewTapped(int index) {
_loadList().then((_) {
_currentPage = 1;
setState(() {
_viewIndex = index;
});
});
}
ListView _listView(BuildContext context) {
return ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
itemCount: taskState.tasks.length * 2,
itemBuilder: (context, i) {
if (i.isOdd) return Divider();
if (_loadingTasks.isNotEmpty) {
final loadingTask = _loadingTasks.removeLast();
return _buildLoadingTile(loadingTask);
}
final index = i ~/ 2;
if (taskState.maxPages == _currentPage &&
index == taskState.tasks.length)
throw Exception("Check itemCount attribute");
if (index >= taskState.tasks.length &&
_currentPage < taskState.maxPages) {
_currentPage++;
_loadTasksForPage(_currentPage);
}
return _buildTile(taskState.tasks[index]);
});
}
Widget _buildTile(Task task) {
return ListenableProvider.value(
value: taskState,
child: TaskTile(
task: task,
loading: false,
onEdit: () {},
onMarkedAsDone: (done) {
Provider.of<ListProvider>(context, listen: false).updateTask(
context: context,
task: task.copyWith(done: done),
);
},
),
);
}
Future<void> updateDisplayDoneTasks() {
return VikunjaGlobal.of(context)
.listService
.getDisplayDoneTasks(_list.id)
.then((value) {
displayDoneTasks = value == "1";
});
}
TaskTile _buildLoadingTile(Task task) {
return TaskTile(
task: task,
loading: true,
onEdit: () {},
);
}
Future<void> _loadList() async {
taskState.pageStatus = (PageStatus.loading);
updateDisplayDoneTasks().then((value) async {
switch (_viewIndex) {
case 0:
_loadTasksForPage(1);
break;
case 1:
await _kanban.loadBucketsForPage(1);
// load all buckets to get length for RecordableListView
while (_currentPage < taskState.maxPages) {
_currentPage++;
await _kanban.loadBucketsForPage(_currentPage);
}
break;
default:
_loadTasksForPage(1);
}
});
}
Future<void> _loadTasksForPage(int page) {
return Provider.of<ListProvider>(context, listen: false).loadTasks(
context: context,
listId: _list.id,
page: page,
displayDoneTasks: displayDoneTasks);
}
Future<void> _addItemDialog(BuildContext context, [Bucket? bucket]) {
return showDialog(
context: context,
builder: (_) => AddDialog(
onAdd: (title) => _addItem(title, context, bucket),
decoration: InputDecoration(
labelText:
(bucket != null ? '\'${bucket.title}\': ' : '') + 'New Task Name',
hintText: 'eg. Milk',
),
),
);
}
Future<void> _addItem(String title, BuildContext context,
[Bucket? bucket]) async {
final currentUser = VikunjaGlobal.of(context).currentUser;
if (currentUser == null) {
return;
}
final newTask = Task(
title: title,
createdBy: currentUser,
done: false,
bucketId: bucket?.id,
projectId: _list.id,
);
setState(() => _loadingTasks.add(newTask));
return Provider.of<ListProvider>(context, listen: false)
.addTask(
context: context,
newTask: newTask,
listId: _list.id,
)
.then((_) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The task was added successfully' +
(bucket != null ? ' to \'${bucket.title}\'' : '') +
'!'),
));
setState(() {
_loadingTasks.remove(newTask);
});
});
}
}

View File

@ -1,174 +0,0 @@
import 'dart:ffi';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/theme/button.dart';
import 'package:vikunja_app/theme/buttonText.dart';
class ListEditPage extends StatefulWidget {
final TaskList list;
ListEditPage({required this.list}) : super(key: Key(list.toString()));
@override
State<StatefulWidget> createState() => _ListEditPageState();
}
class _ListEditPageState extends State<ListEditPage> {
final _formKey = GlobalKey<FormState>();
bool _loading = false;
String _title = '', _description = '';
bool? displayDoneTasks;
late int listId;
@override
void initState() {
listId = widget.list.id;
super.initState();
}
@override
Widget build(BuildContext ctx) {
if (displayDoneTasks == null)
VikunjaGlobal.of(context)
.listService
.getDisplayDoneTasks(listId)
.then((value) => setState(() => displayDoneTasks = value == "1"));
else
log("Display done tasks: " + displayDoneTasks.toString());
return Scaffold(
appBar: AppBar(
title: Text('Edit List'),
),
body: Builder(
builder: (BuildContext context) => SafeArea(
child: Form(
key: _formKey,
child: ListView(
//reverse: true,
padding: const EdgeInsets.all(16.0),
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.list.title,
onSaved: (title) => _title = title ?? '',
validator: (title) {
//if (title?.length < 3 || title.length > 250) {
// return 'The title needs to have between 3 and 250 characters.';
//}
return null;
},
decoration: new InputDecoration(
labelText: 'Title',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.list.description,
onSaved: (description) =>
_description = description ?? '',
validator: (description) {
if (description == null) return null;
if (description.length > 1000) {
return 'The description can have a maximum of 1000 characters.';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Description',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: CheckboxListTile(
value: displayDoneTasks ?? false,
title: Text("Show done tasks"),
onChanged: (value) {
value ??= false;
VikunjaGlobal.of(context)
.listService
.setDisplayDoneTasks(listId, value ? "1" : "0");
setState(() => displayDoneTasks = value);
},
),
),
Builder(
builder: (context) => Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: FancyButton(
onPressed: !_loading
? () {
if (_formKey.currentState!.validate()) {
Form.of(context)?.save();
_saveList(context);
}
}
: () {},
child: _loading
? CircularProgressIndicator()
: VikunjaButtonText('Save'),
))),
/*ExpansionTile(
title: Text("Sharing"),
children: [
TypeAheadFormField(
onSuggestionSelected: (suggestion) {},
itemBuilder: (BuildContext context, Object? itemData) {
return Card(
child: Container(
padding: EdgeInsets.all(10),
child: Text(itemData.toString())),
);},
suggestionsCallback: (String pattern) {
List<String> matches = <String>[];
matches.addAll(["test", "test2", "test3"]);
matches.retainWhere((s){
return s.toLowerCase().contains(pattern.toLowerCase());
});
return matches;
},)
],
)*/
]),
),
),
),
);
}
_saveList(BuildContext context) async {
setState(() => _loading = true);
// FIXME: is there a way we can update the list without creating a new list object?
// aka updating the existing list we got from context (setters?)
widget.list.title = _title;
widget.list.description = _description;
VikunjaGlobal.of(context).listService.update(widget.list).then((_) {
setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The list was updated successfully!'),
));
}).catchError((err) {
setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Something went wrong: ' + err.toString()),
action: SnackBarAction(
label: 'CLOSE',
onPressed: ScaffoldMessenger.of(context).hideCurrentSnackBar),
),
);
});
}
}

View File

@ -1,192 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:vikunja_app/components/AddDialog.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/models/namespace.dart';
import 'package:vikunja_app/pages/list/list.dart';
import 'package:vikunja_app/pages/namespace/namespace_edit.dart';
import 'package:vikunja_app/stores/list_store.dart';
import '../../components/pagestatus.dart';
class NamespacePage extends StatefulWidget {
final Namespace namespace;
NamespacePage({required this.namespace})
: super(key: Key(namespace.id.toString()));
@override
_NamespacePageState createState() => new _NamespacePageState();
}
class _NamespacePageState extends State<NamespacePage> {
List<TaskList> _lists = [];
PageStatus namespacestatus = PageStatus.loading;
/////
// This essentially shows the lists.
@override
Widget build(BuildContext context) {
Widget body;
switch (namespacestatus) {
case PageStatus.built:
_loadLists();
body = new Stack(children: [
ListView(),
Center(
child: CircularProgressIndicator(),
)
]);
break;
case PageStatus.loading:
body = new Stack(children: [
ListView(),
Center(
child: CircularProgressIndicator(),
)
]);
break;
case PageStatus.error:
body = new Stack(children: [
ListView(),
Center(child: Text("There was an error loading this view"))
]);
break;
case PageStatus.success:
body = new ListView(
padding: EdgeInsets.symmetric(vertical: 8.0),
children: ListTile.divideTiles(
context: context,
tiles: _lists.map((ls) => Dismissible(
key: Key(ls.id.toString()),
direction: DismissDirection.startToEnd,
child: ListTile(
title: new Text(ls.title),
onTap: () => _openList(context, ls),
trailing: Icon(Icons.arrow_right),
),
background: Container(
color: Colors.red,
child: const ListTile(
leading: Icon(Icons.delete,
color: Colors.white, size: 36.0)),
),
onDismissed: (direction) {
_removeList(ls).then((_) => ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(content: Text("${ls.title} removed"))));
},
))).toList(),
);
break;
case PageStatus.empty:
body = new Stack(
children: [ListView(), Center(child: Text("This view is empty"))]);
break;
}
return new Scaffold(
appBar: AppBar(
title: Text(widget.namespace.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.edit),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NamespaceEditPage(
namespace: widget.namespace,
),
)).whenComplete(() => _loadLists()),
),
],
),
body: RefreshIndicator(onRefresh: () => _loadLists(), child: body),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: () => _addListDialog(context),
child: const Icon(Icons.add))),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadLists();
}
Future<void> _removeList(TaskList list) {
return VikunjaGlobal.of(context)
.listService
.delete(list.id)
.then((_) => _loadLists());
}
Future<void> _loadLists() {
// FIXME: This is called even when the tasks on a list are loaded - which is not needed at all
namespacestatus = PageStatus.loading;
return VikunjaGlobal.of(context)
.listService
.getByNamespace(widget.namespace.id)
.then((lists) => setState(() {
if (lists != null) {
this._lists = lists;
namespacestatus = PageStatus.success;
} else {
namespacestatus = PageStatus.error;
}
}));
}
_openList(BuildContext context, TaskList list) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ChangeNotifierProvider<ListProvider>(
create: (_) => new ListProvider(),
child: ListPage(
taskList: list,
),
),
// ListPage(taskList: list)
));
}
_addListDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => AddDialog(
onAdd: (name) => _addList(name, context),
decoration: new InputDecoration(
labelText: 'List Name', hintText: 'eg. Shopping List')),
);
}
void _addList(String name, BuildContext context) {
final curentUser = VikunjaGlobal.of(context).currentUser;
if (curentUser == null) {
return;
}
VikunjaGlobal.of(context)
.listService
.create(
widget.namespace.id,
TaskList(
title: name,
tasks: [],
namespaceId: widget.namespace.id,
owner: curentUser,
))
.then((_) {
setState(() {});
_loadLists();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('The list was successfully created!'),
),
);
});
}
}

View File

@ -1,131 +0,0 @@
import 'package:flutter/material.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/namespace.dart';
import 'package:vikunja_app/theme/button.dart';
import 'package:vikunja_app/theme/buttonText.dart';
class NamespaceEditPage extends StatefulWidget {
final Namespace namespace;
NamespaceEditPage({required this.namespace})
: super(key: Key(namespace.toString()));
@override
State<StatefulWidget> createState() => _NamespaceEditPageState();
}
class _NamespaceEditPageState extends State<NamespaceEditPage> {
final _formKey = GlobalKey<FormState>();
bool _loading = false;
late String _name, _description;
@override
void initState() {
_name = widget.namespace.title;
_description = widget.namespace.description;
super.initState();
}
@override
Widget build(BuildContext ctx) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Namespace'),
),
body: Builder(
builder: (BuildContext context) => SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16.0),
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.namespace.title,
onSaved: (name) => _name = name ?? '',
validator: (name) {
//if (name.length < 3 || name.length > 250) {
// return 'The name needs to have between 3 and 250 characters.';
//}
return null;
},
decoration: new InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
maxLines: null,
keyboardType: TextInputType.multiline,
initialValue: widget.namespace.description,
onSaved: (description) =>
_description = description ?? '',
validator: (description) {
//if (description.length > 1000) {
// return 'The description can have a maximum of 1000 characters.';
//}
return null;
},
decoration: new InputDecoration(
labelText: 'Description',
border: OutlineInputBorder(),
),
),
),
Builder(
builder: (context) => Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: FancyButton(
onPressed: !_loading
? () {
if (_formKey.currentState!.validate()) {
Form.of(context)?.save();
_saveNamespace(context);
}
}
: null,
child: _loading
? CircularProgressIndicator()
: VikunjaButtonText('Save'),
))),
]),
),
),
),
);
}
_saveNamespace(BuildContext context) async {
setState(() => _loading = true);
final updatedNamespace = widget.namespace.copyWith(
title: _name,
description: _description,
);
VikunjaGlobal.of(context)
.namespaceService
.update(updatedNamespace)
.then((_) {
setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The namespace was updated successfully!'),
));
}).catchError((err) {
setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Something went wrong: ' + err.toString()),
action: SnackBarAction(
label: 'CLOSE',
onPressed: ScaffoldMessenger.of(context).hideCurrentSnackBar),
),
);
});
}
}

View File

@ -1,124 +0,0 @@
import 'package:after_layout/after_layout.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../components/AddDialog.dart';
import '../../components/ErrorDialog.dart';
import '../../global.dart';
import '../../models/namespace.dart';
import 'namespace.dart';
class NamespaceOverviewPage extends StatefulWidget {
@override
_NamespaceOverviewPageState createState() =>
new _NamespaceOverviewPageState();
}
class _NamespaceOverviewPageState extends State<NamespaceOverviewPage>
with AfterLayoutMixin<NamespaceOverviewPage> {
List<Namespace> _namespaces = [];
int _selectedDrawerIndex = -2, _previousDrawerIndex = -2;
bool _loading = true;
Namespace? get _currentNamespace =>
_selectedDrawerIndex >= -1 && _selectedDrawerIndex < _namespaces.length
? _namespaces[_selectedDrawerIndex]
: null;
@override
void afterFirstLayout(BuildContext context) {
_loadNamespaces();
}
@override
Widget build(BuildContext context) {
List<Widget> namespacesList = <Widget>[];
_namespaces
.asMap()
.forEach((i, namespace) => namespacesList.add(new ListTile(
leading: const Icon(Icons.folder),
title: new Text(namespace.title),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
)));
if (_selectedDrawerIndex > -1) {
return new WillPopScope(
child: NamespacePage(namespace: _namespaces[_selectedDrawerIndex]),
onWillPop: () async {
setState(() {
_selectedDrawerIndex = -2;
});
return false;
});
}
return Scaffold(
body: this._loading
? Center(child: CircularProgressIndicator())
: RefreshIndicator(
child: ListView(
padding: EdgeInsets.zero,
children: ListTile.divideTiles(
context: context, tiles: namespacesList)
.toList()),
onRefresh: _loadNamespaces,
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: () => _addNamespaceDialog(context),
child: const Icon(Icons.add))),
appBar: AppBar(
title: Text("Namespaces"),
),
);
}
Future<void> _loadNamespaces() {
return VikunjaGlobal.of(context).namespaceService.getAll().then((result) {
setState(() {
_loading = false;
if (result != null) _namespaces = result;
});
});
}
_onSelectItem(int index) {
Navigator.push(
context,
MaterialPageRoute(
builder: (buildContext) => NamespacePage(
namespace: _namespaces[index],
),
));
//setState(() => _selectedDrawerIndex = index);
}
_addNamespaceDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => AddDialog(
onAdd: (name) => _addNamespace(name, context),
decoration: new InputDecoration(
labelText: 'Namespace', hintText: 'eg. Personal Namespace'),
));
}
_addNamespace(String name, BuildContext context) {
final currentUser = VikunjaGlobal.of(context).currentUser;
if (currentUser == null) {
return;
}
VikunjaGlobal.of(context)
.namespaceService
.create(Namespace(title: name, owner: currentUser))
.then((_) {
_loadNamespaces();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('The namespace was created successfully!'),
));
}).catchError((error) => showDialog(
context: context, builder: (context) => ErrorDialog(error: error)));
}
}

View File

@ -99,7 +99,7 @@ class _ProjectEditPageState extends State<ProjectEditPage> {
onChanged: (value) {
value ??= false;
VikunjaGlobal.of(context)
.listService
.projectService
.setDisplayDoneTasks(listId, value ? "1" : "0");
setState(() => displayDoneTasks = value);
},

View File

@ -8,11 +8,9 @@ import 'package:vikunja_app/components/AddDialog.dart';
import 'package:vikunja_app/components/KanbanWidget.dart';
import 'package:vikunja_app/components/TaskTile.dart';
import 'package:vikunja_app/global.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/models/task.dart';
import 'package:vikunja_app/models/bucket.dart';
import 'package:vikunja_app/pages/list/list_edit.dart';
import 'package:vikunja_app/pages/list/task_edit.dart';
import 'package:vikunja_app/pages/project/task_edit.dart';
import 'package:vikunja_app/pages/project/project_edit.dart';
import '../../components/pagestatus.dart';

View File

@ -82,7 +82,7 @@ class MockedNamespaceService implements NamespaceService {
return create(ns);
}
}
/*
class MockedListService implements ListService {
@override
Future<TaskList> create(namespaceId, TaskList tl) {
@ -140,7 +140,7 @@ class MockedListService implements ListService {
void setDefaultList(int? listId) {
// TODO: implement setDefaultList
}
}
}*/
class MockedTaskService implements TaskService {
@override

View File

@ -6,7 +6,6 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:vikunja_app/api/response.dart';
import 'package:vikunja_app/models/label.dart';
import 'package:vikunja_app/models/labelTask.dart';
import 'package:vikunja_app/models/list.dart';
import 'package:vikunja_app/models/namespace.dart';
import 'package:vikunja_app/models/task.dart';
import 'package:vikunja_app/models/user.dart';
@ -163,7 +162,7 @@ abstract class NamespaceService {
Future delete(int namespaceId);
}
/*
abstract class ListService {
Future<List<TaskList>?> getAll();
@ -185,7 +184,7 @@ abstract class ListService {
//void setDefaultList(int? listId);
}
*/
abstract class TaskService {
Future<Task?> get(int taskId);