diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 053f2bcc..ed3ddf4f 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -15,6 +15,7 @@ import 'package:taskwarrior/app/models/json/task.dart'; import 'package:taskwarrior/app/models/storage.dart'; import 'package:taskwarrior/app/models/storage/client.dart'; import 'package:taskwarrior/app/models/tag_meta_data.dart'; +import 'package:taskwarrior/app/models/json/annotation.dart'; import 'package:taskwarrior/app/modules/home/controllers/widget.controller.dart'; import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart'; import 'package:taskwarrior/app/services/deep_link_service.dart'; @@ -30,6 +31,7 @@ import 'package:taskwarrior/app/utils/taskfunctions/projects.dart'; import 'package:taskwarrior/app/utils/taskfunctions/query.dart'; import 'package:taskwarrior/app/utils/taskfunctions/tags.dart'; import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/urgency.dart'; import 'package:taskwarrior/app/v3/champion/replica.dart'; import 'package:taskwarrior/app/v3/champion/models/task_for_replica.dart'; import 'package:taskwarrior/app/v3/db/task_database.dart'; @@ -39,6 +41,8 @@ import 'package:taskwarrior/app/v3/net/fetch.dart'; import 'package:textfield_tags/textfield_tags.dart'; import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; +import 'package:built_collection/built_collection.dart'; +import 'package:taskwarrior/app/v3/models/annotation.dart' as ChampionAnn; class HomeController extends GetxController { final SplashController splashController = Get.find(); @@ -197,7 +201,117 @@ class HomeController extends GetxController { tasksFromReplica.value = await Replica.getAllTasksFromReplica(); debugPrint("Tasks from Replica: ${tasks.length}"); } - + + Future mergeReplica(Task task) async { + final updated = task.rebuild( + (b) => b.modified = DateTime.now().toUtc(), + ); + final replicaTask = convertTaskToReplica(updated); + await Replica.modifyTaskInReplica(replicaTask); + await refreshReplicaTaskList(); +} + // its convert Task into Replica + TaskForReplica convertTaskToReplica(Task t){ + return TaskForReplica( + uuid: t.uuid, + description: t.description, + status: t.status, + project: t.project, + priority: t.priority, + due: t.due?.toIso8601String(), + start: t.start?.toIso8601String(), + wait: t.wait?.toIso8601String(), + // entry: t.entry?.toIso8601String(), + tags: t.tags?.toList(), + ); + } + // its convert Replica into Task + Task convertReplicaToTask(TaskForReplica t) { + final now = DateTime.now().toUtc(); + return Task((b) => b + ..uuid = t.uuid + ..description = t.description ?? '' + ..status = t.status ?? 'pending' + ..project = t.project + ..priority = t.priority + ..due = t.due != null ? DateTime.parse(t.due!) : null + ..start = t.start != null ? DateTime.parse(t.start!) : null + ..wait = t.wait != null ? DateTime.parse(t.wait!) : null + // ..entry = DateTime.now().toUtc() + // ..modified = DateTime.now().toUtc() + ..entry = now + ..modified = now + ..end = null + ..tags = t.tags != null + ? ListBuilder(t.tags!) + : null + ); +} + + Future mergeTaskChampion(TaskForC task) async { + await taskdb.updateTask(task); + tasks.value = await taskdb.fetchTasksFromDatabase(); + } + // its convert Task into TaskForC + TaskForC convertTaskToTaskForC(Task t) { + debugPrint("Annotations to save: ${t.annotations?.length}"); + return TaskForC( + id: t.id!, + uuid: t.uuid, + description: t.description, + status: t.status, + project: t.project, + priority: t.priority, + due: t.due?.toIso8601String(), + start: t.start?.toIso8601String(), + wait: t.wait?.toIso8601String(), + entry: t.entry.toIso8601String(), + modified: t.modified?.toIso8601String(), + end: t.end?.toIso8601String(), + rtype: null, + recur: t.recur, + depends: t.depends?.toList(), + urgency: urgency(t), + tags: t.tags?.toList(), + annotations: (t.annotations ?? BuiltList()) + .map((a) => ChampionAnn.Annotation( + description: a.description, + entry: a.entry?.toIso8601String() ?? DateTime.now().toIso8601String(), + )) + .toList() + ); +} + // its convert TaskForC into Task + Task convertTaskForCToTask(TaskForC t) { + return Task((b) => b + ..id = t.id + ..uuid = t.uuid + ..description = t.description + ..status = t.status + ..project = t.project + ..priority = t.priority + ..due = t.due != null ? DateTime.parse(t.due!) : null + ..start = t.start != null ? DateTime.parse(t.start!) : null + ..wait = t.wait != null ? DateTime.parse(t.wait!) : null + ..entry = DateTime.parse(t.entry) + ..modified = t.modified != null + ? DateTime.parse(t.modified!) + : null + ..end = t.end != null ? DateTime.parse(t.end!) : null + ..tags = t.tags != null + ? ListBuilder(t.tags!) + : null + ..annotations = t.annotations != null + ? ListBuilder( + t.annotations!.map( + (a) => Annotation((ann) => ann + ..description = a.description ?? '' + ..entry = DateTime.parse(a.entry ?? DateTime.now().toIso8601String())), + ), + ) + : null + ); +} void addListenerToScrollController() { scrollController.addListener(() { //scroll listener diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index 008b30fb..dc0a9316 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -178,8 +178,11 @@ class TaskViewBuilder extends StatelessWidget { color: tColors.secondaryBackgroundColor, child: InkWell( splashColor: tColors.primaryBackgroundColor, - onTap: () => - Get.toNamed(Routes.TASKC_DETAILS, arguments: task), + // onTap: () => + // Get.toNamed(Routes.TASKC_DETAILS, arguments: task), + onTap: () => + // print("NAVIGATING TO TASK_INFO_ROUTE"); + Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task), child: Container( decoration: BoxDecoration( border: Border.all( diff --git a/lib/app/modules/home/views/show_tasks_replica.dart b/lib/app/modules/home/views/show_tasks_replica.dart index 642fbdff..6e8efe0d 100644 --- a/lib/app/modules/home/views/show_tasks_replica.dart +++ b/lib/app/modules/home/views/show_tasks_replica.dart @@ -122,7 +122,8 @@ class TaskReplicaViewBuilder extends StatelessWidget { child: InkWell( splashColor: tColors.primaryBackgroundColor, onTap: () => - Get.toNamed(Routes.TASKC_DETAILS, arguments: task), + // Get.toNamed(Routes.TASKC_DETAILS, arguments: task), + Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task), child: Container( decoration: BoxDecoration( border: Border.all( diff --git a/lib/app/modules/home/views/tasks_builder.dart b/lib/app/modules/home/views/tasks_builder.dart index 54846126..e38ab7e2 100644 --- a/lib/app/modules/home/views/tasks_builder.dart +++ b/lib/app/modules/home/views/tasks_builder.dart @@ -242,7 +242,7 @@ class TasksBuilder extends StatelessWidget { child: InkWell( splashColor: tColors.secondaryBackgroundColor, onTap: () { - Get.toNamed(Routes.DETAIL_ROUTE, + Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: ["uuid", task.uuid]); }, // child: Text(task.entry.toString()), @@ -271,7 +271,7 @@ class TasksBuilder extends StatelessWidget { child: InkWell( splashColor: tColors.secondaryBackgroundColor, onTap: () { - Get.toNamed(Routes.DETAIL_ROUTE, + Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: ["uuid", task.uuid]); }, // child: Text(task.entry.toString()), diff --git a/lib/app/modules/infoRoute/bindings/task_info_binding.dart b/lib/app/modules/infoRoute/bindings/task_info_binding.dart new file mode 100644 index 00000000..6d8c7a22 --- /dev/null +++ b/lib/app/modules/infoRoute/bindings/task_info_binding.dart @@ -0,0 +1,15 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:get/get.dart'; +import 'package:taskwarrior/app/modules/infoRoute/controllers/tasks_info_route_controller.dart'; +// import 'package:taskwarrior/app/modules/infoRoute/views/tasks_info_view.dart'; + +class TasksInfoRouteBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut( + () => TasksInfoRouteController(), + ); + } +} \ No newline at end of file diff --git a/lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart b/lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart new file mode 100644 index 00000000..16fdec05 --- /dev/null +++ b/lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart @@ -0,0 +1,47 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; +import 'package:taskwarrior/app/models/json/task.dart'; +import 'package:collection/collection.dart'; +class TasksInfoRouteController extends GetxController { + late String uuid; + var task = Rxn(); + @override + void onInit() { + super.onInit(); + var arguments = Get.arguments; + // uuid = arguments[1] as String; + if(arguments is List){ + uuid = arguments[1] as String; + } else{ + uuid = arguments.uuid; + } + loadTask(); + } + Future loadTask() async { + final homeController = Get.find(); + Task? foundTask; + if (homeController.taskchampion.value) { + final dbTask = await homeController.taskdb.getTaskByUuid(uuid); + + if (dbTask != null) { + foundTask = + homeController.convertTaskForCToTask(dbTask); + } + } + else if (homeController.taskReplica.value) { + await homeController.refreshReplicaTaskList(); + final replicaTask = homeController.tasksFromReplica + .firstWhereOrNull((t) => t.uuid == uuid); + if (replicaTask != null) { + foundTask = + homeController.convertReplicaToTask(replicaTask); + } + } + else { + foundTask = homeController.getTask(uuid); + } + task.value = foundTask; + } +} \ No newline at end of file diff --git a/lib/app/modules/infoRoute/views/task_info_view.dart b/lib/app/modules/infoRoute/views/task_info_view.dart new file mode 100644 index 00000000..6a98e12e --- /dev/null +++ b/lib/app/modules/infoRoute/views/task_info_view.dart @@ -0,0 +1,410 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:intl/intl.dart'; + +import 'package:built_collection/built_collection.dart'; +import 'package:taskwarrior/app/modules/detailRoute/bindings/detail_route_binding.dart'; +import 'package:taskwarrior/app/modules/detailRoute/views/detail_route_view.dart'; +import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; +// import 'package:taskwarrior/app/utils/taskfunctions/modify.dart'; +import 'package:taskwarrior/app/models/json/task.dart'; +import 'package:taskwarrior/app/models/json/annotation.dart'; +import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; +import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; +import 'package:taskwarrior/app/modules/infoRoute/controllers/tasks_info_route_controller.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/urgency.dart'; +import 'package:taskwarrior/app/modules/taskc_details/bindings/taskc_details_binding.dart'; +import 'package:taskwarrior/app/modules/taskc_details/views/taskc_details_view.dart'; + +class TasksInfoView extends GetView { + const TasksInfoView({super.key}); + + @override + Widget build(BuildContext context) { + final tColors = Theme.of(context).extension(); + return Obx(() { + final task = controller.task.value; + if (task == null || tColors == null) { + return const Scaffold( + body: Center(child: CircularProgressIndicator()), + ); + } + return Scaffold( + backgroundColor: tColors.primaryBackgroundColor, + appBar: AppBar( + backgroundColor: tColors.primaryBackgroundColor, + surfaceTintColor: Colors.transparent, + elevation: 0, + scrolledUnderElevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Get.back(), + ), + title: const Text( + "task Info", + style: TextStyle( + fontFamily: FontFamily.poppins, + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeLarge, + ), + ), + actions: [ + Padding(padding: const EdgeInsets.only(right: 12), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: IconButton( + icon: Icon(Icons.add, color: Colors.black,), + // onPressed: () async{ + // final homeController = Get.find(); + // if (homeController.taskchampion.value) { + + // Get.to( + // () => TaskcDetailsView(), + // binding: TaskcDetailsBinding(), + // arguments: task, + // ); + // } else{ + // Get.to( + // () => DetailRouteView(), + // binding: DetailRouteBinding(), + // arguments: ["uuid", task.uuid], + // ); + // } + // await controller.loadTask(); + // }, + onPressed: () async { + final homeController = Get.find(); + if (homeController.taskchampion.value) { + final dbTask = + await homeController.taskdb.getTaskByUuid(controller.uuid); + if (dbTask != null) { + await Get.to( + () => TaskcDetailsView(), + binding: TaskcDetailsBinding(), + arguments: dbTask, + ); + // await controller.loadTask(); + } + } + else if (homeController.taskReplica.value) { + final replicaTask = homeController.tasksFromReplica + .firstWhereOrNull((t) => t.uuid == controller.uuid); + if (replicaTask != null) { + await Get.to( + () => TaskcDetailsView(), + binding: TaskcDetailsBinding(), + arguments: replicaTask, + ); + // await controller.loadTask(); + } + } + else { + Get.to( + () => DetailRouteView(), + binding: DetailRouteBinding(), + arguments: ["uuid", controller.uuid], + ); + } + await controller.loadTask(); + } + ), + ), + ), + ], + ), + body: buildBody(task, tColors), + ); + }); + } + + Widget buildBody(Task task, TaskwarriorColorTheme tColors) { + return SingleChildScrollView( + padding: const EdgeInsets.only(left: 14, right: 14, top: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + taskInfoCard(task, tColors), + const SizedBox(height: 20), + actionButtons(task), + const SizedBox(height: 20), + annotationSection(task, tColors), + ], + ), + ); + } + +Widget taskInfoCard(Task task, TaskwarriorColorTheme tColors) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade600), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 14, + height: 14, + decoration: BoxDecoration( + color: getPriorityColor(task.priority), + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Text( + task.description, + style: TextStyle( + fontFamily: FontFamily.poppins, + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeLarge, + color: tColors.primaryTextColor, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _richInfo("id: ", task.id?.toString() ?? "-", tColors), + Text( + task.status, + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeMedium, + fontWeight: TaskWarriorFonts.medium, + color: tColors.primaryTextColor, + ), + ), + _richInfo("urg: ", urgency(task).toStringAsFixed(3), tColors, ), + ], + ), + const SizedBox(height: 8), + _richInfo("entry: ", formatDate(task.entry), tColors), + const SizedBox(height: 6), + _richInfo( + "mod: ", task.modified != null ? formatDate(task.modified!) : "-", tColors, ), + const SizedBox(height: 6), + _richInfo("due: ", task.due != null ? formatDate(task.due!) : "-", tColors, ), + const SizedBox(height: 6), + _richInfo("project: ", task.project ?? "-", tColors), + const SizedBox(height: 6), + _richInfo("tags: ", task.tags != null && task.tags!.isNotEmpty ? task.tags!.join(" ") : "-", tColors, ), + const SizedBox(height: 6), + _richInfo("priority: ", task.priority ?? "-", tColors), + ], + ), + ); +} + +Widget _richInfo( + String label, + String value, + TaskwarriorColorTheme tColors, +) { + return RichText( + text: TextSpan( + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeMedium, + ), + children: [ + TextSpan( + text: label, + style: TextStyle(color: Colors.grey), + ), + TextSpan( + text: value, + style: TextStyle( + color: tColors.primaryTextColor, + fontSize: TaskWarriorFonts.fontSizeMedium - 1, + ), + ), + ], + ), + ); +} + Widget actionButtons(Task task) { + final homeController = Get.find(); + return Wrap( + spacing: 8, + runSpacing: 8, + children: [ + actionButton("done", const Color.fromARGB(255, 54, 188, 58), () { + controller.loadTask(); + }), + actionButton("start", const Color.fromARGB(255, 206, 190, 47), () { + controller.loadTask(); + }), + actionButton("wait", const Color.fromARGB(255, 35, 110, 240), () { + controller.loadTask(); + }), + actionButton("delete", const Color.fromARGB(255, 219, 28, 14), () { + controller.loadTask(); + }), + ], + ); +} + Widget actionButton( + String text, Color color, VoidCallback onPressed) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: color, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + onPressed: onPressed, + child: Text(text, style: const TextStyle(fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.medium, fontSize: TaskWarriorFonts.fontSizeMedium)), + ); + } + + Widget annotationSection(Task task, TaskwarriorColorTheme tColors) { + final homeController = Get.find(); + final annotations = task.annotations ?? BuiltList(); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey.shade600, + ), + onPressed: () => + openAnnotationDialog(task, null), + child: const Text("new annotation", style: TextStyle(fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.medium, fontSize: TaskWarriorFonts.fontSizeLarge)), + ), + ), + const SizedBox(height: 10), + const Text( + "Annotations", + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeMedium, + fontWeight: TaskWarriorFonts.medium, + ), + ), + const SizedBox(height: 10), + + if (annotations.isNotEmpty) + ...annotations.asMap().entries.map((entry) { + final index = entry.key; + final annotation = entry.value; + + return Card( + color: tColors.secondaryBackgroundColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: ListTile( + title: Text(annotation.description), + subtitle: Text(formatDate(annotation.entry)), + onTap: () => + openAnnotationDialog(task, index), + ), + ); + }), + ], + ); + } + + void openAnnotationDialog(Task task, int? index) { + final homeController = Get.find(); + final annotations = task.annotations ?? BuiltList(); + + final textController = TextEditingController( + text: (index != null && index < annotations.length) + ? annotations[index].description + : "", + ); + Get.dialog( + AlertDialog( + title: Text(index == null + ? "New Annotation" + : "Edit Annotation"), + content: TextField( + controller: textController, + maxLines: null, + autofocus: true, + ), + actions: [ + TextButton( + onPressed: () => Get.back(), + child: const Text("Cancel"), + ), + TextButton( + onPressed: () async{ + final text = textController.text.trim(); + if (text.isEmpty) { + Get.back(); + return; + } + final updatedTask = task.rebuild((b) { + b.annotations ??= ListBuilder(); + if (index == null) { + b.annotations!.add( + Annotation((a) => a + ..description = text + ..entry = DateTime.now().toUtc()), + ); + } else if (index < b.annotations!.length) { + b.annotations![index] = + b.annotations![index] + .rebuild((a) => + a..description = text); + } + }); + // homeController.mergeTask(updatedTask); + final homeController = Get.find(); + if (homeController.taskReplica.value) { + await homeController.mergeReplica(updatedTask); + } + else if (homeController.taskchampion.value) { + final taskForC = + homeController.convertTaskToTaskForC(updatedTask); + await homeController.mergeTaskChampion(taskForC); + } + else { + homeController.mergeTask(updatedTask); + } + Get.back(); + await controller.loadTask(); + }, + child: const Text("Save"), + ), + ], + ), + ); + } + String formatDate(DateTime date) { + final format = + AppSettings.use24HourFormatRx.value + ? 'EEE, yyyy-MM-dd HH:mm:ss' + : 'EEE, yyyy-MM-dd hh:mm:ss a'; + return DateFormat(format).format(date.toLocal()); + } + + Color getPriorityColor(String? priority) { + switch (priority) { + case 'H': + return Colors.red; + case 'M': + return Colors.yellow; + case 'L': + return Colors.green; + default: + return Colors.grey; + } + } +} \ No newline at end of file diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 90ace627..7ce43429 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -4,6 +4,8 @@ import '../modules/about/bindings/about_binding.dart'; import '../modules/about/views/about_view.dart'; import '../modules/detailRoute/bindings/detail_route_binding.dart'; import '../modules/detailRoute/views/detail_route_view.dart'; +import '../modules/infoRoute/bindings/task_info_binding.dart'; +import '../modules/infoRoute/views/task_info_view.dart'; import '../modules/home/bindings/home_binding.dart'; import '../modules/home/views/home_view.dart'; import '../modules/logs/bindings/logs_binding.dart'; @@ -62,6 +64,11 @@ class AppPages { page: () => const DetailRouteView(), binding: DetailRouteBinding(), ), + GetPage( + name: _Paths.TASK_INFO_ROUTE, + page: () => const TasksInfoView(), + binding: TasksInfoRouteBinding(), + ), GetPage( name: _Paths.PROFILE, page: () => const ProfileView(), diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index 04490f3f..5dfd37f7 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -10,6 +10,7 @@ abstract class Routes { static const SPLASH = _Paths.SPLASH; static const MANAGE_TASK_SERVER = _Paths.MANAGE_TASK_SERVER; static const DETAIL_ROUTE = _Paths.DETAIL_ROUTE; + static const TASK_INFO_ROUTE = _Paths.TASK_INFO_ROUTE; static const PROFILE = _Paths.PROFILE; static const ABOUT = _Paths.ABOUT; static const REPORTS = _Paths.REPORTS; @@ -27,6 +28,7 @@ abstract class _Paths { static const SPLASH = '/splash'; static const MANAGE_TASK_SERVER = '/manage-task-server'; static const DETAIL_ROUTE = '/detail-route'; + static const TASK_INFO_ROUTE = '/task-info-route'; static const PROFILE = '/profile'; static const ABOUT = '/about'; static const REPORTS = '/reports'; diff --git a/lib/app/v3/models/task.dart b/lib/app/v3/models/task.dart index 91c64045..04f0a265 100644 --- a/lib/app/v3/models/task.dart +++ b/lib/app/v3/models/task.dart @@ -64,7 +64,13 @@ class TaskForC { recur: json['recur'], depends: json['depends']?.map((d) => d.toString()).toList() ?? [], - annotations: []); + // annotations: []); + annotations: json['annotations'] != null + ? (json['annotations'] as List) + .map((a) => Annotation.fromJson(a)) + .toList() + : [], + ); } Map toJson() { @@ -93,6 +99,31 @@ class TaskForC { }; } + TaskForC copyWith({ + List? annotations, +}) { + return TaskForC( + id: id, + description: description, + project: project, + status: status, + uuid: uuid, + urgency: urgency, + priority: priority, + due: due, + end: end, + entry: entry, + modified: modified, + tags: tags, + start: start, + wait: wait, + rtype: rtype, + recur: recur, + depends: depends, + annotations: annotations ?? this.annotations, + ); +} + @override String toString() { return "TaskForC(${toJson().toString()})"; diff --git a/test/routes/app_routes_test.dart b/test/routes/app_routes_test.dart index dd644bf8..7cb05508 100644 --- a/test/routes/app_routes_test.dart +++ b/test/routes/app_routes_test.dart @@ -8,6 +8,7 @@ void main() { expect(Routes.SPLASH, '/splash'); expect(Routes.MANAGE_TASK_SERVER, '/manage-task-server'); expect(Routes.DETAIL_ROUTE, '/detail-route'); + expect(Routes.TASK_INFO_ROUTE, '/task-info-route'); expect(Routes.PROFILE, '/profile'); expect(Routes.ABOUT, '/about'); expect(Routes.REPORTS, '/reports');