mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 18:35:28 +03:00
update
This commit is contained in:
@@ -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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user