// Copyright 2021 The Flutter team. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. 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; class ColorPalettesScreen extends StatelessWidget { const ColorPalettesScreen({super.key}); @override Widget build(BuildContext context) { Color selectedColor = Theme.of(context).primaryColor; ThemeData lightTheme = ThemeData( colorSchemeSeed: selectedColor, brightness: Brightness.light, ); 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.'), ], ), ); return Expanded( child: LayoutBuilder(builder: (context, constraints) { if (constraints.maxWidth < narrowScreenWidthThreshold) { return SingleChildScrollView( child: Column( children: [ dynamicColorNotice(), divider, schemeLabel('Light ColorScheme'), schemeView(lightTheme), divider, divider, schemeLabel('Dark ColorScheme'), schemeView(darkTheme), ], ), ); } else { return SingleChildScrollView( 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: [ 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: '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: '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: '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: 'surface', color: colorScheme.surface, onColor: colorScheme.onSurface, ), ColorChip( label: 'onSurface', color: colorScheme.onSurface, onColor: colorScheme.surface, ), ColorChip( label: 'surfaceVariant', color: colorScheme.surfaceVariant, onColor: colorScheme.onSurfaceVariant, ), ColorChip( label: 'onSurfaceVariant', color: colorScheme.onSurfaceVariant, onColor: colorScheme.surfaceVariant, ), ColorChip( label: 'surfaceTint', color: colorScheme.surfaceTint, ), ], ), divider, ColorGroup( children: [ ColorChip( label: 'outline', color: colorScheme.outline, ), ColorChip( label: 'outlineVariant', color: colorScheme.outlineVariant, ), ], ), divider, ColorGroup( children: [ 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, ), ], ), divider, ColorGroup( children: [ ColorChip( label: 'background', color: colorScheme.background, onColor: colorScheme.onBackground, ), ColorChip( label: 'onBackground', color: colorScheme.onBackground, onColor: colorScheme.background, ), ColorChip( label: 'scrim', color: colorScheme.scrim, ), ColorChip( label: 'shadow', color: colorScheme.shadow, ), ], ), divider, ], ); } } class ColorGroup extends StatelessWidget { const ColorGroup({super.key, required this.children}); final List 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) { final brightness = ThemeData.estimateBrightnessForColor(color); switch (brightness) { case Brightness.dark: return Colors.white; case Brightness.light: return Colors.black; } } @override Widget build(BuildContext context) { final Color labelColor = onColor ?? contrastColor(color); return Container( color: color, child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Expanded(child: Text(label, style: TextStyle(color: labelColor))), ], ), ), ); } }