Skip to content

Improve directory buttons UI in settings screen #623

Open
srykaran wants to merge 4 commits intoCCExtractor:mainfrom
srykaran:improve-directory-buttons-ui
Open

Improve directory buttons UI in settings screen #623
srykaran wants to merge 4 commits intoCCExtractor:mainfrom
srykaran:improve-directory-buttons-ui

Conversation

@srykaran
Copy link

@srykaran srykaran commented Mar 13, 2026

Description

This PR improves the UI consistency of the "Set To Default" and "Change Directory" buttons in the Settings → Storage and Data section.

Previously these buttons appeared visually inconsistent with the rest of the settings UI.

Changes

  • Updated button styling for better visual hierarchy
  • Added outlined style for Set To Default
  • Used filled primary style for Change Directory
  • Improved alignment and spacing between the buttons

Screenshots

Before

image

After

image

Type of Change

UI improvement / UX consistency

Summary by CodeRabbit

  • New Features

    • Added a "No Project" filter option to view tasks without assigned projects alongside the existing "All Projects" filter.
    • Introduced radio button selection for project filters on the home page.
  • UI Improvements

    • Updated settings directory buttons with icons and enhanced styling.
  • Localization

    • Added "No Project" label translations across all supported languages (English, Bengali, French, German, Hindi, Marathi, Spanish, Urdu).

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

This PR adds support for filtering tasks with no project assigned. It introduces a sentinel constant in HomeController, updates project column UI to display and handle a "No Project" filter option, adds translations across 8 supported languages, and refines button styling in the settings page.

Changes

Cohort / File(s) Summary
Controller Enhancement
lib/app/modules/home/controllers/home_controller.dart
Introduces noProjectValue static constant as a sentinel display name and updates project filtering logic to treat this value as a special case for tasks with null or empty project fields.
Project Column Views
lib/app/modules/home/views/project_column_home_page.dart, lib/app/modules/home/views/project_column_taskc.dart
Adds UI selection for "No Project" filter option via radio buttons and GestureDetector handlers. Updates ProjectTileTaskc to accept optional displayName parameter for user-friendly label rendering. Filters out empty project keys.
Language Support
lib/app/utils/language/sentences.dart, lib/app/utils/language/{bengali,english,french,german,hindi,marathi,spanish,urdu}_sentences.dart
Adds noProject getter method to abstract Sentences class and all 8 language implementations, providing singular "No Project" labels in respective languages alongside existing plural forms.
Settings UI
lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart
Replaces TextButton controls with styled icon variants: OutlinedButton.icon for "Reset to Default" and ElevatedButton.icon for "Change Directory", with updated typography and spacing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 A filter for tasks without homes so bare,
With "No Project" option floating there,
Eight tongues now speak this gentle call,
While buttons dress in finest shawl! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title does not accurately reflect the main changes in the changeset. While one file updates button UI in settings, the majority of changes involve adding 'No Project' filtering functionality across multiple files. Update the title to reflect the primary change: 'Add No Project filtering and improve directory buttons UI' or split into separate PRs by concern.
Description check ⚠️ Warning The PR description focuses only on button UI improvements but omits substantial changes: adding noProject filtering logic, new HomeController constant, and i18n translations across 7+ language files. Expand description to document all changes including the new No Project filtering feature, HomeController.noProjectValue constant, and translations added to all language files.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart (1)

60-67: Consider providing a fallback color to avoid potential null crash.

Line 62 uses force-unwrap (tColors.purpleShade!) for BorderSide.color which requires a non-null value. If purpleShade is ever null in the theme extension, this will cause a runtime crash.

💡 Suggested safer approach
                   child: OutlinedButton.icon(
                     style: OutlinedButton.styleFrom(
-                      side: BorderSide(color: tColors.purpleShade!),
+                      side: BorderSide(color: tColors.purpleShade ?? TaskWarriorColors.purple),
                       shape: RoundedRectangleBorder(
                         borderRadius: BorderRadius.circular(12),
                       ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart`
around lines 60 - 67, The BorderSide color currently force-unwraps the theme
extension (tColors.purpleShade!) which can crash if null; update the
OutlinedButton.styleFrom BorderSide(color: ...) in
settings_page_select_directory_list_tile.dart (the OutlinedButton.icon block /
BorderSide usage) to use a safe fallback instead of ! — e.g., use a
null-coalescing fallback from tColors.purpleShade to a sensible default (or
Theme.of(context).colorScheme.primary) so the BorderSide always receives a
non-null Color.
lib/app/utils/language/hindi_sentences.dart (1)

409-410: Consider aligning wording with existing Hindi project terminology.

At Line 409, प्रोजेक्ट is understandable, but the file mostly uses परियोजना. Aligning terminology improves consistency.

♻️ Suggested tweak
-  String get noProject => 'कोई प्रोजेक्ट नहीं';
+  String get noProject => 'कोई परियोजना नहीं';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/app/utils/language/hindi_sentences.dart` around lines 409 - 410, The
Hindi string in the getter noProject uses "प्रोजेक्ट" but the codebase prefers
"परियोजना"; update the return value of the noProject getter to use "कोई परियोजना
नहीं" so terminology matches other translations (search for the noProject getter
to locate and modify the string).
🤖 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`:
- Line 44: The controller uses a UI string as an internal sentinel (static const
String noProjectValue = " (No Project) "), which is fragile; change
noProjectValue to a stable internal key (e.g. "__NO_PROJECT__") and update all
controller logic that checks or sets noProjectValue (references in this file,
including the filter/comparison logic around the current usage at lines
~266-268) to use that internal key; move any user-facing label (the localized "
(No Project) " display text) into the view layer where the project list /
dropdown is rendered so the UI shows the friendly text while the
controller/state uses the stable "__NO_PROJECT__" sentinel. Ensure equality
checks, filter construction, and any serialization still use the new internal
constant name noProjectValue.

In `@lib/app/modules/home/views/project_column_home_page.dart`:
- Around line 91-107: The header is rendering projectFilter directly which can
show the internal token HomeController.noProjectValue; instead, when
projectFilter == HomeController.noProjectValue map it to the localized label
from SentenceManager(currentLanguage:
AppSettings.selectedLanguage).sentences.noProject before rendering. Update the
selected-project header rendering logic to check projectFilter (or the getter
used there) and replace the token with the SentenceManager noProject string so
the UI displays a localized "No Project" label.

In `@lib/app/modules/home/views/project_column_taskc.dart`:
- Around line 76-81: The header currently displays the raw projectFilter value
instead of translating the sentinel; update the header rendering logic to detect
when projectFilter == HomeController.noProjectValue and substitute it with the
translated label from SentenceManager(currentLanguage:
AppSettings.selectedLanguage).sentences.noProject; otherwise continue displaying
projectFilter. Locate the header code that uses projectFilter (the component
that also uses the callback and project props) and implement this conditional
replacement so the UI shows the localized "no project" text rather than the
internal sentinel.

---

Nitpick comments:
In
`@lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart`:
- Around line 60-67: The BorderSide color currently force-unwraps the theme
extension (tColors.purpleShade!) which can crash if null; update the
OutlinedButton.styleFrom BorderSide(color: ...) in
settings_page_select_directory_list_tile.dart (the OutlinedButton.icon block /
BorderSide usage) to use a safe fallback instead of ! — e.g., use a
null-coalescing fallback from tColors.purpleShade to a sensible default (or
Theme.of(context).colorScheme.primary) so the BorderSide always receives a
non-null Color.

In `@lib/app/utils/language/hindi_sentences.dart`:
- Around line 409-410: The Hindi string in the getter noProject uses "प्रोजेक्ट"
but the codebase prefers "परियोजना"; update the return value of the noProject
getter to use "कोई परियोजना नहीं" so terminology matches other translations
(search for the noProject getter to locate and modify the string).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0f84d19a-99d9-4727-84d2-f6a627dc92db

📥 Commits

Reviewing files that changed from the base of the PR and between f058b4a and 2b54158.

📒 Files selected for processing (13)
  • lib/app/modules/home/controllers/home_controller.dart
  • lib/app/modules/home/views/project_column_home_page.dart
  • lib/app/modules/home/views/project_column_taskc.dart
  • lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart
  • lib/app/utils/language/bengali_sentences.dart
  • lib/app/utils/language/english_sentences.dart
  • lib/app/utils/language/french_sentences.dart
  • lib/app/utils/language/german_sentences.dart
  • lib/app/utils/language/hindi_sentences.dart
  • lib/app/utils/language/marathi_sentences.dart
  • lib/app/utils/language/sentences.dart
  • lib/app/utils/language/spanish_sentences.dart
  • lib/app/utils/language/urdu_sentences.dart

import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';

class HomeController extends GetxController {
static const String noProjectValue = " (No Project) ";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a stable internal key instead of display text for the no-project sentinel.

Line 44 currently uses a UI string (" (No Project) ") as internal filter state. That makes filtering fragile (collision with real project names and whitespace sensitivity), and Line 266 depends on that exact formatted text.

♻️ Proposed refactor
-  static const String noProjectValue = " (No Project) ";
+  static const String noProjectFilterKey = '__NO_PROJECT__';
@@
-        if (projectFilter.value == noProjectValue) {
-          return task.project == null || task.project!.isEmpty;
+        if (projectFilter.value == noProjectFilterKey) {
+          return task.project == null || task.project!.trim().isEmpty;
         }

Keep localized display labels in the view layer, and keep this controller value purely internal.

Also applies to: 266-268

🤖 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` at line 44, The
controller uses a UI string as an internal sentinel (static const String
noProjectValue = " (No Project) "), which is fragile; change noProjectValue to a
stable internal key (e.g. "__NO_PROJECT__") and update all controller logic that
checks or sets noProjectValue (references in this file, including the
filter/comparison logic around the current usage at lines ~266-268) to use that
internal key; move any user-facing label (the localized " (No Project) " display
text) into the view layer where the project list / dropdown is rendered so the
UI shows the friendly text while the controller/state uses the stable
"__NO_PROJECT__" sentinel. Ensure equality checks, filter construction, and any
serialization still use the new internal constant name noProjectValue.

Comment on lines +91 to +107
GestureDetector(
onTap: () => callback(HomeController.noProjectValue),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Radio(
activeColor: tColors.primaryTextColor,
focusColor: tColors.secondaryTextColor,
toggleable: true,
value: HomeController.noProjectValue,
groupValue: projectFilter,
onChanged: (_) => callback(HomeController.noProjectValue),
),
Text(
SentenceManager(currentLanguage: AppSettings.selectedLanguage)
.sentences
.noProject,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Map noProjectValue to a localized display label in the selected-project header.

Line 92/Line 100 sets projectFilter to HomeController.noProjectValue, but Line 53 renders projectFilter directly. This can show an internal token instead of localized “No Project”.

🐛 Suggested fix
   `@override`
   Widget build(BuildContext context) {
     TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!;
+    final sentences =
+        SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences;
+    final selectedProjectLabel = projectFilter.isEmpty
+        ? sentences.notSelected
+        : projectFilter == HomeController.noProjectValue
+            ? sentences.noProject
+            : projectFilter;
     return Column(
       children: [
@@
               Text(
-                "${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.project} : ",
+                "${sentences.project} : ",
@@
                       Text(
-                        projectFilter == "" ? SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.notSelected : projectFilter,
+                        selectedProjectLabel,
                         style: TextStyle(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/app/modules/home/views/project_column_home_page.dart` around lines 91 -
107, The header is rendering projectFilter directly which can show the internal
token HomeController.noProjectValue; instead, when projectFilter ==
HomeController.noProjectValue map it to the localized label from
SentenceManager(currentLanguage:
AppSettings.selectedLanguage).sentences.noProject before rendering. Update the
selected-project header rendering logic to check projectFilter (or the getter
used there) and replace the token with the SentenceManager noProject string so
the UI displays a localized "No Project" label.

Comment on lines +76 to +81
project: HomeController.noProjectValue,
projectFilter: projectFilter,
callback: callback),
callback: (val) => callback(val),
displayName: SentenceManager(
currentLanguage: AppSettings.selectedLanguage,
).sentences.noProject),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Translate the selected noProjectValue in the header instead of showing raw filter value.

Line 76 sets the sentinel HomeController.noProjectValue, but the header (Line 51-Line 56) prints projectFilter directly. This may expose internal value text in UI.

🐛 Suggested fix
   `@override`
   Widget build(BuildContext context) {
     TaskwarriorColorTheme tColors =
         Theme.of(context).extension<TaskwarriorColorTheme>()!;
+    final sentences =
+        SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences;
+    final selectedProjectLabel = projectFilter.isEmpty
+        ? sentences.notSelected
+        : projectFilter == HomeController.noProjectValue
+            ? sentences.noProject
+            : projectFilter;
     return Column(
@@
                   child: Text(
-                    projectFilter.isEmpty
-                        ? SentenceManager(
-                                currentLanguage: AppSettings.selectedLanguage)
-                            .sentences
-                            .notSelected
-                        : projectFilter,
+                    selectedProjectLabel,
                     style: TextStyle(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/app/modules/home/views/project_column_taskc.dart` around lines 76 - 81,
The header currently displays the raw projectFilter value instead of translating
the sentinel; update the header rendering logic to detect when projectFilter ==
HomeController.noProjectValue and substitute it with the translated label from
SentenceManager(currentLanguage:
AppSettings.selectedLanguage).sentences.noProject; otherwise continue displaying
projectFilter. Locate the header code that uses projectFilter (the component
that also uses the callback and project props) and implement this conditional
replacement so the UI shows the localized "no project" text rather than the
internal sentinel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant