Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,24 +113,20 @@ void _handleToolOptionsVisibility(WidgetRef ref) {
}

void _showColorPicker(BuildContext context, WidgetRef ref) {
showModalBottomSheet(
final Color initialColor = ref.read(paintProvider).color;

showDialog(
context: context,
isScrollControlled: true,
builder: (BuildContext dialogContext) => Container(
height: MediaQuery.of(dialogContext).size.height * 0.7,
alignment: Alignment.center,
decoration: BoxDecoration(
color: PaintroidTheme.of(dialogContext).onSurfaceColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
)),
child: ColorPicker(
currentColor: ref.watch(paintProvider).color,
onColorChanged: (newColor) {
ref.watch(paintProvider.notifier).updateColor(newColor);
},
),
),
builder: (BuildContext dialogContext) {
return Dialog(
clipBehavior: Clip.antiAlias,
child: ColorPicker(
currentColor: initialColor,
onColorChanged: (newColor) {
ref.read(paintProvider.notifier).updateColor(newColor);
},
),
);
},
);
}
1 change: 1 addition & 0 deletions packages/colorpicker/lib/colorpicker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export 'src/constants/colors.dart';
export 'src/components/color_comparison.dart';
export 'src/components/opacity_slider.dart';
export 'src/components/slider_indicator_shape.dart';
export 'src/components/color_wheel.dart';
233 changes: 173 additions & 60 deletions packages/colorpicker/lib/src/colorpicker.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import 'package:colorpicker/src/components/checkerboard_square.dart';
import 'package:flutter/material.dart';

import 'package:colorpicker/src/components/color_comparison.dart';
import 'package:colorpicker/src/components/color_square.dart';
import 'package:colorpicker/src/components/opacity_slider.dart';
import 'package:colorpicker/src/constants/colors.dart';
import 'package:colorpicker/src/components/recent_colors_section_widget.dart';
import 'package:colorpicker/src/components/custom_tab_widget.dart';
import 'package:colorpicker/src/components/picker_content_widget.dart';
import 'package:colorpicker/src/enums/main_picker_mode_type.dart';
import 'package:colorpicker/src/state/color_picker_state_provider.dart';
import 'package:flutter/material.dart';
import 'package:colorpicker/src/state/recent_color_state_provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:colorpicker/src/constants/colorpicker_colors.dart';

class ColorPicker extends ConsumerWidget {
class ColorPicker extends ConsumerStatefulWidget {
const ColorPicker({
super.key,
required this.currentColor,
Expand All @@ -17,77 +21,186 @@ class ColorPicker extends ConsumerWidget {
final Color currentColor;
final void Function(Color) onColorChanged;

final colors = DisplayColors.colors;
@override
ConsumerState<ColorPicker> createState() => _ColorPickerState();
}

class _ColorPickerState extends ConsumerState<ColorPicker>
with SingleTickerProviderStateMixin {
late TabController _tabController;
MainPickerMode _mainPickerMode = MainPickerMode.grid;

final double _selectedIndicatorHeight = 5.0;
final double _unselectedIndicatorHeight = 2.0;

@override
Widget build(BuildContext context, WidgetRef ref) {
final colorPickerStateData = ref.watch(colorPickerStateProvider);
return Container(
margin: const EdgeInsets.all(26.0),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
),
child: SingleChildScrollView(
void initState() {
super.initState();
_tabController = TabController(
length: 3,
vsync: this,
initialIndex: MainPickerMode.values.indexOf(_mainPickerMode));
_tabController.addListener(_handleTabChange);

WidgetsBinding.instance.addPostFrameCallback((_) {
ref
.read(colorPickerStateProvider.notifier)
.updateColor(widget.currentColor.withAlpha(255));
ref
.read(colorPickerStateProvider.notifier)
.updateOpacity(widget.currentColor.a);
});
}

@override
void dispose() {
_tabController.removeListener(_handleTabChange);
_tabController.dispose();
super.dispose();
}

void _handleTabChange() {
if (mounted &&
_mainPickerMode != MainPickerMode.values[_tabController.index]) {
setState(() {
_mainPickerMode = MainPickerMode.values[_tabController.index];
});
}
}

void _handleColorChange(Color color) {
ref
.read(colorPickerStateProvider.notifier)
.updateColor(color.withAlpha(255));
}

void _handleColorAndOpacityChange(Color color) {
ref
.read(colorPickerStateProvider.notifier)
.updateColor(color.withAlpha(255));
ref.read(colorPickerStateProvider.notifier).updateOpacity(color.a);
}

@override
Widget build(BuildContext context) {
final colorPickerState = ref.watch(colorPickerStateProvider);
final opacity = colorPickerState.currentOpacity;
final baseColor = colorPickerState.currentColor ?? widget.currentColor;
final displayColor =
baseColor.withAlpha((opacity.clamp(0.0, 1.0) * 255).round());

final solidColorForPickers =
(colorPickerState.currentColor ?? widget.currentColor.withAlpha(255))
.withAlpha(255);

final theme = Theme.of(context);
final colorScheme = theme.colorScheme;

return Material(
color: Colors.transparent,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: theme.cardColor,
borderRadius: BorderRadius.circular(16.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
ColorComparison(
currentColor: currentColor,
newColor: colorPickerStateData.currentColor != null
? colorPickerStateData.currentColor!.withValues(
alpha: colorPickerStateData.currentOpacity,
)
: currentColor,
),
const SizedBox(height: 10.0),
GridView.count(
childAspectRatio: 1.4,
crossAxisCount: 4,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
shrinkWrap: true,
children: List.generate(
colors.length + 1,
(index) {
if (index == colors.length) {
return const CheckerboardSquare();
} else {
return ColorSquare(color: colors[index]);
}
},
Flexible(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ColorComparison(
currentColor: widget.currentColor,
newColor: displayColor,
),
RecentColorsSectionWidget(
onColorSelected: _handleColorAndOpacityChange),
const SizedBox(height: 20.0),
SizedBox(
height: 48,
child: TabBar(
controller: _tabController,
labelColor: colorScheme.primary,
dividerHeight: 0,
unselectedLabelColor: colorScheme.onSurface
.withAlpha((255 * 0.7).toInt()),
indicator: const BoxDecoration(),
tabs: <Widget>[
CustomTabWidget(
iconWidget: const Icon(Icons.grid_on),
index: 0,
tabController: _tabController,
selectedIndicatorHeight: _selectedIndicatorHeight,
unselectedIndicatorHeight:
_unselectedIndicatorHeight,
),
CustomTabWidget(
iconWidget: const Icon(Icons.circle),
index: 1,
tabController: _tabController,
selectedIndicatorHeight: _selectedIndicatorHeight,
unselectedIndicatorHeight:
_unselectedIndicatorHeight,
),
CustomTabWidget(
iconWidget: const Icon(Icons.tune),
index: 2,
tabController: _tabController,
selectedIndicatorHeight: _selectedIndicatorHeight,
unselectedIndicatorHeight:
_unselectedIndicatorHeight,
),
],
),
),
const SizedBox(height: 15.0),
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: PickerContentWidget(
mainPickerMode: _mainPickerMode,
colorForPickers: solidColorForPickers,
onColorChanged: _handleColorChange,
onColorAndOpacityChanged: _handleColorAndOpacityChange,
),
),
if (_mainPickerMode != MainPickerMode.sliders) ...[
const SizedBox(height: 20.0),
OpacitySlider(gradientColor: solidColorForPickers),
],
const SizedBox(height: 20.0),
],
),
),
),
const SizedBox(height: 20.0),
OpacitySlider(
gradientColor: colorPickerStateData.currentColor != null
? colorPickerStateData.currentColor!
: currentColor,
),
const SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const Spacer(),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('CANCEL'),
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL',
style: TextStyle(
color: ColorPickerColors.oceanBlue,
fontWeight: FontWeight.w500)),
),
const SizedBox(width: 10.0),
const SizedBox(width: 15.0),
TextButton(
onPressed: () {
if (colorPickerStateData.currentColor != null) {
onColorChanged(colorPickerStateData.currentColor!
.withValues(
alpha: colorPickerStateData.currentOpacity));
}
ref
.read(recentColorsProvider.notifier)
.addColor(displayColor);
widget.onColorChanged(displayColor);
Navigator.pop(context);
},
child: const Text('APPLY'),
child: const Text('APPLY',
style: TextStyle(
color: ColorPickerColors.oceanBlue,
fontWeight: FontWeight.w500)),
),
],
)
),
],
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'package:colorpicker/src/components/color_wheel.dart';
import 'package:colorpicker/src/components/hue_saturation_picker.dart';
import 'package:colorpicker/src/components/toggle_item_widget.dart';
import 'package:colorpicker/src/constants/colorpicker_colors.dart';
import 'package:colorpicker/src/enums/advanced_picker_mode_type.dart';
import 'package:flutter/material.dart';

class AdvancedPickerWidget extends StatefulWidget {
final Color colorForPickers;
final void Function(Color) onColorChanged;
final String text1;
final String text2;

const AdvancedPickerWidget({
super.key,
required this.colorForPickers,
required this.onColorChanged,
required this.text1,
required this.text2,
});

@override
State<AdvancedPickerWidget> createState() =>
_AdvancedPickerWidgetState();
}

class _AdvancedPickerWidgetState extends State<AdvancedPickerWidget> {
AdvancedPickerMode _advancedPickerMode = AdvancedPickerMode.picker;

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;

return Column(
key: const ValueKey('advanced_picker'),
mainAxisSize: MainAxisSize.min,
children: [
ToggleButtons(
isSelected: [
_advancedPickerMode == AdvancedPickerMode.picker,
_advancedPickerMode == AdvancedPickerMode.wheel,
],
onPressed: (int index) {
setState(() {
_advancedPickerMode = index == 0
? AdvancedPickerMode.picker
: AdvancedPickerMode.wheel;
});
},
borderRadius: BorderRadius.circular(18.0),
borderWidth: 1.5,
borderColor: colorScheme.primary,
selectedBorderColor: colorScheme.primary,
fillColor: colorScheme.surface,
color: ColorPickerColors.orange,
constraints: const BoxConstraints(minHeight: 30.0, minWidth: 70.0),
children: <Widget>[
ToggleItemWidget(
text: widget.text1,
currentMode: _advancedPickerMode,
buttonMode: AdvancedPickerMode.picker),
ToggleItemWidget(
text: widget.text2,
currentMode: _advancedPickerMode,
buttonMode: AdvancedPickerMode.wheel),
],
),
const SizedBox(height: 20),
SizedBox(
height: 220.0,
child: Center(
child: _advancedPickerMode == AdvancedPickerMode.picker
? HueSaturationValuePicker(
initialColor: widget.colorForPickers,
onColorChanged: widget.onColorChanged)
: ColorWheel(
pickerColor: widget.colorForPickers,
onColorChanged: widget.onColorChanged),
),
),
],
);
}
}
Loading