feat: introducing task_info and improving task_edit#608
feat: introducing task_info and improving task_edit#608Prashik-Sasane wants to merge 2 commits intoCCExtractor:mainfrom
Conversation
|
Hey @SGI-CAPP-AT2 , @linuxcaffe & @Pavel401 I have fix this issue #382 & #385 and you can check the code. |
|
ALRIGHT! Amazing, can't wait to check it out!
…On Sat, 28 Feb 2026 at 00:16, Prashik-Sasane ***@***.***> wrote:
*Prashik-Sasane* left a comment (CCExtractor/taskwarrior-flutter#608)
<#608 (comment)>
Hey @SGI-CAPP-AT2 <https://github.com/SGI-CAPP-AT2> , @linuxcaffe
<https://github.com/linuxcaffe> & @Pavel401 <https://github.com/Pavel401>
I have fix this issue #382
<#382> & #385
<#385> and you
check the code.
—
Reply to this email directly, view it on GitHub
<#608 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAR6S634DMFRS7ZVKFRCE4T4OEQBTAVCNFSM6AAAAACWCNHV62VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTSNZWGQYTEOJUGE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
@Prashik-Sasane , does it work for tc v3? |
|
@SGI-CAPP-AT2 till now no, but if it is require so i can implement it? |
Every change must be compatible with both mode |
📝 WalkthroughWalkthroughThis pull request introduces support for task annotations as a complete feature. It adds a new Task Info Route module with binding, controller, and view components; includes bidirectional data conversion utilities for Task-Replica and Task-Champion formats in HomeController; updates navigation routes and view references to use the new route; and extends the TaskForC model with annotation copying. Changes
Sequence DiagramsequenceDiagram
participant User
participant TaskCard as Task Card View
participant Navigation as Get.toNamed
participant TaskInfoCtrl as TasksInfoRouteController
participant HomeCtrl as HomeController
participant DB as Database/Model
participant TaskInfoView as Task Info View
User->>TaskCard: Tap task
TaskCard->>Navigation: toNamed(TASK_INFO_ROUTE, args: uuid)
Navigation->>TaskInfoCtrl: Route to controller
TaskInfoCtrl->>TaskInfoCtrl: onInit() extracts uuid
TaskInfoCtrl->>TaskInfoCtrl: loadTask()
alt taskchampion flag
TaskInfoCtrl->>DB: getByUUID(uuid)
DB-->>TaskInfoCtrl: TaskForC
TaskInfoCtrl->>HomeCtrl: convertTaskForCToTask(TaskForC)
HomeCtrl-->>TaskInfoCtrl: Task with annotations
else taskReplica flag
TaskInfoCtrl->>HomeCtrl: refreshReplicaTasks()
HomeCtrl->>DB: Fetch replicas
DB-->>HomeCtrl: TaskForReplica[]
TaskInfoCtrl->>HomeCtrl: convertReplicaToTask(TaskForReplica)
HomeCtrl-->>TaskInfoCtrl: Task
else default
TaskInfoCtrl->>HomeCtrl: getTask(uuid)
HomeCtrl-->>TaskInfoCtrl: Task
end
TaskInfoCtrl->>TaskInfoView: Update task Rx
TaskInfoView->>User: Display task details + annotations
User->>TaskInfoView: Click add/edit annotation
TaskInfoView->>TaskInfoView: Open annotation dialog
User->>TaskInfoView: Save annotation
TaskInfoView->>HomeCtrl: mergeTaskChampion()/mergeReplica()
HomeCtrl->>DB: Persist task
HomeCtrl->>TaskInfoCtrl: Trigger loadTask()
TaskInfoCtrl->>TaskInfoView: Update annotations
TaskInfoView->>User: Display updated annotations
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
lib/app/modules/home/views/show_tasks_replica.dart (1)
125-126: Remove the stale commented navigation line.Keeping only the active
Get.toNamed(Routes.TASK_INFO_ROUTE, ...)line will reduce noise in this tap handler.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/views/show_tasks_replica.dart` around lines 125 - 126, Remove the stale commented navigation line so only the active navigation call remains: delete the commented Get.toNamed(Routes.TASKC_DETAILS, arguments: task) and keep Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task) inside the tap handler in show_tasks_replica.dart to reduce noise.lib/app/modules/home/views/show_tasks.dart (1)
181-185: Clean up commented debug/legacy onTap lines.Consider removing the commented
TASKC_DETAILSand debug print lines now thatTASK_INFO_ROUTEis the stable target.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/views/show_tasks.dart` around lines 181 - 185, Remove the legacy commented onTap lines and debug print so the widget contains a single clear navigation handler: delete the commented references to Routes.TASKC_DETAILS and the print statement and keep only the onTap that calls Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task) (locate the onTap block around Get.toNamed in the same widget to update).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/app/modules/home/controllers/home_controller.dart`:
- Around line 293-300: The task conversion code is currently using
DateTime.parse on persisted strings (fields t.entry, t.due, t.start, t.wait,
t.modified, t.end) which will throw FormatException for empty or malformed
values; update the conversion logic in the method containing those chained
assignments and in the similar convertTaskForReplicaToTask method to use
DateTime.tryParse(...) for each timestamp and fall back to null (or an
appropriate default) when tryParse returns null, ensuring you replace
DateTime.parse(...) calls for t.entry and the other fields with defensive
tryParse usage and explicit null handling.
In `@lib/app/modules/infoRoute/bindings/task_info_binding.dart`:
- Around line 1-4: Remove the unused import 'dart:io' from
task_info_binding.dart (the binding that contains imports including
package:flutter/material.dart, package:flutter_slidable/flutter_slidable.dart,
and package:get/get.dart); locate the top-of-file import list in the TaskInfo
binding and delete the line "import 'dart:io';" so only used packages remain
imported.
In `@lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart`:
- Around line 15-19: The current assignment of uuid assumes arguments is a List
with at least two items or an object with a .uuid property; add defensive
validation before using arguments: when arguments is List check arguments.length
> 1 and that arguments[1] is a non-null String before assigning uuid, otherwise
handle the error or fallback; when not a List, check that arguments has a uuid
(e.g., arguments != null && arguments.uuid is String) or provide alternative
extraction (e.g., check for Map with 'uuid' key) and handle missing/invalid
values consistently (return error, null, or throw). Update the block around the
if(arguments is List) { ... } else { ... } to perform these guards and clear
fallback/error handling.
In `@lib/app/modules/infoRoute/views/task_info_view.dart`:
- Around line 243-254: The action buttons created by
actionButton("done"/"start"/"wait"/"delete") only call controller.loadTask() and
therefore do nothing to change task state; replace each handler to invoke the
appropriate controller methods (e.g.,
controller.markDone()/controller.startTask()/controller.waitTask()/controller.deleteTask()
or whatever existing mutator methods are defined on the controller) and then
refresh state (call controller.loadTask() or update the task in-place) so the UI
and backend reflect the action; locate the handlers inside actionButton(...)
calls in task_info_view.dart and wire each label to its corresponding controller
method and handle success/error (update/load task) accordingly.
- Around line 107-114: The navigation call using Get.to(() => DetailRouteView(),
binding: DetailRouteBinding(), arguments: ["uuid", controller.uuid]) in the else
branch is not awaited causing controller.loadTask() to run before navigation
completes; update that call to await the Get.to(...) invocation so the method
DetailRouteView navigation completes before calling controller.loadTask(),
preserving the existing pattern used earlier and preventing the race with
controller.loadTask().
---
Nitpick comments:
In `@lib/app/modules/home/views/show_tasks_replica.dart`:
- Around line 125-126: Remove the stale commented navigation line so only the
active navigation call remains: delete the commented
Get.toNamed(Routes.TASKC_DETAILS, arguments: task) and keep
Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task) inside the tap handler in
show_tasks_replica.dart to reduce noise.
In `@lib/app/modules/home/views/show_tasks.dart`:
- Around line 181-185: Remove the legacy commented onTap lines and debug print
so the widget contains a single clear navigation handler: delete the commented
references to Routes.TASKC_DETAILS and the print statement and keep only the
onTap that calls Get.toNamed(Routes.TASK_INFO_ROUTE, arguments: task) (locate
the onTap block around Get.toNamed in the same widget to update).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1f4c8ab4-cfcf-4696-944d-fd6fd1799292
📒 Files selected for processing (11)
lib/app/modules/home/controllers/home_controller.dartlib/app/modules/home/views/show_tasks.dartlib/app/modules/home/views/show_tasks_replica.dartlib/app/modules/home/views/tasks_builder.dartlib/app/modules/infoRoute/bindings/task_info_binding.dartlib/app/modules/infoRoute/controllers/tasks_info_route_controller.dartlib/app/modules/infoRoute/views/task_info_view.dartlib/app/routes/app_pages.dartlib/app/routes/app_routes.dartlib/app/v3/models/task.darttest/routes/app_routes_test.dart
| ..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 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the file
find . -name "home_controller.dart" -type fRepository: CCExtractor/taskwarrior-flutter
Length of output: 130
🏁 Script executed:
# Read the specific file around the mentioned lines
if [ -f "lib/app/modules/home/controllers/home_controller.dart" ]; then
echo "=== Lines 290-315 ==="
sed -n '290,315p' lib/app/modules/home/controllers/home_controller.dart | cat -n
fiRepository: CCExtractor/taskwarrior-flutter
Length of output: 1195
🏁 Script executed:
# Search for all DateTime.parse and DateTime.tryParse usage in the codebase
rg -n "DateTime\.(parse|tryParse)" --type=dart -B2 -A2Repository: CCExtractor/taskwarrior-flutter
Length of output: 15552
🏁 Script executed:
# Check specifically in the home_controller.dart file
if [ -f "lib/app/modules/home/controllers/home_controller.dart" ]; then
echo "=== DateTime parsing in home_controller.dart ==="
rg -n "DateTime\.(parse|tryParse)" lib/app/modules/home/controllers/home_controller.dart -B3 -A3
fiRepository: CCExtractor/taskwarrior-flutter
Length of output: 1416
🏁 Script executed:
# Get context about the convertTaskForCToTask method
if [ -f "lib/app/modules/home/controllers/home_controller.dart" ]; then
echo "=== Searching for convertTaskForCToTask method ==="
rg -n "convertTaskForCToTask" lib/app/modules/home/controllers/home_controller.dart -B5 -A50
fiRepository: CCExtractor/taskwarrior-flutter
Length of output: 2155
Harden persisted timestamp parsing in task conversions.
Lines 293–300 and 309 use DateTime.parse() on stored values without defensive checks. Line 296 (..entry = DateTime.parse(t.entry)) is particularly risky—any malformed or empty string will throw FormatException and crash task loading. Empty strings pass null-checks but will still cause crashes.
Replace with DateTime.tryParse() and explicit fallback handling. This pattern is already used elsewhere in the codebase (e.g., lines 357, 367 in taskc_details_controller.dart).
Also applies to the similar conversion method at lines 234–242 (convertTaskForReplicaToTask).
Proposed fix example
Task convertTaskForCToTask(TaskForC t) {
+ DateTime? _safeParse(String? raw) {
+ if (raw == null || raw.isEmpty) return null;
+ return DateTime.tryParse(raw);
+ }
+ final fallbackNow = DateTime.now().toUtc();
+
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
+ ..due = _safeParse(t.due)
+ ..start = _safeParse(t.start)
+ ..wait = _safeParse(t.wait)
+ ..entry = _safeParse(t.entry) ?? fallbackNow
+ ..modified = _safeParse(t.modified)
+ ..end = _safeParse(t.end)
..tags = t.tags != null
? ListBuilder<String>(t.tags!)
: null
..annotations = t.annotations != null
? ListBuilder<Annotation>(
t.annotations!.map(
(a) => Annotation((ann) => ann
..description = a.description ?? ''
- ..entry = DateTime.parse(a.entry ?? DateTime.now().toIso8601String())),
+ ..entry = _safeParse(a.entry) ?? fallbackNow),
),
)
: null
);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/home/controllers/home_controller.dart` around lines 293 -
300, The task conversion code is currently using DateTime.parse on persisted
strings (fields t.entry, t.due, t.start, t.wait, t.modified, t.end) which will
throw FormatException for empty or malformed values; update the conversion logic
in the method containing those chained assignments and in the similar
convertTaskForReplicaToTask method to use DateTime.tryParse(...) for each
timestamp and fall back to null (or an appropriate default) when tryParse
returns null, ensuring you replace DateTime.parse(...) calls for t.entry and the
other fields with defensive tryParse usage and explicit null handling.
| import 'dart:io'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter_slidable/flutter_slidable.dart'; | ||
| import 'package:get/get.dart'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Step 1: Verify dart:io import in the specific file
echo "=== Checking the specific file ==="
cat -n lib/app/modules/infoRoute/bindings/task_info_binding.dart | head -20Repository: CCExtractor/taskwarrior-flutter
Length of output: 719
🏁 Script executed:
#!/bin/bash
# Step 2: Check if dart:io is actually used in the binding file
echo "=== Checking if dart:io is used in the binding ==="
rg "dart:io" lib/app/modules/infoRoute/bindings/task_info_binding.dart -A 5 -B 5Repository: CCExtractor/taskwarrior-flutter
Length of output: 450
🏁 Script executed:
#!/bin/bash
# Step 3: Search for all dart:io imports in lib/
echo "=== All dart:io imports in lib/ ==="
rg -n "^import 'dart:io';" lib/ -C 1Repository: CCExtractor/taskwarrior-flutter
Length of output: 5009
🏁 Script executed:
#!/bin/bash
# Step 4: Check if this binding is conditionally imported for web
echo "=== Searching for conditional imports or web guards ==="
rg -n "dart:io|web" lib/app/modules/infoRoute/bindings/ -B 2 -A 2Repository: CCExtractor/taskwarrior-flutter
Length of output: 425
Remove unused dart:io import from this binding.
Line 1 imports dart:io but it is not used anywhere in the binding file. Bindings should only import dependencies they directly reference. Removing this unused import improves code cleanliness.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/infoRoute/bindings/task_info_binding.dart` around lines 1 -
4, Remove the unused import 'dart:io' from task_info_binding.dart (the binding
that contains imports including package:flutter/material.dart,
package:flutter_slidable/flutter_slidable.dart, and package:get/get.dart);
locate the top-of-file import list in the TaskInfo binding and delete the line
"import 'dart:io';" so only used packages remain imported.
| if(arguments is List){ | ||
| uuid = arguments[1] as String; | ||
| } else{ | ||
| uuid = arguments.uuid; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart | head -40Repository: CCExtractor/taskwarrior-flutter
Length of output: 1622
🏁 Script executed:
rg -nP --type=dart "Routes\.TASK_INFO_ROUTE" -B2 -A2Repository: CCExtractor/taskwarrior-flutter
Length of output: 2685
🏁 Script executed:
rg -nP --type=dart "Get\.toNamed\(\s*Routes\.TASK_INFO_ROUTE" -C3Repository: CCExtractor/taskwarrior-flutter
Length of output: 3137
🏁 Script executed:
rg -nP --type=dart "TASK_INFO_ROUTE" -C2Repository: CCExtractor/taskwarrior-flutter
Length of output: 3944
Validate List bounds and argument shape before assigning uuid.
Lines 15–19 assume List has at least 2 elements and non-list arguments have a .uuid property. Add defensive checks to prevent RangeError and NoSuchMethodError on unexpected argument shapes.
Minimal fix
- if(arguments is List){
- uuid = arguments[1] as String;
- } else{
- uuid = arguments.uuid;
- }
+ if (arguments is List && arguments.length > 1) {
+ uuid = arguments[1] as String;
+ } else if (arguments is! List) {
+ uuid = arguments.uuid;
+ } else {
+ throw ArgumentError('Invalid TASK_INFO_ROUTE arguments: $arguments');
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if(arguments is List){ | |
| uuid = arguments[1] as String; | |
| } else{ | |
| uuid = arguments.uuid; | |
| } | |
| if (arguments is List && arguments.length > 1) { | |
| uuid = arguments[1] as String; | |
| } else if (arguments is! List) { | |
| uuid = arguments.uuid; | |
| } else { | |
| throw ArgumentError('Invalid TASK_INFO_ROUTE arguments: $arguments'); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/infoRoute/controllers/tasks_info_route_controller.dart`
around lines 15 - 19, The current assignment of uuid assumes arguments is a List
with at least two items or an object with a .uuid property; add defensive
validation before using arguments: when arguments is List check arguments.length
> 1 and that arguments[1] is a non-null String before assigning uuid, otherwise
handle the error or fallback; when not a List, check that arguments has a uuid
(e.g., arguments != null && arguments.uuid is String) or provide alternative
extraction (e.g., check for Map with 'uuid' key) and handle missing/invalid
values consistently (return error, null, or throw). Update the block around the
if(arguments is List) { ... } else { ... } to perform these guards and clear
fallback/error handling.
| Get.to( | ||
| () => DetailRouteView(), | ||
| binding: DetailRouteBinding(), | ||
| arguments: ["uuid", controller.uuid], | ||
| ); | ||
| } | ||
| await controller.loadTask(); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n -C2 "await Get\.to\(|Get\.to\(" lib/app/modules/infoRoute/views/task_info_view.dartRepository: CCExtractor/taskwarrior-flutter
Length of output: 1255
🏁 Script executed:
sed -n '100,120p' lib/app/modules/infoRoute/views/task_info_view.dartRepository: CCExtractor/taskwarrior-flutter
Length of output: 705
Add await to navigation in else branch to prevent race condition.
Line 107 Get.to() is not awaited in the non-taskchampion/non-replica branch, unlike lines 86 and 98. This causes controller.loadTask() on line 113 to execute before navigation completes, potentially reloading the task before edits are made.
Proposed fix
}
else {
- Get.to(
+ await Get.to(
() => DetailRouteView(),
binding: DetailRouteBinding(),
arguments: ["uuid", controller.uuid],
);
}
await controller.loadTask();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Get.to( | |
| () => DetailRouteView(), | |
| binding: DetailRouteBinding(), | |
| arguments: ["uuid", controller.uuid], | |
| ); | |
| } | |
| await controller.loadTask(); | |
| } | |
| await Get.to( | |
| () => DetailRouteView(), | |
| binding: DetailRouteBinding(), | |
| arguments: ["uuid", controller.uuid], | |
| ); | |
| } | |
| await controller.loadTask(); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/infoRoute/views/task_info_view.dart` around lines 107 - 114,
The navigation call using Get.to(() => DetailRouteView(), binding:
DetailRouteBinding(), arguments: ["uuid", controller.uuid]) in the else branch
is not awaited causing controller.loadTask() to run before navigation completes;
update that call to await the Get.to(...) invocation so the method
DetailRouteView navigation completes before calling controller.loadTask(),
preserving the existing pattern used earlier and preventing the race with
controller.loadTask().
| 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(); | ||
| }), |
There was a problem hiding this comment.
Action buttons are currently no-ops.
Lines 243–254 label buttons as done/start/wait/delete, but each handler only calls controller.loadTask() and does not change task state.
This is a user-facing behavior gap in the task info actions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/app/modules/infoRoute/views/task_info_view.dart` around lines 243 - 254,
The action buttons created by actionButton("done"/"start"/"wait"/"delete") only
call controller.loadTask() and therefore do nothing to change task state;
replace each handler to invoke the appropriate controller methods (e.g.,
controller.markDone()/controller.startTask()/controller.waitTask()/controller.deleteTask()
or whatever existing mutator methods are defined on the controller) and then
refresh state (call controller.loadTask() or update the task in-place) so the UI
and backend reflect the action; locate the handlers inside actionButton(...)
calls in task_info_view.dart and wire each label to its corresponding controller
method and handle success/error (update/load task) accordingly.
|
Hello @linuxcaffe, @Pavel401, and @SGI-CAPP-AT2. Now, it works for taskc v3 as well, and now our project is doesn't support annotations in Replica mode. If you have permission, then I can try annotations for Taskc v3, but for Taskserver it is working fine. |
Description
This PR introduces the task_info page and improves task_edit and issue #382 & #385
Fixes #385 & #382
Task info page for taskserver
taskinfo.mp4
Task info page for taskc(v3)
taskc.v3.mp4
Checklist
Summary by CodeRabbit