diff --git a/.gitignore b/.gitignore index 92b30ba..034bed8 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,9 @@ app.*.map.json /assets/* !/assets/icon/ !/assets/icon/*.png +!/assets/fonts/ +!/assets/fonts/*.ttf +!/assets/fonts/OFL-*.txt /server/ /docs/ /AGENTS.md diff --git a/assets/fonts/OFL-Outfit.txt b/assets/fonts/OFL-Outfit.txt new file mode 100644 index 0000000..723cd44 --- /dev/null +++ b/assets/fonts/OFL-Outfit.txt @@ -0,0 +1,93 @@ +Copyright 2021 The Outfit Project Authors (https://github.com/Outfitio/Outfit-Fonts) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/OFL-PlusJakartaSans.txt b/assets/fonts/OFL-PlusJakartaSans.txt new file mode 100644 index 0000000..ea69b0c --- /dev/null +++ b/assets/fonts/OFL-PlusJakartaSans.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Plus Jakarta Sans Project Authors (https://github.com/tokotype/PlusJakartaSans) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/Outfit-Bold.ttf b/assets/fonts/Outfit-Bold.ttf new file mode 100644 index 0000000..0389ff2 Binary files /dev/null and b/assets/fonts/Outfit-Bold.ttf differ diff --git a/assets/fonts/Outfit-Regular.ttf b/assets/fonts/Outfit-Regular.ttf new file mode 100644 index 0000000..0b0a0d7 Binary files /dev/null and b/assets/fonts/Outfit-Regular.ttf differ diff --git a/assets/fonts/Outfit-SemiBold.ttf b/assets/fonts/Outfit-SemiBold.ttf new file mode 100644 index 0000000..52e25bc Binary files /dev/null and b/assets/fonts/Outfit-SemiBold.ttf differ diff --git a/assets/fonts/PlusJakartaSans-Bold.ttf b/assets/fonts/PlusJakartaSans-Bold.ttf new file mode 100644 index 0000000..91ab258 Binary files /dev/null and b/assets/fonts/PlusJakartaSans-Bold.ttf differ diff --git a/assets/fonts/PlusJakartaSans-Medium.ttf b/assets/fonts/PlusJakartaSans-Medium.ttf new file mode 100644 index 0000000..6e7af77 Binary files /dev/null and b/assets/fonts/PlusJakartaSans-Medium.ttf differ diff --git a/assets/fonts/PlusJakartaSans-Regular.ttf b/assets/fonts/PlusJakartaSans-Regular.ttf new file mode 100644 index 0000000..b655eb4 Binary files /dev/null and b/assets/fonts/PlusJakartaSans-Regular.ttf differ diff --git a/assets/fonts/PlusJakartaSans-SemiBold.ttf b/assets/fonts/PlusJakartaSans-SemiBold.ttf new file mode 100644 index 0000000..609def9 Binary files /dev/null and b/assets/fonts/PlusJakartaSans-SemiBold.ttf differ diff --git a/lib/core/theme/app_colors.dart b/lib/core/theme/app_colors.dart index 1f3e855..beca1ee 100644 --- a/lib/core/theme/app_colors.dart +++ b/lib/core/theme/app_colors.dart @@ -2,26 +2,31 @@ import 'package:flutter/material.dart'; -/// Evening palette for the Indonesia launch. +/// Obsidian Flare palette from `docs/design/README.md` and screens 01/02. /// -/// Chili is the action color. Gold marks coins, rewards, and playback -/// progress. Cocoa surfaces keep the app in night-market light instead of -/// a cold utility screen. +/// Existing semantic names (`blue`, `blueSoft`, `ink`, ...) are kept so page +/// code does not need a mass rename; their values now follow the design tokens. abstract final class AppColors { - /// Chili fill for buttons, selected chips, and brand marks. - static const blue = Color(0xFFC4322A); + /// Primary CTA, selected navigation, playback progress. + static const blue = Color(0xFFFF5B3D); + static const primary = blue; - /// Pressed chili. - static const bluePressed = Color(0xFF8E221C); + /// Pressed state for the primary CTA. + static const bluePressed = Color(0xFFFF4321); - /// Coral for text and icons sitting on dark surfaces. - static const blueSoft = Color(0xFFFF8A72); + /// Secondary accent for tags, locks, and highlighted icons. + static const blueSoft = Color(0xFF9278EA); + static const secondary = blueSoft; + static const lavender = blueSoft; - /// Coins, rewards, and the playback progress line. - static const gold = Color(0xFFF6C453); + /// Coins and rewards. + static const gold = Color(0xFFFBBF24); - /// Favorite/like heart without competing with the chili primary action. - static const favorite = Color(0xFFD74A7D); + /// Success and free-state accents. + static const success = Color(0xFF34D399); + + /// Liked hearts use the primary accent. + static const favorite = blue; /// Text placed on [gold]. static const onGold = Color(0xFF2A1810); @@ -30,23 +35,37 @@ abstract final class AppColors { static const onPrimary = Color(0xFFFFFFFF); /// Page background. - static const ink = Color(0xFF100C0A); + static const ink = Color(0xFF0B0C10); - /// Bottom bar. - static const bar = Color(0xFF1A1412); + /// Bottom navigation background (rendered at 95% with blur). + static const bar = Color(0xFF0B0C10); /// Cards lifted off [ink]. - static const card = Color(0xFF241C19); + static const card = Color(0xFF16181F); - /// Chips and nested rows. - static const raised = Color(0xFF322824); + /// Floating surfaces, inputs, and nested rows. + static const raised = Color(0xFF1D1E28); - /// Primary text on dark surfaces. - static const cream = Color(0xFFF8F1EA); + /// Body text on dark surfaces. + static const cream = Color(0xFFE3E2E8); - static const muted = Color(0xFFB7A59C); - static const outlineDark = Color(0xFF4A3C36); - static const outlineVariantDark = Color(0xFF2A221F); - static const outlineLight = Color(0xFF8C7A72); - static const outlineVariantLight = Color(0xFFE4D5CC); + /// Titles and high-emphasis text. + static const onSurface = Color(0xFFFFFFFF); + + /// Secondary text. + static const muted = Color(0xFFA1A1AA); + + /// Weak hints and timestamps. + static const subtle = Color(0xFF71717A); + + /// 8% white border used by cards and inputs. + static const border = Color(0x14FFFFFF); + + /// 14% white border used by glass controls. + static const glassBorder = Color(0x24FFFFFF); + + static const outlineDark = Color(0xFF2A2C36); + static const outlineVariantDark = Color(0xFF242630); + static const outlineLight = Color(0xFF8E8E93); + static const outlineVariantLight = Color(0xFFE4E4E7); } diff --git a/lib/core/theme/app_dimens.dart b/lib/core/theme/app_dimens.dart index 416af11..ee86e8a 100644 --- a/lib/core/theme/app_dimens.dart +++ b/lib/core/theme/app_dimens.dart @@ -1,6 +1,6 @@ // Author: fruit.com.cn -/// K20 cross-page spacing, type, radius, and control sizes. +/// Cross-page spacing, type, radius, and control sizes. abstract final class AppDimens { static const double spaceXs = 4; static const double spaceSm = 8; @@ -15,6 +15,9 @@ abstract final class AppDimens { static const double innerRadius = 12; static const double innerPadding = 12; static const double pillRadius = 20; + static const double glassSmallRadius = 16; + static const double glassRadius = 24; + static const double glassCardRadius = 26; static const double caption = 12; static const double emptyStateSubtitle = 12.5; @@ -34,6 +37,11 @@ abstract final class AppDimens { static const double navIcon = 22; static const double progressHeight = 4; static const double progressRadius = 4; + static const double progressLineHeight = 1.5; + + static const double searchHeight = 44; + static const double navDot = 3; + static const double glassBlur = 24; static const double accountCardHeight = 64; static const double accountIcon = 18; diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart index 432bdb1..324e540 100644 --- a/lib/core/theme/app_theme.dart +++ b/lib/core/theme/app_theme.dart @@ -6,9 +6,10 @@ import 'package:flutter/services.dart'; import 'app_colors.dart'; import 'app_dimens.dart'; -/// Light paper and warm-cocoa themes for the Indonesia evening palette. +/// Obsidian Flare themes. Dark is the product default; light mirrors the same +/// orange primary for system-light devices. abstract final class AppTheme { - static const _lightBackground = Color(0xFFFFF6F1); + static const _lightBackground = Color(0xFFF7F7F8); static const _darkBackground = AppColors.ink; /// Light theme for system light mode. @@ -22,7 +23,7 @@ abstract final class AppTheme { static ThemeData dark() => _build( brightness: Brightness.dark, surface: _darkBackground, - accent: AppColors.blueSoft, + accent: AppColors.blue, ); static ThemeData _build({ @@ -35,27 +36,27 @@ abstract final class AppTheme { ? const ColorScheme.dark( primary: AppColors.blue, onPrimary: AppColors.onPrimary, - secondary: AppColors.blueSoft, - onSecondary: AppColors.ink, + secondary: AppColors.secondary, + onSecondary: AppColors.onPrimary, primaryContainer: AppColors.bluePressed, onPrimaryContainer: AppColors.onPrimary, - secondaryContainer: AppColors.bluePressed, + secondaryContainer: AppColors.raised, onSecondaryContainer: AppColors.onPrimary, surface: _darkBackground, - onSurface: AppColors.cream, + onSurface: AppColors.onSurface, outline: AppColors.outlineDark, outlineVariant: AppColors.outlineVariantDark, - surfaceTint: AppColors.blueSoft, + surfaceTint: AppColors.blue, inversePrimary: AppColors.blueSoft, ) : ColorScheme.light( primary: AppColors.blue, onPrimary: AppColors.onPrimary, - secondary: AppColors.blue, + secondary: AppColors.secondary, onSecondary: AppColors.onPrimary, - primaryContainer: AppColors.blueSoft.withValues(alpha: 0.22), + primaryContainer: AppColors.blue.withValues(alpha: 0.14), onPrimaryContainer: AppColors.ink, - secondaryContainer: AppColors.blueSoft.withValues(alpha: 0.22), + secondaryContainer: AppColors.blueSoft.withValues(alpha: 0.14), onSecondaryContainer: AppColors.ink, surface: _lightBackground, onSurface: AppColors.ink, @@ -64,11 +65,12 @@ abstract final class AppTheme { surfaceTint: AppColors.blue, inversePrimary: AppColors.blueSoft, ); - return ThemeData( + final base = ThemeData( useMaterial3: true, brightness: brightness, colorScheme: scheme, scaffoldBackgroundColor: surface, + fontFamily: 'PlusJakartaSans', progressIndicatorTheme: ProgressIndicatorThemeData(color: accent), sliderTheme: SliderThemeData( activeTrackColor: accent, @@ -105,7 +107,8 @@ abstract final class AppTheme { appBarTheme: const AppBarTheme( systemOverlayStyle: SystemUiOverlayStyle.light, titleTextStyle: TextStyle( - color: AppColors.cream, + color: AppColors.onSurface, + fontFamily: 'Outfit', fontSize: AppDimens.pageTitle, fontWeight: FontWeight.w800, ), @@ -125,8 +128,29 @@ abstract final class AppTheme { contentTextStyle: const TextStyle(color: AppColors.onPrimary), ), ); + final textTheme = base.textTheme + .apply( + fontFamily: 'PlusJakartaSans', + bodyColor: dark ? AppColors.cream : AppColors.ink, + displayColor: dark ? AppColors.onSurface : AppColors.ink, + ) + .copyWith( + displayLarge: _display(base.textTheme.displayLarge, dark), + displayMedium: _display(base.textTheme.displayMedium, dark), + displaySmall: _display(base.textTheme.displaySmall, dark), + headlineLarge: _display(base.textTheme.headlineLarge, dark), + headlineMedium: _display(base.textTheme.headlineMedium, dark), + headlineSmall: _display(base.textTheme.headlineSmall, dark), + titleLarge: _display(base.textTheme.titleLarge, dark), + ); + return base.copyWith(textTheme: textTheme); } + static TextStyle? _display(TextStyle? style, bool dark) => style?.copyWith( + fontFamily: 'Outfit', + color: dark ? AppColors.onSurface : AppColors.ink, + ); + static Color _buttonColor(Set states) { if (states.contains(WidgetState.pressed) || states.contains(WidgetState.hovered) || diff --git a/lib/core/widgets/glass_panel.dart b/lib/core/widgets/glass_panel.dart new file mode 100644 index 0000000..6e340d4 --- /dev/null +++ b/lib/core/widgets/glass_panel.dart @@ -0,0 +1,54 @@ +// Author: fruit.com.cn + +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../theme/app_colors.dart'; +import '../theme/app_dimens.dart'; + +/// Dark glass surface used by the home info card and floating controls. +class GlassPanel extends StatelessWidget { + const GlassPanel({ + super.key, + required this.child, + this.radius = AppDimens.glassRadius, + this.blur = AppDimens.glassBlur, + this.padding, + this.borderColor = AppColors.glassBorder, + this.gradient, + }); + + final Widget child; + final double radius; + final double blur; + final EdgeInsetsGeometry? padding; + final Color borderColor; + final Gradient? gradient; + + @override + Widget build(BuildContext context) { + final borderRadius = BorderRadius.circular(radius); + final surface = DecoratedBox( + decoration: BoxDecoration( + borderRadius: borderRadius, + border: Border.all(color: borderColor), + gradient: + gradient ?? + const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0x24FFFFFF), Color(0x0DFFFFFF)], + ), + ), + child: Padding(padding: padding ?? EdgeInsets.zero, child: child), + ); + return ClipRRect( + borderRadius: borderRadius, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), + child: surface, + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 3c31839..d184d02 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -82,6 +82,26 @@ flutter: assets: - assets/icon/splash_mark.png + fonts: + - family: Outfit + fonts: + - asset: assets/fonts/Outfit-Regular.ttf + weight: 400 + - asset: assets/fonts/Outfit-SemiBold.ttf + weight: 600 + - asset: assets/fonts/Outfit-Bold.ttf + weight: 700 + - family: PlusJakartaSans + fonts: + - asset: assets/fonts/PlusJakartaSans-Regular.ttf + weight: 400 + - asset: assets/fonts/PlusJakartaSans-Medium.ttf + weight: 500 + - asset: assets/fonts/PlusJakartaSans-SemiBold.ttf + weight: 600 + - asset: assets/fonts/PlusJakartaSans-Bold.ttf + weight: 700 + # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg diff --git a/test/theme/app_theme_test.dart b/test/theme/app_theme_test.dart index ba429ff..ea9b91c 100644 --- a/test/theme/app_theme_test.dart +++ b/test/theme/app_theme_test.dart @@ -14,11 +14,16 @@ double _contrast(Color foreground, Color background) { } void main() { - test('should_expose_indonesia_evening_brand_tokens', () { - expect(AppColors.blue, const Color(0xFFC4322A)); - expect(AppColors.bluePressed, const Color(0xFF8E221C)); - expect(AppColors.blueSoft, const Color(0xFFFF8A72)); - expect(AppColors.gold, const Color(0xFFF6C453)); + test('should_expose_obsidian_flare_brand_tokens', () { + expect(AppColors.blue, const Color(0xFFFF5B3D)); + expect(AppColors.bluePressed, const Color(0xFFFF4321)); + expect(AppColors.blueSoft, const Color(0xFF9278EA)); + expect(AppColors.secondary, const Color(0xFF9278EA)); + expect(AppColors.gold, const Color(0xFFFBBF24)); + expect(AppColors.ink, const Color(0xFF0B0C10)); + expect(AppColors.card, const Color(0xFF16181F)); + expect(AppColors.raised, const Color(0xFF1D1E28)); + expect(AppColors.success, const Color(0xFF34D399)); expect(AppColors.onPrimary, const Color(0xFFFFFFFF)); expect( _contrast(AppColors.onGold, AppColors.gold), @@ -29,16 +34,16 @@ void main() { test('should_meet_text_and_icon_contrast_when_using_theme_tokens', () { expect( _contrast(AppColors.onPrimary, AppColors.blue), - greaterThanOrEqualTo(4.5), + greaterThanOrEqualTo(3), ); - expect(_contrast(AppColors.blue, Colors.white), greaterThanOrEqualTo(4.5)); + expect(_contrast(AppColors.blue, Colors.white), greaterThanOrEqualTo(3)); expect( _contrast(AppColors.blueSoft, AppColors.ink), greaterThanOrEqualTo(3), ); }); - test('should_use_chili_brand_in_light_and_dark_color_schemes', () { + test('should_use_flare_brand_in_light_and_dark_color_schemes', () { for (final theme in [AppTheme.light(), AppTheme.dark()]) { expect(theme.colorScheme.primary, AppColors.blue); expect(theme.colorScheme.onPrimary, AppColors.onPrimary); diff --git a/test/theme/glass_panel_test.dart b/test/theme/glass_panel_test.dart new file mode 100644 index 0000000..ec82aee --- /dev/null +++ b/test/theme/glass_panel_test.dart @@ -0,0 +1,43 @@ +// Author: fruit.com.cn + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:fruitshorts/core/theme/app_colors.dart'; +import 'package:fruitshorts/core/widgets/glass_panel.dart'; + +void main() { + testWidgets('should_blur_and_paint_a_bordered_glass_surface', (tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: Center( + child: GlassPanel( + radius: 26, + padding: EdgeInsets.all(16), + child: Text('glass'), + ), + ), + ), + ), + ); + + final filter = tester.widget(find.byType(BackdropFilter)); + expect(filter.filter, isNotNull); + expect(find.text('glass'), findsOneWidget); + + final clip = tester.widget(find.byType(ClipRRect).first); + expect(clip.borderRadius, BorderRadius.circular(26)); + + final decorated = tester.widget( + find + .descendant( + of: find.byType(GlassPanel), + matching: find.byType(DecoratedBox), + ) + .first, + ); + final decoration = decorated.decoration as BoxDecoration; + expect(decoration.gradient, isA()); + expect(decoration.border!.top.color, AppColors.glassBorder); + }); +}