Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion lib/app/models/filters.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
import 'package:taskwarrior/app/services/tag_filter.dart';
// lib/app/models/filters.dart

import 'package:taskwarrior/app/models/tag_filters.dart';


class Filters {
const Filters({
required this.pendingFilter,
required this.waitingFilter,
required this.completedFilter,
required this.deletedFilter,
required this.togglePendingFilter,
required this.toggleWaitingFilter,
required this.toggleCompletedFilter,
required this.toggleDeletedFilter,
required this.tagFilters,
required this.projects,
required this.projectFilter,
required this.toggleProjectFilter,
required this.hideBlocked, // ADD
required this.toggleHideBlocked,
});

final bool pendingFilter;
final bool waitingFilter;
final bool completedFilter;
final bool deletedFilter;
final void Function() togglePendingFilter;
final void Function() toggleWaitingFilter;
final void Function() toggleCompletedFilter;
final void Function() toggleDeletedFilter;
final TagFilters tagFilters;
final dynamic projects;
final String projectFilter;
final void Function(String) toggleProjectFilter;
final bool hideBlocked;
final void Function() toggleHideBlocked;
}
25 changes: 25 additions & 0 deletions lib/app/models/tag_filters.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// lib/app/models/tag_filters.dart

class TagFilterMetadata {
const TagFilterMetadata({
required this.display,
required this.selected,
});

final String display;
final bool selected;
}

class TagFilters {
const TagFilters({
required this.tagUnion,
required this.toggleTagUnion,
required this.tags,
required this.toggleTagFilter,
});

final bool tagUnion;
final void Function() toggleTagUnion;
final Map<String, TagFilterMetadata> tags;
final void Function(String) toggleTagFilter;
}
126 changes: 114 additions & 12 deletions lib/app/modules/home/controllers/home_controller.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// ignore_for_file: use_build_context_synchronously, unrelated_type_equality_checks

import 'package:taskwarrior/app/utils/language/sentences.dart';

import 'dart:collection';
import 'dart:io';

import 'package:taskwarrior/app/routes/app_pages.dart';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
Expand All @@ -18,7 +22,8 @@ import 'package:taskwarrior/app/models/tag_meta_data.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';
import 'package:taskwarrior/app/services/tag_filter.dart';
import 'package:taskwarrior/app/models/tag_filters.dart';

import 'package:taskwarrior/app/tour/filter_drawer_tour.dart';
import 'package:taskwarrior/app/tour/home_page_tour.dart';
import 'package:taskwarrior/app/tour/task_swipe_tour.dart';
Expand All @@ -40,12 +45,20 @@ 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:taskwarrior/app/utils/language/sentence_manager.dart';


class HomeController extends GetxController {
final SplashController splashController = Get.find<SplashController>();
late Storage storage;
final RxBool taskServerBannerShown = false.obs;
late Sentences sentences;
final RxBool pendingFilter = false.obs;
final RxBool waitingFilter = false.obs;
final RxBool hideBlocked = false.obs;
final RxString projectFilter = ''.obs;
final RxBool completedFilter = false.obs;
final RxBool deletedFilter = false.obs;
final RxBool tagUnion = false.obs;
final RxString selectedSort = ''.obs;
final RxSet<String> selectedTags = <String>{}.obs;
Expand All @@ -72,6 +85,9 @@ class HomeController extends GetxController {
void onInit() {
debugPrint("🚀 BOOT: HomeController.onInit()");
super.onInit();
sentences = SentenceManager(
currentLanguage: AppSettings.selectedLanguage,
).sentences;
storage = Storage(
Directory(
'${splashController.baseDirectory.value.path}/profiles/${splashController.currentProfile.value}',
Expand Down Expand Up @@ -100,6 +116,8 @@ class HomeController extends GetxController {
everAll([
pendingFilter,
waitingFilter,
completedFilter,
deletedFilter,
projectFilter,
tagUnion,
selectedSort,
Expand Down Expand Up @@ -224,12 +242,7 @@ class HomeController extends GetxController {

void _profileSet() {
pendingFilter.value = Query(storage.tabs.tab()).getPendingFilter();
if (!Query(storage.tabs.tab()).getWaitingFilter()) {
waitingFilter.value = Query(storage.tabs.tab()).getWaitingFilter();
} else {
Query(storage.tabs.tab()).toggleWaitingFilter();
waitingFilter.value = Query(storage.tabs.tab()).getWaitingFilter();
}
waitingFilter.value = Query(storage.tabs.tab()).getWaitingFilter();
projectFilter.value = Query(storage.tabs.tab()).projectFilter();
tagUnion.value = Query(storage.tabs.tab()).tagUnion();
selectedSort.value = Query(storage.tabs.tab()).getSelectedSort();
Expand All @@ -244,22 +257,46 @@ class HomeController extends GetxController {
}

void _refreshTasks() {
if (pendingFilter.value) {

if (deletedFilter.value) {
queriedTasks.value = storage.data
.completedData()
.where((task) => task.status == 'deleted')
.toList();
} else if (completedFilter.value) {
queriedTasks.value = storage.data
.completedData()
.where((task) => task.status == 'completed')
.toList();
} else if (pendingFilter.value) {
queriedTasks.value = storage.data
.pendingData()
.where((task) => task.status == 'pending')
.toList();
} else {
queriedTasks.value = storage.data.completedData();
var currentTime = DateTime.now();
queriedTasks.value = storage.data.pendingData().where((task) =>
task.status != 'waiting' &&
!(task.wait != null && task.wait!.isAfter(currentTime))
).toList();
}

if (waitingFilter.value) {
var currentTime = DateTime.now();
if (hideBlocked.value) {
queriedTasks.value = queriedTasks
.where((task) => task.wait != null && task.wait!.isAfter(currentTime))
.where((task) => task.depends == null || task.depends!.isEmpty)
.toList();
}


// Rest of the method stays the same...
if (waitingFilter.value) {
var currentTime = DateTime.now();
queriedTasks.value = storage.data.pendingData().where((task) =>
task.status == 'waiting' ||
(task.wait != null && task.wait!.isAfter(currentTime))
).toList();
}
Comment on lines 259 to +298
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Filter logic structure is confusing and potentially incorrect.

The waitingFilter check (lines 292-298) sits outside the main if-else chain and runs after hideBlocked filtering. This means when waitingFilter is enabled, it completely replaces queriedTasks with a fresh query, ignoring the hideBlocked filter that was just applied.

If this is intentional (waiting tasks should ignore blocked filtering), the code flow would be clearer with waitingFilter inside the main if-else chain. If unintentional, blocked tasks would incorrectly appear when viewing waiting tasks.

Additionally:

  • Line 291's comment "Rest of the method stays the same..." is misleading since the waitingFilter code that follows is new logic.
  • DateTime.now() is called twice (lines 277 and 293); consider capturing it once at the method start.
Suggested refactor to clarify intent
 void _refreshTasks() {
-    
+    var currentTime = DateTime.now();
+
     if (deletedFilter.value) {
       queriedTasks.value = storage.data
           .completedData()
           .where((task) => task.status == 'deleted')
           .toList();
     } else if (completedFilter.value) {
       queriedTasks.value = storage.data
           .completedData()
           .where((task) => task.status == 'completed')
           .toList();
+    } else if (waitingFilter.value) {
+      queriedTasks.value = storage.data.pendingData().where((task) =>
+        task.status == 'waiting' ||
+        (task.wait != null && task.wait!.isAfter(currentTime))
+      ).toList();
     } else if (pendingFilter.value) {
       queriedTasks.value = storage.data
           .pendingData()
           .where((task) => task.status == 'pending')
           .toList();
     } else {
-      var currentTime = DateTime.now();
       queriedTasks.value = storage.data.pendingData().where((task) =>
         task.status != 'waiting' &&
         !(task.wait != null && task.wait!.isAfter(currentTime))
       ).toList();
     }

     if (hideBlocked.value) {
       queriedTasks.value = queriedTasks
           .where((task) => task.depends == null || task.depends!.isEmpty)
           .toList();
     }
-
-    // Rest of the method stays the same...
-    if (waitingFilter.value) {
-      var currentTime = DateTime.now();
-      queriedTasks.value = storage.data.pendingData().where((task) =>
-        task.status == 'waiting' ||
-        (task.wait != null && task.wait!.isAfter(currentTime))
-      ).toList();
-    }
🤖 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 259 -
298, The _refreshTasks method's filter order is wrong: waitingFilter is applied
after hideBlocked and replaces queriedTasks, causing hideBlocked to be ignored
for waiting views; fix by capturing DateTime.now() once at method start (assign
to currentTime), then move the waitingFilter branch into the main if-else chain
alongside deletedFilter/completedFilter/pendingFilter so it produces
queriedTasks from storage.data.pendingData() like the others, or if waiting
should ignore hideBlocked explicitly apply hideBlocked only for the non-waiting
branches; also remove or update the misleading "Rest of the method stays the
same..." comment so it reflects the new flow (references: _refreshTasks,
waitingFilter, hideBlocked, queriedTasks, storage.data.pendingData(),
storage.data.completedData()).


if (projectFilter.value.isNotEmpty) {
queriedTasks.value = queriedTasks.where((task) {
if (task.project == null) {
Expand Down Expand Up @@ -354,6 +391,22 @@ class HomeController extends GetxController {
_refreshTasks();
}

void toggleCompletedFilter() {
completedFilter.toggle();
if (completedFilter.value) {
deletedFilter.value = false;
}
_refreshTasks();
}

void toggleDeletedFilter() {
deletedFilter.toggle();
if (deletedFilter.value) {
completedFilter.value = false;
}
_refreshTasks();
}

void toggleProjectFilter(String project) {
Query(storage.tabs.tab()).toggleProjectFilter(project);
projectFilter.value = Query(storage.tabs.tab()).projectFilter();
Expand Down Expand Up @@ -544,6 +597,44 @@ class HomeController extends GetxController {
_refreshTasks();
}

void showTaskServerNotConfiguredBanner(BuildContext context) {
if (taskServerBannerShown.value) return;

taskServerBannerShown.value = true;
final messenger = ScaffoldMessenger.of(context);

messenger.clearMaterialBanners();

messenger.showMaterialBanner(
MaterialBanner(
content: Text(sentences.homePageTaskWarriorNotConfigured),
actions: [
TextButton(
onPressed: () {
messenger.hideCurrentMaterialBanner();
taskServerBannerShown.value = false; // ✅ RESET flag
Get.toNamed(Routes.MANAGE_TASK_SERVER);
},
child: Text(sentences.homePageSetup),
),
TextButton(
onPressed: () {
messenger.hideCurrentMaterialBanner();
taskServerBannerShown.value = false; // ✅ RESET flag
},
child: const Text('Dismiss'),
),
],
),
);

Future.delayed(const Duration(seconds: 5), () {
messenger.hideCurrentMaterialBanner();
taskServerBannerShown.value = false; // ✅ RESET flag
});
}


void renameTab({
required String tab,
required String name,
Expand Down Expand Up @@ -656,15 +747,26 @@ class HomeController extends GetxController {
tags: tags,
toggleTagFilter: toggleTagFilter,
);

// REPLACE this entire Filters() instantiation:
var filters = Filters(
pendingFilter: pendingFilter.value,
waitingFilter: waitingFilter.value,
completedFilter: completedFilter.value,
deletedFilter: deletedFilter.value,
togglePendingFilter: togglePendingFilter,
toggleWaitingFilter: toggleWaitingFilter,
toggleCompletedFilter: toggleCompletedFilter,
toggleDeletedFilter: toggleDeletedFilter,
projects: projects,
projectFilter: projectFilter.value,
toggleProjectFilter: toggleProjectFilter,
tagFilters: tagFilters,
hideBlocked: hideBlocked.value,
toggleHideBlocked: () {
hideBlocked.value = !hideBlocked.value;
_refreshTasks();
},
);
return filters;
}
Expand Down
Loading
Loading