Fixed: Task server is not configured#579
Fixed: Task server is not configured#579Apprentice2907 wants to merge 10 commits intoCCExtractor:mainfrom
Conversation
|
Code looks irrelevant to issue |
|
The remaining CI failure is due to existing analyzer lints that are treated as errors via analysis_options.yaml (e.g. library_private_types_in_public_api, curly_braces_in_flow_control_structures, depend_on_referenced_packages). These issues are unrelated to the “Task server is not configured” fix and pre-exist on this branch. I’ve fixed all new analyzer errors introduced by this change. Happy to submit a follow-up PR to address analyzer debt if desired. |
|
@Apprentice2907 , |
|
Commits from diffrent PRs |
📝 WalkthroughWalkthroughThe pull request adds completed and deleted task status filters with mutually exclusive selection, migrates tag filter model classes to a dedicated models file, extends TaskServer configuration with trust parameter handling, and implements an auto-dismissing banner for unconfigured TaskServer scenarios. Changes
Sequence DiagramsequenceDiagram
participant User
participant HomeController
participant FilterDrawer
participant ScaffoldMessenger
participant TaskData
User->>FilterDrawer: Tap status filter (Deleted/Completed/Pending)
FilterDrawer->>HomeController: toggleDeletedFilter() or toggleCompletedFilter()
HomeController->>HomeController: Set filter flag, clear others (mutually exclusive)
HomeController->>HomeController: _refreshTasks()
HomeController->>TaskData: Fetch tasks by status filter
TaskData-->>HomeController: Return filtered tasks
HomeController->>FilterDrawer: Update displayed status
rect rgba(255, 0, 0, 0.5)
Note over HomeController,ScaffoldMessenger: TaskServer Not Configured Scenario
User->>HomeController: Trigger task refresh (no TaskServer config)
HomeController->>ScaffoldMessenger: showTaskServerNotConfiguredBanner()
ScaffoldMessenger->>User: Display MaterialBanner
HomeController->>HomeController: Start 5-second auto-dismiss timer
HomeController->>ScaffoldMessenger: clearMaterialBanners() after 5s
ScaffoldMessenger->>User: Banner disappears
HomeController->>HomeController: Reset taskServerBannerShown flag
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart (1)
52-75:⚠️ Potential issue | 🟡 MinorMissing field assignments in
setConfigurationFromFixtureForDebugging:The method parses the fixture taskrc and assigns
trust = taskrc.trust(line 57), but does not extract and assignserverandcredentialsfrom the same parsed taskrc object. This is inconsistent withonInitandsetContent, where all three fields are assigned together. The fixture method should include:var taskrc = Taskrc.fromString(contents); server = taskrc.server; credentials = taskrc.credentials; trust = taskrc.trust;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart` around lines 52 - 75, In setConfigurationFromFixtureForDebugging(), after parsing the fixture with Taskrc.fromString(contents) you only assign trust; additionally assign server and credentials from the parsed Taskrc (i.e. server = taskrc.server; credentials = taskrc.credentials;) so the controller's fields match onInit/setContent; update() remains the same and keep error handling as-is.lib/app/modules/home/views/filter_drawer_home_page.dart (1)
100-162:⚠️ Potential issue | 🟠 MajorThis drawer drops the waiting control and still never enters
completed.From the default branch on Line 127 you only call
togglePendingFilter(), so this UI never enablestoggleCompletedFilter()from the pending state. The row on Line 152 is now hard-wired to deleted, butwaitingFilteris still restored and applied inHomeController, which means an existing waiting filter can become invisible and impossible to turn off.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/home/views/filter_drawer_home_page.dart` around lines 100 - 162, The onTap logic in the filter drawer always falls back to filters.togglePendingFilter(), which prevents entering the completed state and leaves waitingFilter restored but invisible; update the onTap branch in the filter row (the one that currently calls togglePendingFilter()) to detect and call filters.toggleCompletedFilter() when the UI should switch to completed (or alternatively handle a waitingFilter state by exposing/toggling filters.toggleWaitingFilter() if that exists), and ensure the Visibility/switch block that binds filters.deletedFilter does not hide or block toggling of the waiting/completed state—use the existing symbols filters.toggleCompletedFilter(), filters.togglePendingFilter(), filters.toggleDeletedFilter(), and homeController.taskReplica to decide which toggle to call so waitingFilter cannot remain applied but invisible.lib/app/modules/home/controllers/home_controller.dart (1)
238-257:⚠️ Potential issue | 🟠 Major
completedFilteranddeletedFilterare the only drawer filters that aren’t tab-backed.Unlike the older filters, the new toggles on Line 390 and Line 398 only mutate Rx state.
_profileSet(),setInitialTabIndex(), andremoveTab()never reload them, so switching tabs or profiles silently drops the active completed/deleted status filter.Also applies to: 390-404, 565-593
🤖 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 238 - 257, _profileSet currently reloads many tab-backed filters but omits the two non-tab-backed toggles completedFilter and deletedFilter, so add lines to reload them from the current tab; specifically set completedFilter.value = Query(storage.tabs.tab()).getCompletedFilter() and deletedFilter.value = Query(storage.tabs.tab()).getDeletedFilter() inside _profileSet. Make the same change in setInitialTabIndex and removeTab so those functions also restore completedFilter and deletedFilter when switching/removing tabs (reference the completedFilter and deletedFilter Rx variables and the Query(...).getCompletedFilter()/getDeletedFilter() accessors).
🧹 Nitpick comments (6)
lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart (3)
45-45: Remove instructional comment.The
// ⬅️ ADD THISmarker should be removed before merging.🧹 Proposed cleanup
- trust = taskrc.trust; // ⬅️ ADD THIS + trust = taskrc.trust;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart` at line 45, Remove the leftover instructional comment marker from the assignment "trust = taskrc.trust;" in the manage_task_server_controller.dart controller so the line reads cleanly without the "// ⬅️ ADD THIS" suffix; locate the assignment to the variable trust in the controller method where taskrc is used (e.g., the controller that assigns taskrc.trust to trust) and delete only the trailing comment text.
101-101: Remove instructional comment.Same as previous - remove the
// ⬅️ ADD THISdevelopment marker.🧹 Proposed cleanup
- trust = taskrc.trust; // ⬅️ ADD THIS + trust = taskrc.trust;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart` at line 101, Remove the development marker comment next to the assignment "trust = taskrc.trust;" in the ManageTaskServerController (or the controller method where that assignment occurs); simply delete the trailing comment text "// ⬅️ ADD THIS" so the line becomes a plain assignment without any instructional marker, leaving surrounding logic and the variable names unchanged.
169-171: Logic is correct; remove instructional comment.The conditional appending of
taskd.trustis implemented correctly with proper null-safety checks. However, the// ⬅️ ADD THIScomment should be removed.🧹 Proposed cleanup
if (trust?.isNotEmpty == true) { - taskrcContent += "\ntaskd.trust=$trust"; // ⬅️ ADD THIS + taskrcContent += "\ntaskd.trust=$trust"; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart` around lines 169 - 171, Remove the inline instructional comment after the append line so the code reads cleanly; locate the conditional that checks `if (trust?.isNotEmpty == true)` in the ManageTaskServerController (or the method where `taskrcContent` is built) and delete the trailing comment `// ⬅️ ADD THIS` from the line `taskrcContent += "\ntaskd.trust=$trust";` leaving the logic unchanged.lib/app/utils/taskserver/taskrc.dart (2)
24-24: Remove instructional comment before merging.The comment
// ⬅️ ADD THIS LINEappears to be a development/instruction marker that should be removed before the code is merged.🧹 Proposed cleanup
- var trust = taskrc['taskd.trust']; // ⬅️ ADD THIS LINE + var trust = taskrc['taskd.trust'];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/utils/taskserver/taskrc.dart` at line 24, Remove the development/instruction marker from the inline comment on the variable declaration for trust: locate the line that declares var trust = taskrc['taskd.trust']; in taskrc.dart and delete the trailing comment "// ⬅️ ADD THIS LINE" so the code only contains the declaration (var trust = taskrc['taskd.trust'];) with no instructional comments.
30-30: Remove instructional comment.Same as above - remove the development marker comment.
🧹 Proposed cleanup
- trust: trust, // ⬅️ ADD THIS LINE + trust: trust,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/app/utils/taskserver/taskrc.dart` at line 30, Remove the development marker comment trailing the property assignment "trust: trust" (the inline comment "// ⬅️ ADD THIS LINE") so the code only contains the property assignment; locate the "trust: trust" entry in the taskrc.dart object/constructor and delete the instructional comment while preserving the assignment and formatting.test/models/filters_test.dart (1)
32-67: Add assertions for the new status filters.The fixture now wires
completedFilteranddeletedFilter, but none of the tests call those toggles or assert the initial field values. A constructor/callback wiring bug in the new parameters would still pass here.🧪 Suggested test additions
test('should correctly initialize with given parameters', () { expect(filters.pendingFilter, pendingFilter); expect(filters.waitingFilter, waitingFilter); + expect(filters.completedFilter, completedFilter); + expect(filters.deletedFilter, deletedFilter); expect(filters.projectFilter, projectFilter); expect(filters.tagFilters.tagUnion, tagUnion); expect(filters.tagFilters.tags, tags); }); + + test('should correctly toggle completed filter', () { + filters.toggleCompletedFilter(); + expect(completedFilter, isTrue); + + filters.toggleCompletedFilter(); + expect(completedFilter, isFalse); + }); + + test('should correctly toggle deleted filter', () { + filters.toggleDeletedFilter(); + expect(deletedFilter, isTrue); + + filters.toggleDeletedFilter(); + expect(deletedFilter, isFalse); + });Also applies to: 71-119
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/models/filters_test.dart` around lines 32 - 67, Tests are missing assertions and invocations for the new completedFilter and deletedFilter wiring in the Filters fixture; add checks that completedFilter and deletedFilter initialize to the expected values and call toggleCompletedFilter and toggleDeletedFilter to verify the callbacks flip their booleans. Locate the Filters construction in the test (the Filters(...) instance) and add assertions that completedFilter and deletedFilter equal the fixture vars, then invoke toggleCompletedFilter() and toggleDeletedFilter() and assert the corresponding completedFilter and deletedFilter values have toggled; do the same in the other fixture block referenced (lines ~71-119) to cover both cases.
🤖 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 3-4: The code tries to instantiate the abstract Sentences class
and references a non-existent Routes.TASKSERVER_SETUP; change the Sentences()
instantiation to use the concrete implementation or factory (e.g., the project's
concrete subclass or a getSentences() provider) so you don't instantiate an
abstract class, and fix the route reference by replacing Routes.TASKSERVER_SETUP
with the actual route constant defined in your routes file (or add a
TASKSERVER_SETUP constant to the routes configuration if that route is intended
to exist); update all occurrences (the Sentences() construction and the
Routes.TASKSERVER_SETUP usages) to use the correct concrete class/factory and
valid route constant.
- Around line 596-630: The current implementation can dismiss the wrong banner
because it clears all banners and uses scaffold-wide
hideCurrentMaterialBanner(); modify showTaskServerNotConfiguredBanner to capture
and track the specific ScaffoldFeatureController returned by
messenger.showMaterialBanner (e.g. store it in a field like
_taskServerBannerController) and use that controller.close() to dismiss this
banner; also create and store a Timer (e.g. _taskServerBannerTimer) for the 5s
auto-dismiss so you can cancel it when either TextButton is pressed or before
showing a new banner, remove the global messenger.clearMaterialBanners() call,
and ensure both button handlers and the timer clear/reset taskServerBannerShown
and null out the controller and timer so the lifecycle is tied to this banner
instance only.
---
Outside diff comments:
In `@lib/app/modules/home/controllers/home_controller.dart`:
- Around line 238-257: _profileSet currently reloads many tab-backed filters but
omits the two non-tab-backed toggles completedFilter and deletedFilter, so add
lines to reload them from the current tab; specifically set
completedFilter.value = Query(storage.tabs.tab()).getCompletedFilter() and
deletedFilter.value = Query(storage.tabs.tab()).getDeletedFilter() inside
_profileSet. Make the same change in setInitialTabIndex and removeTab so those
functions also restore completedFilter and deletedFilter when switching/removing
tabs (reference the completedFilter and deletedFilter Rx variables and the
Query(...).getCompletedFilter()/getDeletedFilter() accessors).
In `@lib/app/modules/home/views/filter_drawer_home_page.dart`:
- Around line 100-162: The onTap logic in the filter drawer always falls back to
filters.togglePendingFilter(), which prevents entering the completed state and
leaves waitingFilter restored but invisible; update the onTap branch in the
filter row (the one that currently calls togglePendingFilter()) to detect and
call filters.toggleCompletedFilter() when the UI should switch to completed (or
alternatively handle a waitingFilter state by exposing/toggling
filters.toggleWaitingFilter() if that exists), and ensure the Visibility/switch
block that binds filters.deletedFilter does not hide or block toggling of the
waiting/completed state—use the existing symbols
filters.toggleCompletedFilter(), filters.togglePendingFilter(),
filters.toggleDeletedFilter(), and homeController.taskReplica to decide which
toggle to call so waitingFilter cannot remain applied but invisible.
In
`@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart`:
- Around line 52-75: In setConfigurationFromFixtureForDebugging(), after parsing
the fixture with Taskrc.fromString(contents) you only assign trust; additionally
assign server and credentials from the parsed Taskrc (i.e. server =
taskrc.server; credentials = taskrc.credentials;) so the controller's fields
match onInit/setContent; update() remains the same and keep error handling
as-is.
---
Nitpick comments:
In
`@lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart`:
- Line 45: Remove the leftover instructional comment marker from the assignment
"trust = taskrc.trust;" in the manage_task_server_controller.dart controller so
the line reads cleanly without the "// ⬅️ ADD THIS" suffix; locate the
assignment to the variable trust in the controller method where taskrc is used
(e.g., the controller that assigns taskrc.trust to trust) and delete only the
trailing comment text.
- Line 101: Remove the development marker comment next to the assignment "trust
= taskrc.trust;" in the ManageTaskServerController (or the controller method
where that assignment occurs); simply delete the trailing comment text "// ⬅️
ADD THIS" so the line becomes a plain assignment without any instructional
marker, leaving surrounding logic and the variable names unchanged.
- Around line 169-171: Remove the inline instructional comment after the append
line so the code reads cleanly; locate the conditional that checks `if
(trust?.isNotEmpty == true)` in the ManageTaskServerController (or the method
where `taskrcContent` is built) and delete the trailing comment `// ⬅️ ADD THIS`
from the line `taskrcContent += "\ntaskd.trust=$trust";` leaving the logic
unchanged.
In `@lib/app/utils/taskserver/taskrc.dart`:
- Line 24: Remove the development/instruction marker from the inline comment on
the variable declaration for trust: locate the line that declares var trust =
taskrc['taskd.trust']; in taskrc.dart and delete the trailing comment "// ⬅️ ADD
THIS LINE" so the code only contains the declaration (var trust =
taskrc['taskd.trust'];) with no instructional comments.
- Line 30: Remove the development marker comment trailing the property
assignment "trust: trust" (the inline comment "// ⬅️ ADD THIS LINE") so the code
only contains the property assignment; locate the "trust: trust" entry in the
taskrc.dart object/constructor and delete the instructional comment while
preserving the assignment and formatting.
In `@test/models/filters_test.dart`:
- Around line 32-67: Tests are missing assertions and invocations for the new
completedFilter and deletedFilter wiring in the Filters fixture; add checks that
completedFilter and deletedFilter initialize to the expected values and call
toggleCompletedFilter and toggleDeletedFilter to verify the callbacks flip their
booleans. Locate the Filters construction in the test (the Filters(...)
instance) and add assertions that completedFilter and deletedFilter equal the
fixture vars, then invoke toggleCompletedFilter() and toggleDeletedFilter() and
assert the corresponding completedFilter and deletedFilter values have toggled;
do the same in the other fixture block referenced (lines ~71-119) to cover both
cases.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0d6c07b0-0fb1-4ef0-b9aa-bd1636abbd40
📒 Files selected for processing (9)
lib/app/models/filters.dartlib/app/models/tag_filters.dartlib/app/modules/home/controllers/home_controller.dartlib/app/modules/home/views/filter_drawer_home_page.dartlib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dartlib/app/services/tag_filter.dartlib/app/utils/add_task_dialogue/date_picker_input.dartlib/app/utils/taskserver/taskrc.darttest/models/filters_test.dart
| import 'package:taskwarrior/app/utils/language/sentences.dart'; | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether `Sentences` is abstract/concrete and whether `TASKSERVER_SETUP` is declared.
rg -n --type=dart 'abstract class Sentences|class Sentences\b' lib/app/utils/language
rg -n --type=dart '\bTASKSERVER_SETUP\b' lib/app/routesRepository: CCExtractor/taskwarrior-flutter
Length of output: 141
Fix compilation errors: Sentences is abstract and Routes.TASKSERVER_SETUP does not exist.
Line 54 instantiates Sentences() directly, but Sentences is an abstract class and cannot be instantiated. Line 612 references Routes.TASKSERVER_SETUP, which does not exist in the routes configuration. Both changes will fail to compile and must be corrected before merging.
Also applies to: 3-4, 8-8, 606-614
🤖 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 3 - 4,
The code tries to instantiate the abstract Sentences class and references a
non-existent Routes.TASKSERVER_SETUP; change the Sentences() instantiation to
use the concrete implementation or factory (e.g., the project's concrete
subclass or a getSentences() provider) so you don't instantiate an abstract
class, and fix the route reference by replacing Routes.TASKSERVER_SETUP with the
actual route constant defined in your routes file (or add a TASKSERVER_SETUP
constant to the routes configuration if that route is intended to exist); update
all occurrences (the Sentences() construction and the Routes.TASKSERVER_SETUP
usages) to use the correct concrete class/factory and valid route constant.
| 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.TASKSERVER_SETUP), | ||
| }, | ||
| 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 | ||
| }); |
There was a problem hiding this comment.
The auto-dismiss task can clear the wrong banner.
Line 602 clears every material banner up front, and the delayed callback on Line 627 later calls hideCurrentMaterialBanner() on whichever banner is current at that moment. If this warning is dismissed or replaced before 5 seconds elapse, the timer can remove an unrelated banner, and the “shown” guard becomes reusable immediately after. Track the specific banner controller/timer instead of the global current banner.
🛠️ Safer banner lifecycle sketch
+import 'dart:async';
import 'dart:collection';
import 'dart:io';
class HomeController extends GetxController {
+ Timer? _taskServerBannerTimer;
+ ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason>?
+ _taskServerBannerController;
+
void showTaskServerNotConfiguredBanner(BuildContext context) {
if (taskServerBannerShown.value) return;
taskServerBannerShown.value = true;
final messenger = ScaffoldMessenger.of(context);
- messenger.clearMaterialBanners();
-
- messenger.showMaterialBanner(
+ _taskServerBannerTimer?.cancel();
+ _taskServerBannerController?.close();
+ _taskServerBannerController = messenger.showMaterialBanner(
MaterialBanner(
content: Text(sentences.homePageTaskWarriorNotConfigured),
actions: [
TextButton(
onPressed: () {
- messenger.hideCurrentMaterialBanner();
+ _taskServerBannerTimer?.cancel();
+ _taskServerBannerController?.close();
taskServerBannerShown.value = false;
Get.toNamed(Routes.TASKSERVER_SETUP);
},
child: Text(sentences.homePageSetup),
),
TextButton(
onPressed: () {
- messenger.hideCurrentMaterialBanner();
+ _taskServerBannerTimer?.cancel();
+ _taskServerBannerController?.close();
taskServerBannerShown.value = false;
},
child: const Text('Dismiss'),
),
],
),
);
- Future.delayed(const Duration(seconds: 5), () {
- messenger.hideCurrentMaterialBanner();
+ _taskServerBannerTimer = Timer(const Duration(seconds: 5), () {
+ _taskServerBannerController?.close();
taskServerBannerShown.value = false;
});
}
`@override`
void onClose() {
+ _taskServerBannerTimer?.cancel();
searchFocusNode.dispose();
super.onClose();
}
}🤖 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 596 -
630, The current implementation can dismiss the wrong banner because it clears
all banners and uses scaffold-wide hideCurrentMaterialBanner(); modify
showTaskServerNotConfiguredBanner to capture and track the specific
ScaffoldFeatureController returned by messenger.showMaterialBanner (e.g. store
it in a field like _taskServerBannerController) and use that controller.close()
to dismiss this banner; also create and store a Timer (e.g.
_taskServerBannerTimer) for the 5s auto-dismiss so you can cancel it when either
TextButton is pressed or before showing a new banner, remove the global
messenger.clearMaterialBanners() call, and ensure both button handlers and the
timer clear/reset taskServerBannerShown and null out the controller and timer so
the lifecycle is tied to this banner instance only.
Description
This PR fixes the issue where the “TaskServer is not configured” banner remained visible indefinitely on the Home screen.
The banner now:
The fix is limited to UI/UX behavior and does not modify TaskServer parsing or backend logic.
Fixes #577
Screenshots
N/A (UI behavior change – auto and manual dismissal)
Checklist
Summary by CodeRabbit
New Features
Refactor