|
|
|
// 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: 'surfaceContainerHighest',
|
|
|
|
color: colorScheme.surfaceContainerHighest,
|
|
|
|
onColor: colorScheme.surfaceContainerHighest,
|
|
|
|
),
|
|
|
|
ColorChip(
|
|
|
|
label: 'surfaceContainerHighest',
|
|
|
|
color: colorScheme.surfaceContainerHighest,
|
|
|
|
onColor: colorScheme.surfaceContainerHighest,
|
|
|
|
),
|
|
|
|
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.surface,
|
|
|
|
onColor: colorScheme.onSurface,
|
|
|
|
),
|
|
|
|
ColorChip(
|
|
|
|
label: 'onSurface',
|
|
|
|
color: colorScheme.onSurface,
|
|
|
|
onColor: colorScheme.surface,
|
|
|
|
),
|
|
|
|
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<Widget> 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 Container(
|
|
|
|
color: color,
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Expanded(child: Text(label, style: TextStyle(color: labelColor))),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|