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;
Color _tempPrimary = CardColorService.defaultPrimary;
Color _tempSecondary = CardColorService.defaultSecondary;
HSVColor _tempPrimaryHSV = HSVColor.fromColor(CardColorService.defaultPrimary);
HSVColor _tempSecondaryHSV = HSVColor.fromColor(CardColorService.defaultSecondary);
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) {
final isDark = Theme.of(context).brightness == Brightness.dark;
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);
_tempPrimary = colors.primary;
_tempSecondary = colors.secondary;
_tempPrimaryHSV = HSVColor.fromColor(colors.primary);
_tempSecondaryHSV = HSVColor.fromColor(colors.secondary);
// Calculate actual card bottom: status bar + appbar + top padding + card height
final statusBar = MediaQuery.of(context).padding.top;
@@ -261,6 +279,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
left: 20,
right: 20,
top: _cardBottomY + 16,
bottom: MediaQuery.of(context).padding.bottom + 16,
child: GestureDetector(
onTap: () {}, // prevent dismiss
child: _buildColorPanel(context),
@@ -271,8 +290,17 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
}
Widget _buildColorPanel(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20),
final maxHeight = MediaQuery.of(context).size.height - _cardBottomY - 32 - MediaQuery.of(context).padding.bottom;
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(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(20),
@@ -288,7 +316,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Toggle between primary/secondary
// TOP ROW: tabs + close button
Row(
children: [
_PanelTab(
@@ -297,40 +325,102 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
color: _tempPrimary,
onTap: () => setState(() => _editingPrimary = true),
),
const SizedBox(width: 12),
const SizedBox(width: 10),
_PanelTab(
label: 'Secondary',
isSelected: !_editingPrimary,
color: _tempSecondary,
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),
// HSV Color Picker
SizedBox(
height: 200,
child: ColorPicker(
pickerColor: _editingPrimary ? _tempPrimary : _tempSecondary,
onColorChanged: (color) {
setState(() {
if (_editingPrimary) {
_tempPrimary = color;
} else {
_tempSecondary = color;
}
});
},
colorPickerWidth: MediaQuery.of(context).size.width - 80,
pickerAreaHeightPercent: 0.7,
enableAlpha: false,
displayThumbColor: true,
labelTypes: const [],
pickerAreaBorderRadius: BorderRadius.circular(12),
// 2D spectrum area — drag to pick saturation + value
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: SizedBox(
height: 180,
width: double.infinity,
child: ColorPickerArea(
_currentHSV,
_onHSVChanged,
PaletteType.hsvWithHue,
),
),
),
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),
// Confirm button
// APPLY BUTTON
SizedBox(
width: double.infinity,
child: ElevatedButton(
@@ -354,6 +444,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
],
),
),
),
);
}
}
@@ -373,6 +465,12 @@ class _PanelTab extends StatelessWidget {
@override
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(
onTap: onTap,
child: AnimatedContainer(
@@ -382,7 +480,7 @@ class _PanelTab extends StatelessWidget {
color: isSelected ? color.withOpacity(0.15) : Colors.transparent,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: isSelected ? color : Colors.white24,
color: isSelected ? color : unselectedBorder,
width: 1.5,
),
),
@@ -395,7 +493,10 @@ class _PanelTab extends StatelessWidget {
decoration: BoxDecoration(
color: color,
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),
@@ -404,7 +505,7 @@ class _PanelTab extends StatelessWidget {
style: TextStyle(
fontSize: 13,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
color: isSelected ? color : Colors.white60,
color: isSelected ? color : unselectedText,
),
),
],