import 'package:after_layout/after_layout.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:vikunja_app/global.dart'; import 'package:vikunja_app/service/services.dart'; import 'dart:developer'; import '../components/AddDialog.dart'; import '../components/TaskTile.dart'; import '../components/pagestatus.dart'; import '../models/task.dart'; class HomeScreenWidget extends StatefulWidget { HomeScreenWidget({Key? key}) : super(key: key); @override State createState() { // TODO: implement createState throw UnimplementedError(); } } class LandingPage extends HomeScreenWidget { LandingPage({Key? key}) : super(key: key); @override State createState() => LandingPageState(); } class LandingPageState extends State with AfterLayoutMixin { int? defaultList; List _tasks = []; PageStatus landingPageStatus = PageStatus.built; static const platform = const MethodChannel('vikunja'); Future _updateDefaultList() async { return VikunjaGlobal.of(context).listService.getDefaultList().then( (value) => setState( () => defaultList = value == null ? null : int.tryParse(value))); } @override void initState() { Future.delayed( Duration.zero, () => _updateDefaultList().then((value) { try { platform.invokeMethod("isQuickTile", "").then((value) => {if (value is bool && value) _addItemDialog(context)}); } catch (e) { log(e.toString()); } })); super.initState(); } @override void afterFirstLayout(BuildContext context) { try { // This is needed when app is already open and quicktile is clicked platform.setMethodCallHandler((call) { switch (call.method) { case "open_add_task": _addItemDialog(context); break; } return Future.value(); }); } catch (e) { log(e.toString()); } } @override Widget build(BuildContext context) { Widget body; switch (landingPageStatus) { case PageStatus.built: _loadList(context); 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.empty: body = new Stack(children: [ ListView(), Center(child: Text("This view is empty")) ]); break; case PageStatus.success: body = ListView( scrollDirection: Axis.vertical, padding: EdgeInsets.symmetric(vertical: 8.0), children: ListTile.divideTiles(context: context, tiles: _listTasks(context)) .toList(), ); break; } return new Scaffold( body: RefreshIndicator(onRefresh: () => _loadList(context), child: body), floatingActionButton: Builder( builder: (context) => FloatingActionButton( onPressed: () { _addItemDialog(context); }, child: const Icon(Icons.add), )), appBar: AppBar( title: Text("Vikunja"), ), ); } _addItemDialog(BuildContext context) { if (defaultList == null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('Please select a default list in the settings'), )); } else { showDialog( context: context, builder: (_) => AddDialog( onAddTask: (title, dueDate) => _addTask(title, dueDate, context), decoration: new InputDecoration( labelText: 'Task Name', hintText: 'eg. Milk'))); } } Future _addTask( String title, DateTime? dueDate, BuildContext context) async { final globalState = VikunjaGlobal.of(context); if (globalState.currentUser == null) { return; } await globalState.taskService.add( defaultList!, Task( title: title, dueDate: dueDate, createdBy: globalState.currentUser!, projectId: defaultList!, ), ); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('The task was added successfully!'), )); _loadList(context).then((value) => setState(() {})); } List _listTasks(BuildContext context) { var tasks = (_tasks.map((task) => _buildTile(task, context))).toList(); //tasks.addAll(_loadingTasks.map(_buildLoadingTile)); return tasks; } TaskTile _buildTile(Task task, BuildContext context) { // key: UniqueKey() seems like a weird workaround to fix the loading issue // is there a better way? return TaskTile( key: UniqueKey(), task: task, onEdit: () => _loadList(context), showInfo: true, ); } Future _loadList(BuildContext context) { _tasks = []; landingPageStatus = PageStatus.loading; // FIXME: loads and reschedules tasks each time list is updated VikunjaGlobal.of(context).notifications.scheduleDueNotifications(VikunjaGlobal.of(context).taskService); return VikunjaGlobal.of(context) .taskService .getByOptions(TaskServiceOptions()) .then?>((taskList) { if (taskList != null && taskList.isEmpty) { setState(() { landingPageStatus = PageStatus.empty; }); return null; } //taskList.forEach((task) {task.list = lists.firstWhere((element) => element.id == task.list_id);}); setState(() { if (taskList != null) { _tasks = taskList; landingPageStatus = PageStatus.success; } else { landingPageStatus = PageStatus.error; } }); return null; }); } }