From 09737e3cb3a77a4de6df586d6f412c8339e078a1 Mon Sep 17 00:00:00 2001 From: Lucio Baglione Date: Wed, 29 May 2024 14:00:23 +0200 Subject: [PATCH] feat: Add brand specific assets (#517) * feat: Add dark and icon version of brand logos. * feat: Add `BrandAssets` theme extention to have brand related assets available. * test: Add tests for `BrandAssets`. * chore: Remove `uses-material-design` option. * docs: Add docs for `BrandAssets` and `VoicesColorScheme`. * feat: Add basic lerp function for image transitioning. --- .../assets/images/catalyst_logo_icon.svg | 60 ++++ .../images/catalyst_logo_icon_white.svg | 17 + .../assets/images/catalyst_logo_white.svg | 32 ++ .../assets/images/fallback_logo.svg | 315 ++++++++++++++++++ .../assets/images/fallback_logo_icon.svg | 81 +++++ .../lib/generated/assets.gen.dart | 32 +- .../catalyst_voices_assets/pubspec.yaml | 1 - .../src/theme_extensions/brand_assets.dart | 53 +++ .../voices_color_scheme.dart | 5 + .../lib/src/themes/catalyst.dart | 18 +- .../lib/src/themes/fallback.dart | 14 +- .../test/src/catalyst_voices_brands_test.dart | 67 ++++ 12 files changed, 689 insertions(+), 6 deletions(-) create mode 100644 catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon.svg create mode 100644 catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon_white.svg create mode 100644 catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_white.svg create mode 100644 catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo.svg create mode 100644 catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo_icon.svg create mode 100644 catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/brand_assets.dart rename catalyst_voices/packages/catalyst_voices_brands/lib/src/{themes => theme_extensions}/voices_color_scheme.dart (96%) diff --git a/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon.svg b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon.svg new file mode 100644 index 0000000000..99604f3253 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon_white.svg b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon_white.svg new file mode 100644 index 0000000000..9c10d0b2a4 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_icon_white.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_white.svg b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_white.svg new file mode 100644 index 0000000000..51915d6656 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_assets/assets/images/catalyst_logo_white.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo.svg b/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo.svg new file mode 100644 index 0000000000..5f93f5dfa5 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo_icon.svg b/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo_icon.svg new file mode 100644 index 0000000000..6eebad4859 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_assets/assets/images/fallback_logo_icon.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + diff --git a/catalyst_voices/packages/catalyst_voices_assets/lib/generated/assets.gen.dart b/catalyst_voices/packages/catalyst_voices_assets/lib/generated/assets.gen.dart index e2079b0e71..ce2cdbaf47 100644 --- a/catalyst_voices/packages/catalyst_voices_assets/lib/generated/assets.gen.dart +++ b/catalyst_voices/packages/catalyst_voices_assets/lib/generated/assets.gen.dart @@ -18,6 +18,18 @@ class $AssetsImagesGen { SvgGenImage get catalystLogo => const SvgGenImage('assets/images/catalyst_logo.svg'); + /// File path: assets/images/catalyst_logo_icon.svg + SvgGenImage get catalystLogoIcon => + const SvgGenImage('assets/images/catalyst_logo_icon.svg'); + + /// File path: assets/images/catalyst_logo_icon_white.svg + SvgGenImage get catalystLogoIconWhite => + const SvgGenImage('assets/images/catalyst_logo_icon_white.svg'); + + /// File path: assets/images/catalyst_logo_white.svg + SvgGenImage get catalystLogoWhite => + const SvgGenImage('assets/images/catalyst_logo_white.svg'); + /// File path: assets/images/coming_soon_bkg.webp AssetGenImage get comingSoonBkg => const AssetGenImage('assets/images/coming_soon_bkg.webp'); @@ -26,9 +38,25 @@ class $AssetsImagesGen { AssetGenImage get dummyCatalystVoices => const AssetGenImage('assets/images/dummy_catalyst_voices.webp'); + /// File path: assets/images/fallback_logo.svg + SvgGenImage get fallbackLogo => + const SvgGenImage('assets/images/fallback_logo.svg'); + + /// File path: assets/images/fallback_logo_icon.svg + SvgGenImage get fallbackLogoIcon => + const SvgGenImage('assets/images/fallback_logo_icon.svg'); + /// List of all assets - List get values => - [catalystLogo, comingSoonBkg, dummyCatalystVoices]; + List get values => [ + catalystLogo, + catalystLogoIcon, + catalystLogoIconWhite, + catalystLogoWhite, + comingSoonBkg, + dummyCatalystVoices, + fallbackLogo, + fallbackLogoIcon + ]; } class VoicesAssets { diff --git a/catalyst_voices/packages/catalyst_voices_assets/pubspec.yaml b/catalyst_voices/packages/catalyst_voices_assets/pubspec.yaml index 6743ad0b9d..b469ea2c33 100644 --- a/catalyst_voices/packages/catalyst_voices_assets/pubspec.yaml +++ b/catalyst_voices/packages/catalyst_voices_assets/pubspec.yaml @@ -17,7 +17,6 @@ dev_dependencies: flutter_gen_runner: ^5.3.2 flutter: - uses-material-design: true generate: true assets: - assets/images/ diff --git a/catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/brand_assets.dart b/catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/brand_assets.dart new file mode 100644 index 0000000000..d722ec6065 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/brand_assets.dart @@ -0,0 +1,53 @@ +import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; +import 'package:flutter/material.dart'; + +/// A `ThemeExtension` that holds brand-specific assets for theming purposes. +/// +/// `BrandAssets` is used to encapsulate theme-dependent assets such as the +/// brand's logo and logo icon as SVG images which can be utilized throughout +/// the application wherever is required. +/// +/// Example usage: +/// ```dart +/// final logo = Theme.of(context).brandAssets.logo; +/// final logoIcon = Theme.of(context).brandAssets.logoIcon; +/// ``` +@immutable +class BrandAssets extends ThemeExtension { + final SvgGenImage logo; + final SvgGenImage logoIcon; + + const BrandAssets({ + required this.logo, + required this.logoIcon, + }); + + @override + ThemeExtension copyWith({ + SvgGenImage? logo, + SvgGenImage? logoIcon, + }) { + return BrandAssets( + logo: logo ?? this.logo, + logoIcon: logo ?? this.logoIcon, + ); + } + + @override + BrandAssets lerp( + ThemeExtension? other, + double t, + ) { + if (other is! BrandAssets) { + return this; + } else if (t >= 0.5) { + return other; + } else { + return this; + } + } +} + +extension BrandAssetsExtension on ThemeData { + BrandAssets get brandAssets => extension()!; +} diff --git a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/voices_color_scheme.dart b/catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/voices_color_scheme.dart similarity index 96% rename from catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/voices_color_scheme.dart rename to catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/voices_color_scheme.dart index 2708ae520f..42e01c0493 100644 --- a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/voices_color_scheme.dart +++ b/catalyst_voices/packages/catalyst_voices_brands/lib/src/theme_extensions/voices_color_scheme.dart @@ -1,5 +1,10 @@ import 'package:flutter/material.dart'; +/// A `ThemeExtension` that encapsulates a set color properties and extends the +/// standard material color scheme. +/// +/// `VoicesColorScheme` is used to define a comprehensive set of color +/// attributes that can be used in the Voices application to ensure consistency. @immutable class VoicesColorScheme extends ThemeExtension { final Color? textPrimary; diff --git a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart index 885c4efcf6..de9de295e3 100644 --- a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart +++ b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart @@ -1,12 +1,13 @@ import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; -import 'package:catalyst_voices_assets/generated/colors.gen.dart'; -import 'package:catalyst_voices_brands/src/themes/voices_color_scheme.dart'; +import 'package:catalyst_voices_brands/src/theme_extensions/brand_assets.dart'; +import 'package:catalyst_voices_brands/src/theme_extensions/voices_color_scheme.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; ThemeData _buildThemeData( ColorScheme colorScheme, VoicesColorScheme voicesColorScheme, + BrandAssets brandAssets, ) { return ThemeData( textTheme: TextTheme( @@ -113,6 +114,7 @@ ThemeData _buildThemeData( colorScheme: colorScheme, extensions: >[ voicesColorScheme, + brandAssets, ], ); } @@ -219,14 +221,26 @@ const VoicesColorScheme darkVoicesColorScheme = VoicesColorScheme( iconsError: VoicesColors.darkIconsError, ); +final BrandAssets lightBrandAssets = BrandAssets( + logo: VoicesAssets.images.catalystLogo, + logoIcon: VoicesAssets.images.catalystLogoIcon, +); + +final BrandAssets darkBrandAssets = BrandAssets( + logo: VoicesAssets.images.catalystLogoWhite, + logoIcon: VoicesAssets.images.catalystLogoIconWhite, +); + /// [ThemeData] for the `catalyst` brand. final ThemeData catalyst = _buildThemeData( lightColorScheme, lightVoicesColorScheme, + lightBrandAssets, ); /// Dark [ThemeData] for the `catalyst` brand. final ThemeData darkCatalyst = _buildThemeData( darkColorScheme, darkVoicesColorScheme, + darkBrandAssets, ); diff --git a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/fallback.dart b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/fallback.dart index 7fa296225d..bdb8b42232 100644 --- a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/fallback.dart +++ b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/fallback.dart @@ -1,7 +1,19 @@ +import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; +import 'package:catalyst_voices_brands/src/theme_extensions/brand_assets.dart'; import 'package:flutter/material.dart'; +final BrandAssets lightBrandAssets = BrandAssets( + logo: VoicesAssets.images.fallbackLogo, + logoIcon: VoicesAssets.images.fallbackLogoIcon, +); + /// [ThemeData] for the `fallback` brand. -final ThemeData fallback = ThemeData.light(); +final ThemeData fallback = ThemeData( + colorScheme: ThemeData.light().colorScheme, + extensions: >[ + lightBrandAssets, + ], +); /// Dark [ThemeData] for the `fallback` brand. final ThemeData darkFallback = ThemeData.dark(); diff --git a/catalyst_voices/packages/catalyst_voices_brands/test/src/catalyst_voices_brands_test.dart b/catalyst_voices/packages/catalyst_voices_brands/test/src/catalyst_voices_brands_test.dart index eea47f7db2..c99034142f 100644 --- a/catalyst_voices/packages/catalyst_voices_brands/test/src/catalyst_voices_brands_test.dart +++ b/catalyst_voices/packages/catalyst_voices_brands/test/src/catalyst_voices_brands_test.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; import 'package:catalyst_voices_blocs/src/brand/brand_bloc.dart'; import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; +import 'package:catalyst_voices_brands/src/theme_extensions/brand_assets.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -18,6 +19,9 @@ void main() { builder: (context) => Scaffold( body: Row( children: [ + CatalystSvgPicture.asset( + Theme.of(context).brandAssets.logo.path, + ), MaterialButton( key: catalystKey, color: Theme.of(context).primaryColor, @@ -127,4 +131,67 @@ void main() { ); }); }); + group('Test brand_assets', () { + final catalystLogo = CatalystSvgPicture.asset( + VoicesAssets.images.catalystLogo.path, + ); + final fallbackLogo = CatalystSvgPicture.asset( + VoicesAssets.images.fallbackLogo.path, + ); + testWidgets('Logo from Default theme is applied', (tester) async { + await tester.pumpWidget( + buildApp(), + ); + + final logo = find.byType(CatalystSvgPicture).first; + + expect(logo, findsOneWidget); + expect( + tester.widget(logo).bytesLoader, + catalystLogo.bytesLoader, + ); + }); + + testWidgets('Fallback Logo is applied after switch', (tester) async { + await tester.pumpWidget( + buildApp(), + ); + + final logo = find.byType(CatalystSvgPicture).first; + final fallbackButton = find.byKey(fallbackKey); + + expect(logo, findsOneWidget); + expect(fallbackButton, findsOneWidget); + + await tester.tap(fallbackButton); + await tester.pumpAndSettle(); + expect( + tester.widget(logo).bytesLoader, + fallbackLogo.bytesLoader, + ); + }); + + testWidgets('Catalyst Logo is applied after switch', (tester) async { + await tester.pumpWidget( + buildApp(), + ); + + final logo = find.byType(CatalystSvgPicture).first; + final catalystButton = find.byKey(catalystKey); + final fallbackButton = find.byKey(fallbackKey); + + expect(logo, findsOneWidget); + expect(catalystButton, findsOneWidget); + expect(fallbackButton, findsOneWidget); + + await tester.tap(fallbackButton); + await tester.pumpAndSettle(); + await tester.tap(catalystButton); + await tester.pumpAndSettle(); + expect( + tester.widget(logo).bytesLoader, + catalystLogo.bytesLoader, + ); + }); + }); }