color_palettes_screen.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. // Copyright 2021 The Flutter team. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. import 'package:flutter/gestures.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:url_launcher/url_launcher.dart';
  7. const Widget divider = SizedBox(height: 10);
  8. // If screen content width is greater or equal to this value, the light and dark
  9. // color schemes will be displayed in a column. Otherwise, they will
  10. // be displayed in a row.
  11. const double narrowScreenWidthThreshold = 400;
  12. class ColorPalettesScreen extends StatelessWidget {
  13. const ColorPalettesScreen({super.key});
  14. @override
  15. Widget build(BuildContext context) {
  16. Color selectedColor = Theme.of(context).primaryColor;
  17. ThemeData lightTheme = ThemeData(
  18. colorSchemeSeed: selectedColor,
  19. brightness: Brightness.light,
  20. );
  21. ThemeData darkTheme = ThemeData(
  22. colorSchemeSeed: selectedColor,
  23. brightness: Brightness.dark,
  24. );
  25. Widget schemeLabel(String brightness) {
  26. return Padding(
  27. padding: const EdgeInsets.symmetric(vertical: 15),
  28. child: Text(
  29. brightness,
  30. style: const TextStyle(fontWeight: FontWeight.bold),
  31. ),
  32. );
  33. }
  34. Widget schemeView(ThemeData theme) {
  35. return Padding(
  36. padding: const EdgeInsets.symmetric(horizontal: 15),
  37. child: ColorSchemeView(
  38. colorScheme: theme.colorScheme,
  39. ),
  40. );
  41. }
  42. Widget dynamicColorNotice() => RichText(
  43. textAlign: TextAlign.center,
  44. text: TextSpan(
  45. style: Theme.of(context).textTheme.bodySmall,
  46. children: [
  47. const TextSpan(
  48. text: 'To create color schemes based on a '
  49. 'platform\'s implementation of dynamic color, '
  50. 'use the '),
  51. TextSpan(
  52. text: 'dynamic_color',
  53. style: const TextStyle(decoration: TextDecoration.underline),
  54. recognizer: TapGestureRecognizer()
  55. ..onTap = () async {
  56. final url = Uri.parse(
  57. 'https://pub.dev/packages/dynamic_color',
  58. );
  59. if (!await launchUrl(url)) {
  60. throw Exception('Could not launch $url');
  61. }
  62. },
  63. ),
  64. const TextSpan(text: ' package.'),
  65. ],
  66. ),
  67. );
  68. return Expanded(
  69. child: LayoutBuilder(builder: (context, constraints) {
  70. if (constraints.maxWidth < narrowScreenWidthThreshold) {
  71. return SingleChildScrollView(
  72. child: Column(
  73. children: [
  74. dynamicColorNotice(),
  75. divider,
  76. schemeLabel('Light ColorScheme'),
  77. schemeView(lightTheme),
  78. divider,
  79. divider,
  80. schemeLabel('Dark ColorScheme'),
  81. schemeView(darkTheme),
  82. ],
  83. ),
  84. );
  85. } else {
  86. return SingleChildScrollView(
  87. child: Padding(
  88. padding: const EdgeInsets.only(top: 5),
  89. child: Column(
  90. children: [
  91. dynamicColorNotice(),
  92. Row(
  93. children: [
  94. Expanded(
  95. child: Column(
  96. children: [
  97. schemeLabel('Light ColorScheme'),
  98. schemeView(lightTheme),
  99. ],
  100. ),
  101. ),
  102. Expanded(
  103. child: Column(
  104. children: [
  105. schemeLabel('Dark ColorScheme'),
  106. schemeView(darkTheme),
  107. ],
  108. ),
  109. ),
  110. ],
  111. ),
  112. ],
  113. ),
  114. ),
  115. );
  116. }
  117. }),
  118. );
  119. }
  120. }
  121. class ColorSchemeView extends StatelessWidget {
  122. const ColorSchemeView({super.key, required this.colorScheme});
  123. final ColorScheme colorScheme;
  124. @override
  125. Widget build(BuildContext context) {
  126. return Column(
  127. children: [
  128. ColorGroup(children: [
  129. ColorChip(
  130. label: 'primary',
  131. color: colorScheme.primary,
  132. onColor: colorScheme.onPrimary,
  133. ),
  134. ColorChip(
  135. label: 'onPrimary',
  136. color: colorScheme.onPrimary,
  137. onColor: colorScheme.primary),
  138. ColorChip(
  139. label: 'primaryContainer',
  140. color: colorScheme.primaryContainer,
  141. onColor: colorScheme.onPrimaryContainer,
  142. ),
  143. ColorChip(
  144. label: 'onPrimaryContainer',
  145. color: colorScheme.onPrimaryContainer,
  146. onColor: colorScheme.primaryContainer,
  147. ),
  148. ]),
  149. divider,
  150. ColorGroup(children: [
  151. ColorChip(
  152. label: 'secondary',
  153. color: colorScheme.secondary,
  154. onColor: colorScheme.onSecondary,
  155. ),
  156. ColorChip(
  157. label: 'onSecondary',
  158. color: colorScheme.onSecondary,
  159. onColor: colorScheme.secondary,
  160. ),
  161. ColorChip(
  162. label: 'secondaryContainer',
  163. color: colorScheme.secondaryContainer,
  164. onColor: colorScheme.onSecondaryContainer,
  165. ),
  166. ColorChip(
  167. label: 'onSecondaryContainer',
  168. color: colorScheme.onSecondaryContainer,
  169. onColor: colorScheme.secondaryContainer),
  170. ]),
  171. divider,
  172. ColorGroup(
  173. children: [
  174. ColorChip(
  175. label: 'tertiary',
  176. color: colorScheme.tertiary,
  177. onColor: colorScheme.onTertiary),
  178. ColorChip(
  179. label: 'onTertiary',
  180. color: colorScheme.onTertiary,
  181. onColor: colorScheme.tertiary),
  182. ColorChip(
  183. label: 'tertiaryContainer',
  184. color: colorScheme.tertiaryContainer,
  185. onColor: colorScheme.onTertiaryContainer),
  186. ColorChip(
  187. label: 'onTertiaryContainer',
  188. color: colorScheme.onTertiaryContainer,
  189. onColor: colorScheme.tertiaryContainer),
  190. ],
  191. ),
  192. divider,
  193. ColorGroup(
  194. children: [
  195. ColorChip(
  196. label: 'error',
  197. color: colorScheme.error,
  198. onColor: colorScheme.onError),
  199. ColorChip(
  200. label: 'onError',
  201. color: colorScheme.onError,
  202. onColor: colorScheme.error),
  203. ColorChip(
  204. label: 'errorContainer',
  205. color: colorScheme.errorContainer,
  206. onColor: colorScheme.onErrorContainer),
  207. ColorChip(
  208. label: 'onErrorContainer',
  209. color: colorScheme.onErrorContainer,
  210. onColor: colorScheme.errorContainer),
  211. ],
  212. ),
  213. divider,
  214. ColorGroup(
  215. children: [
  216. ColorChip(
  217. label: 'background',
  218. color: colorScheme.background,
  219. onColor: colorScheme.onBackground),
  220. ColorChip(
  221. label: 'onBackground',
  222. color: colorScheme.onBackground,
  223. onColor: colorScheme.background),
  224. ],
  225. ),
  226. divider,
  227. ColorGroup(
  228. children: [
  229. ColorChip(
  230. label: 'surface',
  231. color: colorScheme.surface,
  232. onColor: colorScheme.onSurface),
  233. ColorChip(
  234. label: 'onSurface',
  235. color: colorScheme.onSurface,
  236. onColor: colorScheme.surface),
  237. ColorChip(
  238. label: 'surfaceVariant',
  239. color: colorScheme.surfaceVariant,
  240. onColor: colorScheme.onSurfaceVariant),
  241. ColorChip(
  242. label: 'onSurfaceVariant',
  243. color: colorScheme.onSurfaceVariant,
  244. onColor: colorScheme.surfaceVariant),
  245. ],
  246. ),
  247. divider,
  248. ColorGroup(
  249. children: [
  250. ColorChip(label: 'outline', color: colorScheme.outline),
  251. ColorChip(label: 'shadow', color: colorScheme.shadow),
  252. ColorChip(
  253. label: 'inverseSurface',
  254. color: colorScheme.inverseSurface,
  255. onColor: colorScheme.onInverseSurface),
  256. ColorChip(
  257. label: 'onInverseSurface',
  258. color: colorScheme.onInverseSurface,
  259. onColor: colorScheme.inverseSurface),
  260. ColorChip(
  261. label: 'inversePrimary',
  262. color: colorScheme.inversePrimary,
  263. onColor: colorScheme.primary),
  264. ],
  265. ),
  266. ],
  267. );
  268. }
  269. }
  270. class ColorGroup extends StatelessWidget {
  271. const ColorGroup({super.key, required this.children});
  272. final List<Widget> children;
  273. @override
  274. Widget build(BuildContext context) {
  275. return RepaintBoundary(
  276. child: Card(
  277. clipBehavior: Clip.antiAlias,
  278. child: Column(
  279. children: children,
  280. ),
  281. ),
  282. );
  283. }
  284. }
  285. class ColorChip extends StatelessWidget {
  286. const ColorChip({
  287. super.key,
  288. required this.color,
  289. required this.label,
  290. this.onColor,
  291. });
  292. final Color color;
  293. final Color? onColor;
  294. final String label;
  295. static Color contrastColor(Color color) {
  296. final brightness = ThemeData.estimateBrightnessForColor(color);
  297. switch (brightness) {
  298. case Brightness.dark:
  299. return Colors.white;
  300. case Brightness.light:
  301. return Colors.black;
  302. }
  303. }
  304. @override
  305. Widget build(BuildContext context) {
  306. final Color labelColor = onColor ?? contrastColor(color);
  307. return Container(
  308. color: color,
  309. child: Padding(
  310. padding: const EdgeInsets.all(16),
  311. child: Row(
  312. children: [
  313. Expanded(child: Text(label, style: TextStyle(color: labelColor))),
  314. ],
  315. ),
  316. ),
  317. );
  318. }
  319. }