Created
July 19, 2024 15:42
-
-
Save fredgrott/3682b18e37235bc082730a4d2dc20b27 to your computer and use it in GitHub Desktop.
color palettes screen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2024 Fredrick Allan Grott. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
// | |
// Modified from the Flutter Samples Material Demo | |
// Copyright 2021 under BSD license by Flutter Team | |
// ignore_for_file: avoid_redundant_argument_values | |
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:url_launcher/url_launcher.dart'; | |
const Widget divider = SizedBox(height: 10); | |
// If screen content width is greater or equal to this value, the light and dark | |
// color schemes will be displayed in a column. Otherwise, they will | |
// be displayed in a row. | |
const double narrowScreenWidthThreshold = 400; | |
// ScrollAdapter always requires animating the individual items in a list | |
class ColorPalettesScreen extends StatelessWidget { | |
const ColorPalettesScreen({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
final Color selectedColor = Theme.of(context).primaryColor; | |
final ThemeData lightTheme = ThemeData( | |
colorSchemeSeed: selectedColor, | |
brightness: Brightness.light, | |
); | |
final ThemeData darkTheme = ThemeData( | |
colorSchemeSeed: selectedColor, | |
brightness: Brightness.dark, | |
); | |
Widget schemeLabel(String brightness) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(vertical: 15), | |
child: Text( | |
brightness, | |
style: const TextStyle(fontWeight: FontWeight.bold), | |
), | |
); | |
} | |
Widget schemeView(ThemeData theme) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 15), | |
child: ColorSchemeView( | |
colorScheme: theme.colorScheme, | |
), | |
); | |
} | |
Widget dynamicColorNotice() => RichText( | |
textAlign: TextAlign.center, | |
text: TextSpan( | |
style: Theme.of(context).textTheme.bodySmall, | |
children: [ | |
const TextSpan( | |
text: 'To create color schemes based on a ' | |
"platform's implementation of dynamic color, " | |
'use the ', | |
), | |
TextSpan( | |
text: 'dynamic_color', | |
style: const TextStyle(decoration: TextDecoration.underline), | |
recognizer: TapGestureRecognizer() | |
..onTap = () async { | |
final url = Uri.parse( | |
'https://pub.dev/packages/dynamic_color', | |
); | |
if (!await launchUrl(url)) { | |
throw Exception('Could not launch $url'); | |
} | |
}, | |
), | |
const TextSpan(text: ' package.'), | |
], | |
), | |
); | |
final colorScrollController = ScrollController(); | |
return Expanded( | |
child: LayoutBuilder( | |
builder: (context, constraints) { | |
if (constraints.maxWidth < narrowScreenWidthThreshold) { | |
return SingleChildScrollView( | |
key: const PageStorageKey("colorOne"), | |
restorationId: "one", | |
controller: colorScrollController, | |
child: Column( | |
children: [ | |
dynamicColorNotice(), | |
divider, | |
schemeLabel('Light ColorScheme'), | |
schemeView(lightTheme), | |
divider, | |
divider, | |
schemeLabel('Dark ColorScheme'), | |
schemeView(darkTheme), | |
], | |
), | |
); | |
} else { | |
return SingleChildScrollView( | |
key: const PageStorageKey("colorTwo"), | |
restorationId: "two", | |
controller: colorScrollController, | |
child: Padding( | |
padding: const EdgeInsets.only(top: 5), | |
child: Column( | |
children: [ | |
dynamicColorNotice(), | |
Row( | |
children: [ | |
Expanded( | |
child: Column( | |
children: [ | |
schemeLabel('Light ColorScheme'), | |
schemeView(lightTheme), | |
], | |
), | |
), | |
Expanded( | |
child: Column( | |
children: [ | |
schemeLabel('Dark ColorScheme'), | |
schemeView(darkTheme), | |
], | |
), | |
), | |
], | |
), | |
], | |
), | |
), | |
); | |
} | |
}, | |
), | |
); | |
} | |
} | |
class ColorSchemeView extends StatelessWidget { | |
const ColorSchemeView({super.key, required this.colorScheme}); | |
final ColorScheme colorScheme; | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
children: <Widget>[ | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'primary', | |
color: colorScheme.primary, | |
onColor: colorScheme.onPrimary, | |
), | |
ColorChip( | |
label: 'onPrimary', | |
color: colorScheme.onPrimary, | |
onColor: colorScheme.primary, | |
), | |
ColorChip( | |
label: 'primaryContainer', | |
color: colorScheme.primaryContainer, | |
onColor: colorScheme.onPrimaryContainer, | |
), | |
ColorChip( | |
label: 'onPrimaryContainer', | |
color: colorScheme.onPrimaryContainer, | |
onColor: colorScheme.primaryContainer, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'primaryFixed', | |
color: colorScheme.primaryFixed, | |
onColor: colorScheme.onPrimaryFixed, | |
), | |
ColorChip( | |
label: 'onPrimaryFixed', | |
color: colorScheme.onPrimaryFixed, | |
onColor: colorScheme.primaryFixed, | |
), | |
ColorChip( | |
label: 'primaryFixedDim', | |
color: colorScheme.primaryFixedDim, | |
onColor: colorScheme.onPrimaryFixedVariant, | |
), | |
ColorChip( | |
label: 'onPrimaryFixedVariant', | |
color: colorScheme.onPrimaryFixedVariant, | |
onColor: colorScheme.primaryFixedDim, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'secondary', | |
color: colorScheme.secondary, | |
onColor: colorScheme.onSecondary, | |
), | |
ColorChip( | |
label: 'onSecondary', | |
color: colorScheme.onSecondary, | |
onColor: colorScheme.secondary, | |
), | |
ColorChip( | |
label: 'secondaryContainer', | |
color: colorScheme.secondaryContainer, | |
onColor: colorScheme.onSecondaryContainer, | |
), | |
ColorChip( | |
label: 'onSecondaryContainer', | |
color: colorScheme.onSecondaryContainer, | |
onColor: colorScheme.secondaryContainer, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'secondaryFixed', | |
color: colorScheme.secondaryFixed, | |
onColor: colorScheme.onSecondaryFixed, | |
), | |
ColorChip( | |
label: 'onSecondaryFixed', | |
color: colorScheme.onSecondaryFixed, | |
onColor: colorScheme.secondaryFixed, | |
), | |
ColorChip( | |
label: 'secondaryFixedDim', | |
color: colorScheme.secondaryFixedDim, | |
onColor: colorScheme.onSecondaryFixedVariant, | |
), | |
ColorChip( | |
label: 'onSecondaryFixedVariant', | |
color: colorScheme.onSecondaryFixedVariant, | |
onColor: colorScheme.secondaryFixedDim, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'tertiary', | |
color: colorScheme.tertiary, | |
onColor: colorScheme.onTertiary, | |
), | |
ColorChip( | |
label: 'onTertiary', | |
color: colorScheme.onTertiary, | |
onColor: colorScheme.tertiary, | |
), | |
ColorChip( | |
label: 'tertiaryContainer', | |
color: colorScheme.tertiaryContainer, | |
onColor: colorScheme.onTertiaryContainer, | |
), | |
ColorChip( | |
label: 'onTertiaryContainer', | |
color: colorScheme.onTertiaryContainer, | |
onColor: colorScheme.tertiaryContainer, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'tertiaryFixed', | |
color: colorScheme.tertiaryFixed, | |
onColor: colorScheme.onTertiaryFixed, | |
), | |
ColorChip( | |
label: 'onTertiaryFixed', | |
color: colorScheme.onTertiaryFixed, | |
onColor: colorScheme.tertiaryFixed, | |
), | |
ColorChip( | |
label: 'tertiaryFixedDim', | |
color: colorScheme.tertiaryFixedDim, | |
onColor: colorScheme.onTertiaryFixedVariant, | |
), | |
ColorChip( | |
label: 'onTertiaryFixedVariant', | |
color: colorScheme.onTertiaryFixedVariant, | |
onColor: colorScheme.tertiaryFixedDim, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'error', | |
color: colorScheme.error, | |
onColor: colorScheme.onError, | |
), | |
ColorChip( | |
label: 'onError', | |
color: colorScheme.onError, | |
onColor: colorScheme.error, | |
), | |
ColorChip( | |
label: 'errorContainer', | |
color: colorScheme.errorContainer, | |
onColor: colorScheme.onErrorContainer, | |
), | |
ColorChip( | |
label: 'onErrorContainer', | |
color: colorScheme.onErrorContainer, | |
onColor: colorScheme.errorContainer, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'surfaceDim', | |
color: colorScheme.surfaceDim, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surface', | |
color: colorScheme.surface, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceBright', | |
color: colorScheme.surfaceBright, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceContainerLowest', | |
color: colorScheme.surfaceContainerLowest, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceContainerLow', | |
color: colorScheme.surfaceContainerLow, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceContainer', | |
color: colorScheme.surfaceContainer, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceContainerHigh', | |
color: colorScheme.surfaceContainerHigh, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'surfaceContainerHighest', | |
color: colorScheme.surfaceContainerHighest, | |
onColor: colorScheme.onSurface, | |
), | |
ColorChip( | |
label: 'onSurface', | |
color: colorScheme.onSurface, | |
onColor: colorScheme.surface, | |
), | |
ColorChip( | |
label: 'onSurfaceVariant', | |
color: colorScheme.onSurfaceVariant, | |
onColor: colorScheme.surfaceContainerHighest, | |
), | |
], | |
), | |
divider, | |
ColorGroup( | |
children: [ | |
ColorChip( | |
label: 'outline', | |
color: colorScheme.outline, | |
onColor: null, | |
), | |
ColorChip( | |
label: 'shadow', | |
color: colorScheme.shadow, | |
onColor: null, | |
), | |
ColorChip( | |
label: 'inverseSurface', | |
color: colorScheme.inverseSurface, | |
onColor: colorScheme.onInverseSurface, | |
), | |
ColorChip( | |
label: 'onInverseSurface', | |
color: colorScheme.onInverseSurface, | |
onColor: colorScheme.inverseSurface, | |
), | |
ColorChip( | |
label: 'inversePrimary', | |
color: colorScheme.inversePrimary, | |
onColor: colorScheme.primary, | |
), | |
], | |
), | |
], | |
); | |
} | |
} | |
class ColorGroup extends StatelessWidget { | |
const ColorGroup({super.key, required this.children}); | |
final List<ColorChip> children; | |
@override | |
Widget build(BuildContext context) { | |
return RepaintBoundary( | |
child: Card( | |
clipBehavior: Clip.antiAlias, | |
child: Column( | |
children: children, | |
), | |
), | |
); | |
} | |
} | |
class ColorChip extends StatelessWidget { | |
const ColorChip({ | |
super.key, | |
required this.color, | |
required this.label, | |
this.onColor, | |
}); | |
final Color color; | |
final Color? onColor; | |
final String label; | |
static Color contrastColor(Color color) => switch (ThemeData.estimateBrightnessForColor(color)) { | |
Brightness.dark => Colors.white, | |
Brightness.light => Colors.black | |
}; | |
@override | |
Widget build(BuildContext context) { | |
final Color labelColor = onColor ?? contrastColor(color); | |
return ColoredBox( | |
color: color, | |
child: Padding( | |
padding: const EdgeInsets.all(16), | |
child: Row( | |
children: [ | |
Expanded(child: Text(label, style: TextStyle(color: labelColor))), | |
], | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment