fix(color-picking): Fix color picking failure and card overflow#998
fix(color-picking): Fix color picking failure and card overflow#998lollipopkit merged 6 commits intolollipopkit:mainfrom
Conversation
And uniformly set the scrolledUnderElevation of the AppBar to 0 to optimize visual effects
… updates Add initial value display for the color seed input box on the settings page Modify the color saving logic to notify the application of theme updates Retrieve the system's primary color setting upon application startup Optimize the theme color synchronization logic
Adjust the card height constant value from 108.0 to 110.0
WalkthroughDynamic color handling and settings for the app color seed were updated: ThemeData now uses Changes
Sequence Diagram(s)sequenceDiagram
participant App
participant Stores as Stores.setting
participant ThemeBuilder as _buildDynamicColor/_build
participant UIState as UIs
participant SettingsUI as AppSettings
App->>Stores: read useSystemPrimaryColor
alt system primary enabled
App->>ThemeBuilder: _buildDynamicColor()
ThemeBuilder->>Stores: fetch system light/dark seed (dynamic_color)
ThemeBuilder->>ThemeBuilder: build ThemeData with colorSchemeSeed + appBarTheme(scrolledUnderElevation=0.0)
ThemeBuilder->>UIState: set primaryColor & colorSeed
else system primary disabled
App->>ThemeBuilder: _build()
ThemeBuilder->>Stores: fetch stored colorSeed
ThemeBuilder->>UIState: set primaryColor & colorSeed
end
SettingsUI->>Stores: open color editor (pre-filled)
SettingsUI->>SettingsUI: pick/validate hex → save to Stores
SettingsUI->>UIState: update primaryColor & colorSeed (if not following system)
UIState->>App: apply updated theme
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
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: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/app.dart (1)
65-93: Potential color inconsistency when dynamic colors are unavailable.If both
lightanddarkarenull(on platforms that don't support dynamic colors), the theme will use Flutter's default color scheme, butUIs.primaryColorandUIs.colorSeedwon't be updated. This could cause inconsistency between the applied theme and UI elements that directly referenceUIs.primaryColor.Consider adding a fallback to update
UIsvalues when dynamic colors are unavailable:🔧 Suggested fix
if (context.isDark && dark != null) { UIs.primaryColor = dark.primary; UIs.colorSeed = dark.primary; } else if (!context.isDark && light != null) { UIs.primaryColor = light.primary; UIs.colorSeed = light.primary; + } else { + // Fallback when dynamic colors unavailable + final fallback = Color(Stores.setting.colorSeed.fetch()); + UIs.primaryColor = fallback; + UIs.colorSeed = fallback; }
🧹 Nitpick comments (2)
lib/app.dart (1)
28-29: Unused fetch result appears to be dead code.The
fetch()call on line 29 is executed but its return value is discarded. If this is intended for cache warming, consider adding a comment. Otherwise, this line can be removed sincefetch()is called again inside theListenableBuilderon line 34.🔧 Suggested fix
_setup(context); - - Stores.setting.useSystemPrimaryColor.fetch(); return ListenableBuilder(lib/view/page/setting/entries/app.dart (1)
131-144: Consider also updatingUIs.primaryColorfor consistency.The
_onSaveColormethod updatesUIs.colorSeedbut notUIs.primaryColor. Inlib/app.dart, both values are updated together. While the subsequentRNodes.app.notify()will trigger a rebuild that updates both, there's a brief window where these values could be inconsistent.🔧 Suggested fix
void _onSaveColor(String s) { final color = s.fromColorHex; if (color == null) { context.showSnackBar(libL10n.fail); return; } UIs.colorSeed = color; + UIs.primaryColor = color; _setting.colorSeed.put(color.value255); RNodes.app.notify(); context.pop(); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
lib/app.dartlib/view/page/server/tab/tab.dartlib/view/page/setting/entries/app.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/view/**/*.dart
📄 CodeRabbit inference engine (CLAUDE.md)
lib/view/**/*.dart: Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Prefer using libL10n strings before adding new ones to project l10n
Split UI into build, actions, and utils; use extension on to separate concerns
Files:
lib/view/page/server/tab/tab.dartlib/view/page/setting/entries/app.dart
🔇 Additional comments (3)
lib/view/page/server/tab/tab.dart (1)
347-350: LGTM!The card height adjustment from 108.0 to 110.0 resolves the 2-pixel overflow issue as described in the PR objectives.
lib/app.dart (1)
43-63: LGTM!The static color theme implementation correctly reads the color seed from settings, updates the
UIssingleton, and constructs consistent light/dark themes with theappBarThemeadjustment.lib/view/page/setting/entries/app.dart (1)
88-129: LGTM!The color picker implementation follows fl_lib patterns and correctly:
- Pre-fills the text field with the current color seed hex value
- Conditionally shows the color picker based on
useSystemPrimaryColorsetting- Handles iOS platform limitation for the
dynamic_colorplugin
@coderabbitai Noticed this. This might impact systems without dynamic color or light/dark switch (Android 9-, Windows, etc.) I think, but I don't know if it really matters. But it won't cause any bugs. Investigating. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@GT-610: I can help with the investigation! Let me examine how 🏁 Script executed: Length of output: 6895 Based on the investigation, here's what I found: Key FindingsThe concern is valid. Here's the issue:
ImpactOn platforms like Android 9-, Windows, etc., if users toggle the "Use System Primary Color" setting:
The suggested fallback in the review comment would fix this inconsistency. Would you like to implement it? |
Add the dynamic_color dependency to support dynamic theme colors When the system does not support dynamic colors, use the stored default color as a fallback Optimize the display logic of dynamic color options in the settings page
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/view/page/setting/entries/app.dart (1)
97-127: Fix blank dialog edge case whenuseSystemPrimaryColoris true but system colors aren't available (or on iOS).The ColorPicker visibility depends only on
_setting.useSystemPrimaryColor.fetch()(line 118). When that flag is true on iOS (where the switch is never shown due toif (!isIOS)) or on platforms where dynamic colors are unsupported (lightanddarkare null, so the switch showsSizedBox.shrink()), the dialog content becomes empty—no way to change the color.The proposed fix moves
DynamicColorBuilderto the top level and gates the ColorPicker by!followSystemEnabledinstead of just the stored flag. This ensures the ColorPicker always appears when system color following is unavailable, preventing the blank dialog.Proposed adjustment (gate by "supported AND enabled", not just the stored flag)
- child: StatefulBuilder( - builder: (context, setState) { - final children = <Widget>[ - if (!isIOS) - DynamicColorBuilder( - builder: (light, dark) { - final supported = light != null || dark != null; - if (!supported) return const SizedBox.shrink(); - return ListTile( - title: Text(l10n.followSystem), - trailing: StoreSwitch( - prop: _setting.useSystemPrimaryColor, - callback: (_) => setState(() {}), - ), - ); - }, - ), - ]; - if (!_setting.useSystemPrimaryColor.fetch()) { - children.add( - ColorPicker( - color: Color(_setting.colorSeed.fetch()), - onColorChanged: (c) => ctrl.text = c.toHex, - ), - ); - } - return Column(mainAxisSize: MainAxisSize.min, children: children); - }, - ), + child: StatefulBuilder( + builder: (context, setState) => DynamicColorBuilder( + builder: (light, dark) { + final supported = light != null || dark != null; + final followSystemEnabled = + !isIOS && supported && _setting.useSystemPrimaryColor.fetch(); + + final children = <Widget>[ + if (!isIOS && supported) + ListTile( + title: Text(l10n.followSystem), + trailing: StoreSwitch( + prop: _setting.useSystemPrimaryColor, + callback: (_) => setState(() {}), + ), + ), + if (!followSystemEnabled) + ColorPicker( + color: Color(_setting.colorSeed.fetch()), + onColorChanged: (c) => ctrl.text = c.toHex, + ), + ]; + + return Column(mainAxisSize: MainAxisSize.min, children: children); + }, + ), + ),
🤖 Fix all issues with AI agents
In @lib/view/page/setting/entries/app.dart:
- Around line 136-149: _inSaveColor currently updates UIs.colorSeed and persists
the value via _setting.colorSeed.put but leaves UIs.primaryColor unchanged,
causing a transient desync; update the method to also set UIs.primaryColor =
color (before calling RNodes.app.notify) so UI reads the new primary color
immediately, and ensure you still persist via _setting.colorSeed.put and then
call RNodes.app.notify() and context.pop() as before.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
lib/app.dartlib/view/page/setting/entries/app.dartlib/view/page/setting/entry.dart
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/app.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/view/**/*.dart
📄 CodeRabbit inference engine (CLAUDE.md)
lib/view/**/*.dart: Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Prefer using libL10n strings before adding new ones to project l10n
Split UI into build, actions, and utils; use extension on to separate concerns
Files:
lib/view/page/setting/entry.dartlib/view/page/setting/entries/app.dart
🧠 Learnings (2)
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/view/**/*.dart : Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Applied to files:
lib/view/page/setting/entry.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/view/**/*.dart : Split UI into build, actions, and utils; use extension on to separate concerns
Applied to files:
lib/view/page/setting/entry.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: check
🔇 Additional comments (2)
lib/view/page/setting/entry.dart (2)
31-34: Part reorder looks safe; just ensure no top-level side effects depend on part order.
4-4: No action needed. Thedynamic_colorv1.6.6 API is correctly used. TheDynamicColorBuildersignature (builder receives nullableColorScheme?for light/dark) matches the documented API, and the codebase already properly handles the null values on unsupported platforms (e.g., desktop, older Android) with explicit checks and fallbacks inentries/app.dart. The library-level import is appropriate for the part-based file structure.
…n updating the application theme color When modifying the application theme color, in addition to updating the colorSeed, the primaryColor is now also set synchronously to maintain UI consistency
I added a logic that directly hide "Follow system" feature when the device does not support this feature. This screenshot is taken from Android 9, which does not have dynamic color support. @coderabbitai Please review. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 17941 @GT-610, excellent work! 🎉 Your implementation looks great. Let me break down what I found: ✅ All Major Concerns Addressed1. Dynamic Color UI Hiding (lib/view/page/setting/entries/app.dart, lines 103-120)Perfect implementation! The final supported = light != null || dark != null;
if (!supported) return const SizedBox.shrink();2. Fallback Logic (lib/app.dart, lines 91-95)You've added exactly the fallback I suggested! When dynamic colors are unavailable, it now properly updates } else {
final fallbackColor = Color(Stores.setting.colorSeed.fetch());
UIs.primaryColor = fallbackColor;
UIs.colorSeed = fallbackColor;
}This ensures consistency across the app even on platforms without dynamic color support. 3. Color Consistency (lib/view/page/setting/entries/app.dart, lines 137-138)The UIs.primaryColor = color;
UIs.colorSeed = color;🧹 Minor Remaining NitpickLine 29 in lib/app.dart still has an unused Stores.setting.useSystemPrimaryColor.fetch();The return value is discarded, and SummaryYour changes comprehensively address the color inconsistency concerns on platforms without dynamic color support (Android 9-, Windows, etc.). The implementation is clean, defensive, and user-friendly. Great job! 👍 |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 17982 @GT-610: Excellent work! 🎉 Your implementation properly addresses the main concern: ✅ Issues Resolved
🧹 One minor nitpick remainsLine 29 in Stores.setting.useSystemPrimaryColor.fetch();The return value is discarded, and it's called again inside the The core functionality is now solid! The combination of hiding the UI option and providing a proper fallback ensures correct behavior across all platforms. 👍 |
|
Unused call problem is being fixed. |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/view/page/setting/entries/app.dart (1)
100-130: Handle "Follow System" edge-cases: (1) unsupported dynamic colors, (2) OK overwriting manual seed while system mode is on.Both issues are real:
Unsupported platforms: If dynamic colors are unsupported (
DynamicColorBuilderreturns null for both light/dark) anduseSystemPrimaryColoris already enabled, the dialog renders neither the switch nor the color picker. User is trapped with no way to change settings.Seed overwrite on system mode: When the user enables "Follow System" and taps OK,
_onSaveColor(ctrl.text)runs unconditionally, overwritingUIs.primaryColor/UIs.colorSeedwith the manual seed value—defeating the purpose of system color mode (lib/app.dart checksuseSystemPrimaryColorto decide which colors to apply).Proposed minimal fix (keep current structure)
@@ DynamicColorBuilder( builder: (light, dark) { final supported = light != null || dark != null; - if (!supported) return const SizedBox.shrink(); + if (!supported) { + // If the platform can't provide dynamic colors, ensure the UI doesn't get stuck + // with "Follow System" enabled (which would also hide the manual picker). + if (_setting.useSystemPrimaryColor.fetch()) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _setting.useSystemPrimaryColor.put(false); + setState(() {}); + }); + } + return const SizedBox.shrink(); + } return ListTile( title: Text(l10n.followSystem), trailing: StoreSwitch( prop: _setting.useSystemPrimaryColor, callback: (_) => setState(() {}), ), ); }, ), @@ - actions: Btn.ok(onTap: () => _onSaveColor(ctrl.text)).toList, + actions: Btn.ok( + onTap: () { + // If following system, don't overwrite the manual seed / UIs.* here. + if (_setting.useSystemPrimaryColor.fetch()) { + RNodes.app.notify(); + context.pop(); + return; + } + _onSaveColor(ctrl.text); + }, + ).toList, );
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
lib/view/page/setting/entries/app.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/view/**/*.dart
📄 CodeRabbit inference engine (CLAUDE.md)
lib/view/**/*.dart: Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Prefer using libL10n strings before adding new ones to project l10n
Split UI into build, actions, and utils; use extension on to separate concerns
Files:
lib/view/page/setting/entries/app.dart
🧠 Learnings (1)
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/view/**/*.dart : Prefer widgets/utilities from fl_lib for common UI (e.g., CustomAppBar, context.showRoundDialog, Input, Btnx.cancelOk)
Applied to files:
lib/view/page/setting/entries/app.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: check
🔇 Additional comments (2)
lib/view/page/setting/entries/app.dart (2)
96-99: Prefill seed editor is a good UX improvement.
Pre-fillingctrl.textfrom the persisted seed avoids accidental “empty save” and makes the edit flow clearer.
136-150: Immediate apply looks correct (primaryColor + colorSeed + notify).
SettingUIs.primaryColoralongsideUIs.colorSeed, persisting, thenRNodes.app.notify()should eliminate the “saved but not applied” behavior.One thing to confirm:
color.value255is the intended persisted format (alpha clamping/normalization).
…me colors Ensure that the UI color is updated correctly when the system theme color is disabled, and maintain consistent settings when dynamic colors are not supported

Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.