This commit is contained in:
2026-03-21 01:30:29 +03:00
parent 902d5953a7
commit f73d6788a2
+129 -28
View File
@@ -47,8 +47,24 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
bool _editingPrimary = true; bool _editingPrimary = true;
Color _tempPrimary = CardColorService.defaultPrimary; Color _tempPrimary = CardColorService.defaultPrimary;
Color _tempSecondary = CardColorService.defaultSecondary; Color _tempSecondary = CardColorService.defaultSecondary;
HSVColor _tempPrimaryHSV = HSVColor.fromColor(CardColorService.defaultPrimary);
HSVColor _tempSecondaryHSV = HSVColor.fromColor(CardColorService.defaultSecondary);
double _cardBottomY = 300; double _cardBottomY = 300;
HSVColor get _currentHSV => _editingPrimary ? _tempPrimaryHSV : _tempSecondaryHSV;
void _onHSVChanged(HSVColor hsv) {
setState(() {
if (_editingPrimary) {
_tempPrimaryHSV = hsv;
_tempPrimary = hsv.toColor();
} else {
_tempSecondaryHSV = hsv;
_tempSecondary = hsv.toColor();
}
});
}
Border? _themeBorder(BuildContext context) { Border? _themeBorder(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark; final isDark = Theme.of(context).brightness == Brightness.dark;
return isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1); return isDark ? null : Border.all(color: const Color(0xFFDDDDEE), width: 1);
@@ -58,6 +74,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
final colors = ref.read(cardColorsProvider); final colors = ref.read(cardColorsProvider);
_tempPrimary = colors.primary; _tempPrimary = colors.primary;
_tempSecondary = colors.secondary; _tempSecondary = colors.secondary;
_tempPrimaryHSV = HSVColor.fromColor(colors.primary);
_tempSecondaryHSV = HSVColor.fromColor(colors.secondary);
// Calculate actual card bottom: status bar + appbar + top padding + card height // Calculate actual card bottom: status bar + appbar + top padding + card height
final statusBar = MediaQuery.of(context).padding.top; final statusBar = MediaQuery.of(context).padding.top;
@@ -261,6 +279,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
left: 20, left: 20,
right: 20, right: 20,
top: _cardBottomY + 16, top: _cardBottomY + 16,
bottom: MediaQuery.of(context).padding.bottom + 16,
child: GestureDetector( child: GestureDetector(
onTap: () {}, // prevent dismiss onTap: () {}, // prevent dismiss
child: _buildColorPanel(context), child: _buildColorPanel(context),
@@ -271,8 +290,17 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
} }
Widget _buildColorPanel(BuildContext context) { Widget _buildColorPanel(BuildContext context) {
return Container( final maxHeight = MediaQuery.of(context).size.height - _cardBottomY - 32 - MediaQuery.of(context).padding.bottom;
padding: const EdgeInsets.all(20), final isDark = Theme.of(context).brightness == Brightness.dark;
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxHeight,
),
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Container(
padding: const EdgeInsets.fromLTRB(20, 16, 20, 20),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
@@ -288,7 +316,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Toggle between primary/secondary // TOP ROW: tabs + close button
Row( Row(
children: [ children: [
_PanelTab( _PanelTab(
@@ -297,40 +325,102 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
color: _tempPrimary, color: _tempPrimary,
onTap: () => setState(() => _editingPrimary = true), onTap: () => setState(() => _editingPrimary = true),
), ),
const SizedBox(width: 12), const SizedBox(width: 10),
_PanelTab( _PanelTab(
label: 'Secondary', label: 'Secondary',
isSelected: !_editingPrimary, isSelected: !_editingPrimary,
color: _tempSecondary, color: _tempSecondary,
onTap: () => setState(() => _editingPrimary = false), onTap: () => setState(() => _editingPrimary = false),
), ),
const Spacer(),
// CLOSE BUTTON
GestureDetector(
onTap: () => setState(() => _editingCard = false),
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.08),
shape: BoxShape.circle,
),
child: Icon(
Icons.close_rounded,
size: 18,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
),
),
),
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// HSV Color Picker // 2D spectrum area — drag to pick saturation + value
SizedBox( ClipRRect(
height: 200, borderRadius: BorderRadius.circular(12),
child: ColorPicker( child: SizedBox(
pickerColor: _editingPrimary ? _tempPrimary : _tempSecondary, height: 180,
onColorChanged: (color) { width: double.infinity,
setState(() { child: ColorPickerArea(
if (_editingPrimary) { _currentHSV,
_tempPrimary = color; _onHSVChanged,
} else { PaletteType.hsvWithHue,
_tempSecondary = color;
}
});
},
colorPickerWidth: MediaQuery.of(context).size.width - 80,
pickerAreaHeightPercent: 0.7,
enableAlpha: false,
displayThumbColor: true,
labelTypes: const [],
pickerAreaBorderRadius: BorderRadius.circular(12),
), ),
), ),
),
const SizedBox(height: 12),
// Hue rainbow slider — drag to change hue
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: SizedBox(
height: 24,
child: ColorPickerSlider(
TrackType.hue,
_currentHSV,
_onHSVChanged,
displayThumbColor: true,
),
),
),
const SizedBox(height: 12),
// Color preview row
Row(
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: _tempPrimary,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? Colors.white24 : Colors.black12,
),
),
),
const SizedBox(width: 8),
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: _tempSecondary,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? Colors.white24 : Colors.black12,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
'#${(_editingPrimary ? _tempPrimary : _tempSecondary).value.toRadixString(16).substring(2).toUpperCase()}',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5),
fontFamily: 'monospace',
),
),
),
],
),
const SizedBox(height: 16), const SizedBox(height: 16),
// Confirm button // APPLY BUTTON
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
@@ -354,6 +444,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
), ),
], ],
), ),
),
),
); );
} }
} }
@@ -373,6 +465,12 @@ class _PanelTab extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final unselectedBorder = isDark ? Colors.white24 : const Color(0xFFCCCCDD);
final unselectedText = isDark
? Colors.white60
: Theme.of(context).colorScheme.onSurface.withOpacity(0.5);
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
child: AnimatedContainer( child: AnimatedContainer(
@@ -382,7 +480,7 @@ class _PanelTab extends StatelessWidget {
color: isSelected ? color.withOpacity(0.15) : Colors.transparent, color: isSelected ? color.withOpacity(0.15) : Colors.transparent,
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
border: Border.all( border: Border.all(
color: isSelected ? color : Colors.white24, color: isSelected ? color : unselectedBorder,
width: 1.5, width: 1.5,
), ),
), ),
@@ -395,7 +493,10 @@ class _PanelTab extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: color, color: color,
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.white30, width: 1), border: Border.all(
color: isDark ? Colors.white30 : Colors.black12,
width: 1,
),
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -404,7 +505,7 @@ class _PanelTab extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
color: isSelected ? color : Colors.white60, color: isSelected ? color : unselectedText,
), ),
), ),
], ],