feat: unify Create screens with shared design system#164
feat: unify Create screens with shared design system#164shashank2k5 wants to merge 1 commit intoAOSSIE-Org:mainfrom
Conversation
📝 WalkthroughWalkthroughThis PR consolidates UI styling and components across the Create (Task, Ticket, Meeting) screens by introducing a unified form components library with design tokens, replacing duplicated widget patterns with reusable components, and registering printing/speech-to-text plugins across multiple platform-specific files. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/screens/tasks/create_task_screen.dart (1)
96-101:⚠️ Potential issue | 🟠 Major
_isLoadingserves dual purpose — hides the form during task creation.
_isLoadingis used both for the initial team-member fetch (line 37) and the task creation call (line 99). When_createTasksets_isLoading = true, the entire form body is replaced by aCircularProgressIndicator(line 147–148), so the user loses their form state visually. TheUnifiedActionButton.isLoadingon line 261 is never visible because the form is already gone.Consider using a separate flag (e.g.,
_isSubmitting) for the creation call so the form stays visible with the button's built-in loading indicator.Proposed fix
Add a separate
_isSubmittingflag:bool _isLoading = false; + bool _isSubmitting = false;In
_createTask, use_isSubmittinginstead:Future<void> _createTask() async { if (!_formKey.currentState!.validate()) return; setState(() { - _isLoading = true; + _isSubmitting = true; }); // ... on error: setState(() { - _isLoading = false; + _isSubmitting = false; });And wire the button:
UnifiedActionButton( text: 'Create Task', onPressed: _createTask, - isLoading: _isLoading, + isLoading: _isSubmitting, ),Also applies to: 147-148
lib/screens/tickets/create_ticket_screen.dart (1)
72-77:⚠️ Potential issue | 🟠 MajorSame
_isLoadingdual-purpose issue ascreate_task_screen.dart.
_isLoadingstartstrue(line 22) for team member loading and is reused for ticket creation (line 76). During submission, the form is replaced by a spinner (line 130–131), hiding theUnifiedActionButton's loading state. Use a separate_isSubmittingflag as suggested in the task screen review.Also applies to: 130-131
🤖 Fix all issues with AI agents
In `@android/gradle/wrapper/gradle-wrapper.properties`:
- Around line 1-6: The gradle-wrapper.properties was unintentionally downgraded
and changed from `-all` to `-bin` and includes a local timestamp; revert the
distributionUrl to the original Gradle release with sources/docs (set
distributionUrl back to the gradle-8.14.2-all ZIP) and remove the local
timestamp comment line at the top, ensuring `distributionUrl` uses the -all
artifact (not -bin). Also add `gradle/wrapper/gradle-wrapper.properties` to
android/.gitignore so local wrapper changes (timestamps) aren't committed in
future; check and preserve `distributionBase`, `distributionPath`,
`zipStoreBase`, and `zipStorePath` as-is.
In `@lib/widgets/unified_form_components.dart`:
- Around line 260-266: The Text widget currently decides hint vs value color
using the fragile string check displayText.startsWith('Select'); instead add a
boolean parameter (e.g., bool hasValue) to the widget/class API and use that in
build instead of the string test: replace displayText.startsWith('Select') with
!hasValue (or hasValue inverted as appropriate) when choosing
UnifiedDesignTokens.textSecondary vs UnifiedDesignTokens.textPrimary, update the
widget constructor and any callers to pass hasValue (true when a real value is
present), and keep displayText solely for rendering.
In `@pubspec.yaml`:
- Line 22: The pubspec SDK constraint uses an speculative upper bound ("sdk:
\">=2.17.0 <=4.0.0\") which permits untested Dart 4; update the constraint to a
tested upper bound by replacing the upper operator and version—e.g., change the
upper bound to "<4.0.0" or to a concrete tested version like "<=3.10.9" so the
line becomes "sdk: \">=2.17.0 <4.0.0\"" or "sdk: \">=2.17.0 <=3.10.9\"" to
prevent allowing unreleased SDKs.
In `@README_UI_CHANGES.txt`:
- Around line 256-260: The README_UI_CHANGES.txt contains references to a local
AI-tool artifact directory ".gemini/antigravity/brain/" which likely doesn't
exist in the repo; update README_UI_CHANGES.txt by removing or replacing those
references with valid repository documentation paths or public links (e.g., a
docs/ directory, CONTRIBUTING.md, or a specific design doc), or add the
referenced artifacts into the repo if intentional so the paths resolve.
- Line 68: The README contains a hardcoded absolute path string
"/Users/shankie2k5/Ell-ena" (appearing in the "Open:
/Users/shankie2k5/Ell-ena/.env" line) which leaks a local username; replace that
absolute path with a relative/example or placeholder (e.g., "./.env" or
"<PROJECT_ROOT>/.env" or "path/to/project/.env") and update the instruction text
to say "Open the .env file in the project root" or similar so contributors use a
generic, non-user-specific path; ensure both occurrences of the
"/Users/shankie2k5/Ell-ena" string are changed.
🧹 Nitpick comments (5)
test/widget_test.dart (1)
5-10:pumpAndSettlemay hang ifMyAppperforms async initialization.If
MyApptriggers Supabase initialization or shows indefinite animations (e.g.,CircularProgressIndicator),pumpAndSettlewill time out. Consider usingpump()with a specific duration instead, or mocking the service layer for tests. Based on learnings, the team follows an MVP-first approach for testing, so this is fine to defer.lib/screens/tasks/create_task_screen.dart (1)
198-253: Assignee dropdown item rendering is duplicated across screens.The CircleAvatar + name + admin badge rendering here is nearly identical to the one in
create_ticket_screen.dart(lines 216–260). Given that this PR's goal is to eliminate duplication via unified components, consider extracting a sharedbuildMemberDropdownItemhelper intounified_form_components.dart.lib/screens/meetings/create_meeting_screen.dart (2)
156-166: Date/time picker dialogs still use hardcoded color values instead ofUnifiedDesignTokens.
_selectDate(lines 159–165) and_selectTime(lines 186–191) use hardcodedColor(0xFF2D2D2D)andColor(0xFF1A1A1A)instead ofUnifiedDesignTokens.surfaceColorandUnifiedDesignTokens.backgroundColor. The same issue exists increate_task_screen.dartlines 76–82. This undermines the goal of centralizing design tokens.Example fix for _selectDate
colorScheme: const ColorScheme.dark( primary: Colors.green, onPrimary: Colors.white, - surface: Color(0xFF2D2D2D), + surface: UnifiedDesignTokens.surfaceColor, onSurface: Colors.white, ), - dialogBackgroundColor: const Color(0xFF1A1A1A), + dialogBackgroundColor: UnifiedDesignTokens.backgroundColor,
263-263:displayText.startsWith('Select')check is fragile — seeUnifiedPickerFieldline 263.This is a note for the unified component (line 263 of
unified_form_components.dart), but it manifests here: the picker color logic relies ondisplayText.startsWith('Select')to determine hint vs. value styling. This breaks if the placeholder text is ever localized or reworded. Consider passing ahasValueboolean instead.lib/widgets/unified_form_components.dart (1)
64-80: The label + "(Optional)" pattern is repeated in three components.
UnifiedTextFormField,UnifiedDropdownField, andUnifiedPickerFieldall duplicate the same label Row with optional indicator. Consider extracting a_UnifiedLabelprivate widget to DRY this up.Example extraction
class _UnifiedLabel extends StatelessWidget { final String label; final bool isOptional; const _UnifiedLabel({required this.label, this.isOptional = false}); `@override` Widget build(BuildContext context) { return Row( children: [ Text(label, style: UnifiedDesignTokens.labelStyle), if (isOptional) ...[ const SizedBox(width: 4), Text( '(Optional)', style: TextStyle( color: UnifiedDesignTokens.textSecondary, fontSize: 14, fontWeight: FontWeight.normal, ), ), ], ], ); } }Also applies to: 139-156, 219-236
| #Sun Jan 25 16:10:18 IST 2026 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check git history for gradle-wrapper.properties to see the previous version
git log --all --oneline --format="%h %s" -- android/gradle/wrapper/gradle-wrapper.properties | head -20
# Get the diff between HEAD and previous commit for this file
echo "=== CURRENT VERSION ==="
cat android/gradle/wrapper/gradle-wrapper.properties
echo -e "\n=== GIT DIFF (if available) ==="
git show HEAD:android/gradle/wrapper/gradle-wrapper.properties 2>/dev/null || echo "No previous version in git"
# Check if gradle wrapper files are in .gitignore
echo -e "\n=== CHECKING .gitignore ==="
if [ -f "android/.gitignore" ]; then
echo "Content of android/.gitignore:"
cat -n android/.gitignore
fiRepository: AOSSIE-Org/Ell-ena
Length of output: 1153
🏁 Script executed:
#!/bin/bash
# Check what files changed in the current commit
echo "=== FILES CHANGED IN CURRENT COMMIT ==="
git diff --name-status HEAD~1 HEAD | grep -E "(gradle|wrapper)" || echo "No gradle/wrapper files in diff"
# Check full diff for gradle-wrapper.properties
echo -e "\n=== DETAILED DIFF FOR GRADLE-WRAPPER.PROPERTIES ==="
git diff HEAD~1 HEAD -- android/gradle/wrapper/gradle-wrapper.properties || echo "No diff found"
# Check if file is new in this commit
echo -e "\n=== CHECK IF FILE IS NEW ==="
git diff --diff-filter=A HEAD~1 HEAD -- android/gradle/wrapper/gradle-wrapper.properties && echo "File is NEW in this commit" || echo "File already existed"
# Show all files in android directory changed by this commit
echo -e "\n=== ALL FILES CHANGED IN THIS COMMIT ==="
git diff --name-only HEAD~1 HEADRepository: AOSSIE-Org/Ell-ena
Length of output: 744
🏁 Script executed:
#!/bin/bash
# Check current git status
echo "=== GIT STATUS ==="
git status
# Check current branch/commit
echo -e "\n=== CURRENT COMMIT ==="
git log --oneline -1
# Show all commits
echo -e "\n=== ALL COMMITS ==="
git log --oneline
# Try comparing with the second commit
echo -e "\n=== DIFF BETWEEN CURRENT (HEAD) AND SECOND COMMIT ==="
git diff fdf4d35 HEAD -- android/gradle/wrapper/gradle-wrapper.properties
# Check the initial commit for gradle-wrapper.properties
echo -e "\n=== GRADLE-WRAPPER.PROPERTIES IN INITIAL COMMIT ==="
git show 1ed3f21:android/gradle/wrapper/gradle-wrapper.properties 2>/dev/null || echo "File did not exist in initial commit"
# Check second commit
echo -e "\n=== GRADLE-WRAPPER.PROPERTIES IN SECOND COMMIT ==="
git show fdf4d35:android/gradle/wrapper/gradle-wrapper.properties 2>/dev/null || echo "File did not exist in second commit"Repository: AOSSIE-Org/Ell-ena
Length of output: 1768
Unintentional Gradle downgrade from 8.14.2 to 8.9 — revert this change.
This PR targets UI changes (unifying Create screens), but the gradle-wrapper.properties file downgrades Gradle from 8.14.2-all to 8.9-bin and adds a local environment timestamp (#Sun Jan 25 16:10:18 IST 2026). This change should be reverted to the previous version. Additionally, changing from -all to -bin distribution removes bundled sources/docs, which affects IDE tooling.
Per your team's preferences, Gradle wrapper files should not be version-controlled—add gradle/wrapper/gradle-wrapper.properties to android/.gitignore to prevent future local environment leaks.
🤖 Prompt for AI Agents
In `@android/gradle/wrapper/gradle-wrapper.properties` around lines 1 - 6, The
gradle-wrapper.properties was unintentionally downgraded and changed from `-all`
to `-bin` and includes a local timestamp; revert the distributionUrl to the
original Gradle release with sources/docs (set distributionUrl back to the
gradle-8.14.2-all ZIP) and remove the local timestamp comment line at the top,
ensuring `distributionUrl` uses the -all artifact (not -bin). Also add
`gradle/wrapper/gradle-wrapper.properties` to android/.gitignore so local
wrapper changes (timestamps) aren't committed in future; check and preserve
`distributionBase`, `distributionPath`, `zipStoreBase`, and `zipStorePath`
as-is.
| Text( | ||
| displayText, | ||
| style: TextStyle( | ||
| color: displayText.startsWith('Select') | ||
| ? UnifiedDesignTokens.textSecondary | ||
| : UnifiedDesignTokens.textPrimary, | ||
| ), |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
displayText.startsWith('Select') is a fragile heuristic for hint styling.
This string-based check determines whether to show hint or value color. It will break with localization or any placeholder that doesn't start with "Select". Pass a boolean (e.g., bool hasValue) from the caller instead.
Proposed fix
class UnifiedPickerField extends StatelessWidget {
final String label;
final String displayText;
final IconData icon;
final VoidCallback onTap;
final bool isOptional;
+ final bool hasValue;
const UnifiedPickerField({
super.key,
required this.label,
required this.displayText,
required this.icon,
required this.onTap,
this.isOptional = false,
+ this.hasValue = false,
});Then in build:
Text(
displayText,
style: TextStyle(
- color: displayText.startsWith('Select')
- ? UnifiedDesignTokens.textSecondary
- : UnifiedDesignTokens.textPrimary,
+ color: hasValue
+ ? UnifiedDesignTokens.textPrimary
+ : UnifiedDesignTokens.textSecondary,
),
),🤖 Prompt for AI Agents
In `@lib/widgets/unified_form_components.dart` around lines 260 - 266, The Text
widget currently decides hint vs value color using the fragile string check
displayText.startsWith('Select'); instead add a boolean parameter (e.g., bool
hasValue) to the widget/class API and use that in build instead of the string
test: replace displayText.startsWith('Select') with !hasValue (or hasValue
inverted as appropriate) when choosing UnifiedDesignTokens.textSecondary vs
UnifiedDesignTokens.textPrimary, update the widget constructor and any callers
to pass hasValue (true when a real value is present), and keep displayText
solely for rendering.
|
|
||
| environment: | ||
| sdk: ">=2.17.0 <=3.8.1" | ||
| sdk: ">=2.17.0 <=4.0.0" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
latest stable Dart SDK version February 2026
💡 Result:
As of February 10, 2026, the latest stable Dart SDK version is Dart 3.10.9 (stable release listed on Feb 3, 2026). [1][2]
SDK upper bound <=4.0.0 is speculative and untested.
Dart 4.0.0 does not exist; the latest stable version as of February 2026 is 3.10.9. Using <=4.0.0 allows untested, unreleased SDK versions. Tighten the upper bound to a version you've tested against, such as <4.0.0 or <=3.10.9.
🤖 Prompt for AI Agents
In `@pubspec.yaml` at line 22, The pubspec SDK constraint uses an speculative
upper bound ("sdk: \">=2.17.0 <=4.0.0\") which permits untested Dart 4; update
the constraint to a tested upper bound by replacing the upper operator and
version—e.g., change the upper bound to "<4.0.0" or to a concrete tested version
like "<=3.10.9" so the line becomes "sdk: \">=2.17.0 <4.0.0\"" or "sdk:
\">=2.17.0 <=3.10.9\"" to prevent allowing unreleased SDKs.
|
|
||
| ⚠️ CRITICAL: Fill in the .env file with your credentials | ||
|
|
||
| Open: /Users/shankie2k5/Ell-ena/.env |
There was a problem hiding this comment.
Remove hardcoded local paths.
Lines 68 and 87 contain the developer's machine-specific absolute path (/Users/shankie2k5/Ell-ena). These are meaningless for other contributors and leak the developer's username. Use relative paths or generic placeholders instead.
🤖 Prompt for AI Agents
In `@README_UI_CHANGES.txt` at line 68, The README contains a hardcoded absolute
path string "/Users/shankie2k5/Ell-ena" (appearing in the "Open:
/Users/shankie2k5/Ell-ena/.env" line) which leaks a local username; replace that
absolute path with a relative/example or placeholder (e.g., "./.env" or
"<PROJECT_ROOT>/.env" or "path/to/project/.env") and update the instruction text
to say "Open the .env file in the project root" or similar so contributors use a
generic, non-user-specific path; ensure both occurrences of the
"/Users/shankie2k5/Ell-ena" string are changed.
|
|
||
| Full Details: | ||
| - Implementation Plan: See artifacts in .gemini/antigravity/brain/ | ||
| - Walkthrough: See artifacts in .gemini/antigravity/brain/ | ||
| - This File: README_UI_CHANGES.txt |
There was a problem hiding this comment.
References to .gemini/antigravity/brain/ appear to be local AI tool artifacts.
These paths seem specific to a local AI assistant workspace and are unlikely to exist in the repository. Either remove these references or replace them with actual documentation paths.
🤖 Prompt for AI Agents
In `@README_UI_CHANGES.txt` around lines 256 - 260, The README_UI_CHANGES.txt
contains references to a local AI-tool artifact directory
".gemini/antigravity/brain/" which likely doesn't exist in the repo; update
README_UI_CHANGES.txt by removing or replacing those references with valid
repository documentation paths or public links (e.g., a docs/ directory,
CONTRIBUTING.md, or a specific design doc), or add the referenced artifacts into
the repo if intentional so the paths resolve.
Closes #
Ell-ena
UI Unification - Create Screens Implementation
Date: January 25, 2026
Status: ✅ COMPLETED
Overview
Successfully unified all "Create" screens (Task, Ticket, Meeting) with a consistent design system. All screens now share identical styling, spacing, and interaction patterns.
Result: Professional, polished UI that reduces cognitive load and improves user experience across the entire app.
What Was Changed
Files Created
✓ lib/widgets/unified_form_components.dart (364 lines)
UnifiedTextFormField,UnifiedDropdownField,UnifiedPickerFieldUnifiedActionButton,unifiedCreateAppBar✓ .env (environment variables template)
Files Modified
✓
lib/screens/tasks/create_task_screen.dart(-111 lines)✓
lib/screens/tickets/create_ticket_screen.dart(-110 lines)✓
lib/screens/meetings/create_meeting_screen.dart(-51 lines)Code Reduction: -272 lines of duplicated code eliminated
Key Improvements
Visual Consistency
✓ All AppBars now use dark color (
0xFF2D2D2D)✓ All fields use filled style with 12px border radius
✓ All labels are bold white text above fields
✓ All sections use 24px spacing
✓ All buttons are full-width green at bottom
User Experience
✓ Optional fields clearly marked with "(Optional)"
✓ Consistent button placement across all screens
✓ Predictable interaction patterns
✓ Professional, polished appearance
Developer Experience
✓ Reusable components reduce future code duplication
✓ Centralized design tokens make updates easier
✓ Consistent patterns simplify maintenance
Before You Run the App
Caution
CRITICAL: Fill in the
.envfile with your credentialsOpen:
/Users/shankie2k5/Ell-ena/.envRequired Values (all marked with TODO in the file):
SUPABASE_URL=← Your Supabase project URLSUPABASE_ANON_KEY=← Your Supabase anon keyOAUTH_REDIRECT_URL=← Your OAuth redirect URLGEMINI_API_KEY=← Your Gemini AI API keyWhere to Get Credentials:
How to Run
Step 1: Fill in .env file (see above)
Step 2: Run these commands:
cd /Users/shankie2k5/Ell-ena flutter clean flutter pub get flutter runStep 3: Test the unified UI:
Verify all three screens have consistent styling!
What to Expect
Create Task Screen
✓ Dark AppBar (changed from green)
✓ Bold labels above fields
✓ "Description (Optional)"
✓ "Due Date (Optional)"
✓ "Assign To (Optional)"
✓ Full-width green button at bottom
Create Ticket Screen
✓ Dark AppBar (no check icon)
✓ Create button moved from AppBar to bottom
✓ Bold labels above fields
✓ Clean priority selector
✓ "Assign To (Optional)"
✓ Full-width green button at bottom
Create Meeting Screen
✓ Dark AppBar
✓ Filled fields (not outlined)
✓ Bold labels above fields
✓ "Description (Optional)"
✓ "Duration (Optional)"
✓ "Google Meet URL (Optional)"
✓ Full-width green button at bottom
Design System Reference
Colors
#1A1A1A#2D2D2DColors.green.shade700Spacing
Typography
Borders
Troubleshooting
❌ Error: "No file or variants found for asset: .env"
✅ Solution: Fill in the .env file (already created)
❌ Error: Build fails
✅ Solution: Run
flutter clean && flutter pub get❌ Error: "Supabase not initialized"
✅ Solution: Check
SUPABASE_URLandSUPABASE_ANON_KEYin .env❌ Error: Emulator not starting
✅ Solution:
Or connect physical device via USB
Using Unified Components in Future Code
Import the library:
Text Field
Dropdown
Date/Time Picker
Submit Button
AppBar
Commit Message (for version control)
Security Reminder
Warning
The
.envfile contains sensitive credentials!✓ DO add
.envto.gitignore✗ DO NOT commit
.envto git✗ DO NOT share
.envpubliclyCreate
.env.example(without real values) for team reference.Next Steps
flutter pub getflutter runThen start using the app! 🚀
Questions or Issues:
Made with ❤️
Summary by CodeRabbit
Release Notes
New Features
Improvements
Chores