-
Notifications
You must be signed in to change notification settings - Fork 167
feat: introducing task_info and improving task_edit #608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import 'dart:io'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter_slidable/flutter_slidable.dart'; | ||
| import 'package:get/get.dart'; | ||
|
Comment on lines
+1
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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 Line 1 imports 🤖 Prompt for AI Agents |
||
| 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>( | ||
| () => TasksInfoRouteController(), | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -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<Task>(); | ||||||||||||||||||||||||||
| @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; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
+15
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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 Lines 15–19 assume List has at least 2 elements and non-list arguments have a 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| loadTask(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Future<void> loadTask() async { | ||||||||||||||||||||||||||
| final homeController = Get.find<HomeController>(); | ||||||||||||||||||||||||||
| 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; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: CCExtractor/taskwarrior-flutter
Length of output: 130
🏁 Script executed:
Repository: CCExtractor/taskwarrior-flutter
Length of output: 1195
🏁 Script executed:
Repository: CCExtractor/taskwarrior-flutter
Length of output: 15552
🏁 Script executed:
Repository: CCExtractor/taskwarrior-flutter
Length of output: 1416
🏁 Script executed:
Repository: 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 throwFormatExceptionand 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 intaskc_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