From 2953a15d2289ac2912112cf161ca22fb7682bd93 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 27 May 2026 12:05:42 +0200 Subject: [PATCH 01/35] poc for floating header --- .../components/toolbar/stream_app_bar.dart | 62 +++++++++++++++++-- .../components/stream_app_bar_theme.dart | 4 ++ .../stream_app_bar_theme.g.theme.dart | 11 ++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 9f200a2a..5d32e216 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -72,6 +72,7 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { Widget? trailing, bool primary = true, StreamAppBarStyle? style, + bool floating = false, }) : props = .new( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, @@ -80,6 +81,7 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { trailing: trailing, primary: primary, style: style, + floating: floating, ); /// The properties that configure this app bar. @@ -115,6 +117,7 @@ class StreamAppBarProps { this.trailing, this.primary = true, this.style, + this.floating = false, }); /// A widget to display before the [title]. @@ -172,6 +175,11 @@ class StreamAppBarProps { /// Resolution order per field: this [style] → ambient [StreamAppBarTheme] /// → token-backed defaults. final StreamAppBarStyle? style; + + /// Whether this app bar is floating. + /// + /// When true, the app bar is floating and will be displayed above the content. + final bool floating; } /// The default implementation of [StreamAppBar]. @@ -205,7 +213,10 @@ class DefaultStreamAppBar extends StatelessWidget { final style = context.streamAppBarTheme.style?.merge(props.style) ?? props.style; final defaults = _StreamAppBarStyleDefaults(context); - final effectiveBackgroundColor = style?.backgroundColor ?? defaults.backgroundColor; + final effectiveBackgroundColor = switch (props.floating) { + true => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, + false => style?.backgroundColor ?? defaults.backgroundColor, + }; final effectivePadding = style?.padding ?? defaults.padding; final effectiveSpacing = style?.spacing ?? defaults.spacing; final effectiveTitleTextStyle = style?.titleTextStyle ?? defaults.titleTextStyle; @@ -229,7 +240,8 @@ class DefaultStreamAppBar extends StatelessWidget { }; final useCloseIcon = parentRoute is PageRoute && parentRoute.fullscreenDialog; leading = StreamButton.icon( - type: .ghost, + type: props.floating ? .outline : .ghost, + isFloating: props.floating, style: .secondary, icon: Icon(useCloseIcon ? icons.xmark : backIcon), onPressed: Navigator.of(context).maybePop, @@ -309,14 +321,49 @@ class DefaultStreamAppBar extends StatelessWidget { // not a configurable divider. return DecoratedBox( decoration: BoxDecoration( - color: effectiveBackgroundColor, - border: Border( - bottom: BorderSide(color: context.streamColorScheme.borderSubtle), - ), + color: props.floating ? null : effectiveBackgroundColor, + gradient: props.floating + ? _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor) + : null, + backgroundBlendMode: BlendMode.screen, + border: props.floating ? null : Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), ), child: bar, ); } + + LinearGradient _getFloatingGradient( + BuildContext context, { + required Color effectiveBackgroundColor, + }) { + // Compute the fraction of the total bar height occupied by the system + // safe area so the gradient fade only starts below the status bar. + // Above that boundary the background is fully solid. + final safeAreaTop = props.primary ? MediaQuery.paddingOf(context).top : 0.0; + final totalHeight = safeAreaTop + kStreamToolbarHeight; + final f = totalHeight > 0 ? safeAreaTop / totalHeight : 0.0; + + return LinearGradient( + colors: [ + effectiveBackgroundColor, // solid through safe area + effectiveBackgroundColor, // solid at safe area boundary + effectiveBackgroundColor.withAlpha(0xE8), // ~91 % + effectiveBackgroundColor.withAlpha(0xA8), // ~66 % + effectiveBackgroundColor.withAlpha(0x40), // ~25 % + effectiveBackgroundColor.withAlpha(0x00), // transparent + ], + stops: [ + 0.0, + f, + f + (1 - f) * 0.55, + f + (1 - f) * 0.75, + f + (1 - f) * 0.90, + 1.0, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ); + } } // Default style values for [StreamAppBar]. @@ -336,6 +383,9 @@ class _StreamAppBarStyleDefaults extends StreamAppBarStyle { @override Color get backgroundColor => _colorScheme.backgroundElevation1; + @override + Color get floatingBackgroundColor => _colorScheme.backgroundElevation0; + @override double get spacing => _spacing.sm; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart index 31341006..a389c307 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart @@ -137,6 +137,7 @@ class StreamAppBarStyle with _$StreamAppBarStyle { /// Creates an app bar style with optional property overrides. const StreamAppBarStyle({ this.backgroundColor, + this.floatingBackgroundColor, this.padding, this.spacing, this.titleTextStyle, @@ -148,6 +149,9 @@ class StreamAppBarStyle with _$StreamAppBarStyle { /// The background colour of the app bar. final Color? backgroundColor; + /// The background colour of the floating app bar. + final Color? floatingBackgroundColor; + /// The padding around the header's content row. final EdgeInsetsGeometry? padding; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart index 5f0e722e..0dc90277 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart @@ -100,6 +100,11 @@ mixin _$StreamAppBarStyle { return StreamAppBarStyle( backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), + floatingBackgroundColor: Color.lerp( + a.floatingBackgroundColor, + b.floatingBackgroundColor, + t, + ), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), spacing: lerpDouble$(a.spacing, b.spacing, t), titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t), @@ -123,6 +128,7 @@ mixin _$StreamAppBarStyle { StreamAppBarStyle copyWith({ Color? backgroundColor, + Color? floatingBackgroundColor, EdgeInsetsGeometry? padding, double? spacing, TextStyle? titleTextStyle, @@ -134,6 +140,8 @@ mixin _$StreamAppBarStyle { return StreamAppBarStyle( backgroundColor: backgroundColor ?? _this.backgroundColor, + floatingBackgroundColor: + floatingBackgroundColor ?? _this.floatingBackgroundColor, padding: padding ?? _this.padding, spacing: spacing ?? _this.spacing, titleTextStyle: titleTextStyle ?? _this.titleTextStyle, @@ -156,6 +164,7 @@ mixin _$StreamAppBarStyle { return copyWith( backgroundColor: other.backgroundColor, + floatingBackgroundColor: other.floatingBackgroundColor, padding: other.padding, spacing: other.spacing, titleTextStyle: @@ -186,6 +195,7 @@ mixin _$StreamAppBarStyle { final _other = (other as StreamAppBarStyle); return _other.backgroundColor == _this.backgroundColor && + _other.floatingBackgroundColor == _this.floatingBackgroundColor && _other.padding == _this.padding && _other.spacing == _this.spacing && _other.titleTextStyle == _this.titleTextStyle && @@ -201,6 +211,7 @@ mixin _$StreamAppBarStyle { return Object.hash( runtimeType, _this.backgroundColor, + _this.floatingBackgroundColor, _this.padding, _this.spacing, _this.titleTextStyle, From 86e911fe08506d737443f1ff8d0393a11eaa48c7 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 27 May 2026 14:15:42 +0200 Subject: [PATCH 02/35] Add snapshot test and gallery update --- .../components/toolbar/stream_app_bar.dart | 138 ++++++++-- .../components/toolbar/stream_app_bar.dart | 1 - .../toolbar/stream_app_bar_golden_test.dart | 253 ++++++++++++++++++ .../toolbar/stream_app_bar_test.dart | 77 ++++++ 4 files changed, 445 insertions(+), 24 deletions(-) create mode 100644 packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart index 96963298..42dbf796 100644 --- a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart +++ b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart @@ -53,31 +53,63 @@ Widget buildStreamAppBarPlayground(BuildContext context) { description: 'Horizontal gap between leading, heading, and trailing.', ); - return Align( - alignment: Alignment.topCenter, - child: StreamAppBar( - style: StreamAppBarStyle( - padding: EdgeInsets.all(padding), - spacing: spacing, - ), - leading: showLeading - ? StreamButton.icon( - icon: Icon(context.streamIcons.chevronLeft), - style: StreamButtonStyle.secondary, - type: StreamButtonType.ghost, - onPressed: () {}, - ) - : null, - title: (title != null && title.isNotEmpty) ? Text(title) : null, - subtitle: (subtitle != null && subtitle.isNotEmpty) ? Text(subtitle) : null, - trailing: showTrailing - ? StreamButton.icon( - icon: Icon(context.streamIcons.plus), - onPressed: () {}, - ) - : null, + final floating = context.knobs.boolean( + label: 'Floating', + initialValue: false, + description: + 'When true, the app bar floats above content with a gradient fade ' + 'instead of a solid background and a bottom border.', + ); + + final colorScheme = context.streamColorScheme; + + Widget bar = StreamAppBar( + primary: false, + floating: floating, + style: StreamAppBarStyle( + padding: EdgeInsets.all(padding), + spacing: spacing, ), + leading: showLeading + ? StreamButton.icon( + icon: Icon(context.streamIcons.chevronLeft), + style: StreamButtonStyle.secondary, + type: floating ? StreamButtonType.outline : StreamButtonType.ghost, + isFloating: floating, + onPressed: () {}, + ) + : null, + title: (title != null && title.isNotEmpty) ? Text(title) : null, + subtitle: (subtitle != null && subtitle.isNotEmpty) ? Text(subtitle) : null, + trailing: showTrailing + ? StreamButton.icon( + icon: Icon(context.streamIcons.plus), + isFloating: floating, + onPressed: () {}, + ) + : null, ); + + if (floating) { + return Stack( + children: [ + Positioned.fill( + child: ColoredBox( + color: colorScheme.backgroundApp, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 32), + decoration: BoxDecoration( + color: colorScheme.accentPrimary, + ), + ), + ), + ), + Align(alignment: Alignment.topCenter, child: bar), + ], + ); + } + + return Align(alignment: Alignment.topCenter, child: bar); } // ============================================================================= @@ -227,6 +259,31 @@ Widget buildStreamAppBarShowcase(BuildContext context) { ), ), SizedBox(height: spacing.md), + _AppBarExample( + label: 'Floating — gradient fade over content', + bar: _FloatingAppBarPreview( + bar: StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + leading: StreamButton.icon( + icon: Icon(context.streamIcons.chevronLeft), + style: StreamButtonStyle.secondary, + type: StreamButtonType.outline, + isFloating: true, + onPressed: () {}, + ), + title: const Text('Group chat'), + subtitle: const Text('5 members, 3 online'), + trailing: StreamButton.icon( + icon: Icon(context.streamIcons.plus), + isFloating: true, + onPressed: () {}, + ), + ), + ), + ), + SizedBox(height: spacing.md), const _AutoImplyLeadingDemo(), ], ), @@ -303,6 +360,41 @@ class _AutoImplyLeadingDemo extends StatelessWidget { } } +/// Renders a floating [StreamAppBar] over a simulated gradient background so +/// the fade effect is clearly visible in the Showcase. +class _FloatingAppBarPreview extends StatelessWidget { + const _FloatingAppBarPreview({required this.bar}); + + final Widget bar; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + return SizedBox( + height: kStreamToolbarHeight * 2, + child: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + colorScheme.accentPrimary.withAlpha(0x40), + colorScheme.backgroundApp, + ], + ), + ), + ), + ), + Positioned(top: 0, left: 0, right: 0, child: bar), + ], + ), + ); + } +} + class _AppBarExample extends StatelessWidget { const _AppBarExample({required this.label, required this.bar}); diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 5d32e216..7dc6356b 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -325,7 +325,6 @@ class DefaultStreamAppBar extends StatelessWidget { gradient: props.floating ? _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor) : null, - backgroundBlendMode: BlendMode.screen, border: props.floating ? null : Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), ), child: bar, diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart new file mode 100644 index 00000000..65be76e7 --- /dev/null +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart @@ -0,0 +1,253 @@ +import 'package:alchemist/alchemist.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/stream_core_flutter.dart'; + +const _kBarWidth = 390.0; + +void main() { + group('StreamAppBar Golden Tests', () { + goldenTest( + 'renders light theme variants', + fileName: 'stream_app_bar_light', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'title only', + child: _buildAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + title: const Text('Details'), + ), + ), + ), + GoldenTestScenario( + name: 'leading and trailing', + child: _buildAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + leading: StreamButton.icon( + icon: const Icon(Icons.chevron_left), + style: StreamButtonStyle.secondary, + type: StreamButtonType.ghost, + onPressed: () {}, + ), + title: const Text('Group chat'), + trailing: StreamButton.icon( + icon: const Icon(Icons.add), + onPressed: () {}, + ), + ), + ), + ), + GoldenTestScenario( + name: 'leading only', + child: _buildAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + leading: StreamButton.icon( + icon: const Icon(Icons.chevron_left), + style: StreamButtonStyle.secondary, + type: StreamButtonType.ghost, + onPressed: () {}, + ), + title: const Text('Details'), + ), + ), + ), + ], + ), + ); + + goldenTest( + 'renders dark theme variants', + fileName: 'stream_app_bar_dark', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'title only', + child: _buildAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + title: const Text('Details'), + ), + brightness: Brightness.dark, + ), + ), + GoldenTestScenario( + name: 'leading and trailing', + child: _buildAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + leading: StreamButton.icon( + icon: const Icon(Icons.chevron_left), + style: StreamButtonStyle.secondary, + type: StreamButtonType.ghost, + onPressed: () {}, + ), + title: const Text('Group chat'), + trailing: StreamButton.icon( + icon: const Icon(Icons.add), + onPressed: () {}, + ), + ), + brightness: Brightness.dark, + ), + ), + ], + ), + ); + + goldenTest( + 'renders light theme floating variants', + fileName: 'stream_app_bar_floating_light', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'title only', + child: _buildFloatingAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + title: const Text('Details'), + ), + ), + ), + GoldenTestScenario( + name: 'leading and trailing', + child: _buildFloatingAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + leading: StreamButton.icon( + icon: const Icon(Icons.chevron_left), + style: StreamButtonStyle.secondary, + type: StreamButtonType.outline, + isFloating: true, + onPressed: () {}, + ), + title: const Text('Group chat'), + trailing: StreamButton.icon( + icon: const Icon(Icons.add), + isFloating: true, + onPressed: () {}, + ), + ), + ), + ), + ], + ), + ); + + goldenTest( + 'renders dark theme floating variants', + fileName: 'stream_app_bar_floating_dark', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'title only', + child: _buildFloatingAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + title: const Text('Details'), + ), + brightness: Brightness.dark, + ), + ), + GoldenTestScenario( + name: 'leading and trailing', + child: _buildFloatingAppBarInTheme( + StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + leading: StreamButton.icon( + icon: const Icon(Icons.chevron_left), + style: StreamButtonStyle.secondary, + type: StreamButtonType.outline, + isFloating: true, + onPressed: () {}, + ), + title: const Text('Group chat'), + trailing: StreamButton.icon( + icon: const Icon(Icons.add), + isFloating: true, + onPressed: () {}, + ), + ), + brightness: Brightness.dark, + ), + ), + ], + ), + ); + }); +} + +Widget _buildAppBarInTheme( + Widget appBar, { + Brightness brightness = Brightness.light, +}) { + final streamTheme = StreamTheme(brightness: brightness); + return Theme( + data: ThemeData( + brightness: brightness, + extensions: [streamTheme], + ), + child: Builder( + builder: (context) => Material( + color: StreamTheme.of(context).colorScheme.backgroundApp, + child: SizedBox(width: _kBarWidth, child: appBar), + ), + ), + ); +} + +/// Wraps a floating [StreamAppBar] over a content background so the gradient +/// fade is clearly visible in the snapshot. +Widget _buildFloatingAppBarInTheme( + Widget appBar, { + Brightness brightness = Brightness.light, +}) { + final streamTheme = StreamTheme(brightness: brightness); + return Theme( + data: ThemeData( + brightness: brightness, + extensions: [streamTheme], + ), + child: Builder( + builder: (context) { + final colorScheme = StreamTheme.of(context).colorScheme; + return SizedBox( + width: _kBarWidth, + height: kStreamToolbarHeight * 2, + child: Stack( + children: [ + // Simulated content behind the floating bar. + Positioned.fill( + child: ColoredBox( + color: colorScheme.backgroundApp, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 32), + decoration: BoxDecoration( + color: colorScheme.accentPrimary, + ), + ), + ), + ), + Positioned(top: 0, left: 0, right: 0, child: appBar), + ], + ), + ); + }, + ), + ); +} diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart index 64863a5a..26aacc1a 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart @@ -82,6 +82,80 @@ void main() { }); }); + group('StreamAppBar floating', () { + testWidgets('floating: false uses solid background and bottom border', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + Scaffold( + appBar: StreamAppBar( + automaticallyImplyLeading: false, + title: const Text('Title'), + ), + ), + ), + ); + + final decoratedBox = tester.widget( + find + .descendant( + of: find.byType(StreamAppBar), + matching: find.byType(DecoratedBox), + ) + .first, + ); + final decoration = decoratedBox.decoration as BoxDecoration; + expect(decoration.color, isNotNull); + expect(decoration.gradient, isNull); + expect(decoration.border, isNotNull); + }); + + testWidgets('floating: true uses gradient and no bottom border', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + Scaffold( + body: StreamAppBar( + automaticallyImplyLeading: false, + primary: false, + floating: true, + title: const Text('Title'), + ), + ), + ), + ); + + final decoratedBox = tester.widget( + find + .descendant( + of: find.byType(StreamAppBar), + matching: find.byType(DecoratedBox), + ) + .first, + ); + final decoration = decoratedBox.decoration as BoxDecoration; + expect(decoration.color, isNull); + expect(decoration.gradient, isA()); + expect(decoration.border, isNull); + }); + + testWidgets('floating: true uses outline button type for auto-implied leading', (tester) async { + await tester.pumpWidget(_withStreamTheme(const _LauncherScreen(floating: true))); + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + + final button = tester.widget(find.byType(StreamButton)); + expect(button.props.type, equals(StreamButtonType.outline)); + }); + + testWidgets('floating: false uses ghost button type for auto-implied leading', (tester) async { + await tester.pumpWidget(_withStreamTheme(const _LauncherScreen())); + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + + final button = tester.widget(find.byType(StreamButton)); + expect(button.props.type, equals(StreamButtonType.ghost)); + }); + }); + group('StreamAppBar style precedence', () { testWidgets( 'props.style > theme.style > token defaults (three-level merge)', @@ -155,11 +229,13 @@ class _LauncherScreen extends StatelessWidget { this.customLeading = false, this.implyLeading = true, this.fullscreenDialog = false, + this.floating = false, }); final bool customLeading; final bool implyLeading; final bool fullscreenDialog; + final bool floating; @override Widget build(BuildContext context) { @@ -174,6 +250,7 @@ class _LauncherScreen extends StatelessWidget { builder: (_) => Scaffold( appBar: StreamAppBar( automaticallyImplyLeading: implyLeading, + floating: floating, leading: customLeading ? const SizedBox(key: ValueKey('custom-leading'), width: 40, height: 40) : null, From b2e4352fcff1a769bec4256a12e9517a8f274a9b Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 28 May 2026 15:20:47 +0200 Subject: [PATCH 03/35] Add theming for floating config --- .../components/toolbar/stream_app_bar.dart | 41 ++++++++++++------- .../stream_core_flutter/lib/src/theme.dart | 1 + .../lib/src/theme/stream_app_style.dart | 25 +++++++++++ .../lib/src/theme/stream_theme.dart | 9 ++++ .../lib/src/theme/stream_theme.g.theme.dart | 5 +++ 5 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 packages/stream_core_flutter/lib/src/theme/stream_app_style.dart diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 7dc6356b..d79b768e 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -6,6 +6,7 @@ import '../../theme/components/stream_button_theme.dart'; import '../../theme/primitives/stream_spacing.dart'; import '../../theme/semantics/stream_color_scheme.dart'; import '../../theme/semantics/stream_text_theme.dart'; +import '../../theme/stream_app_style.dart'; import '../../theme/stream_theme_extensions.dart'; import '../buttons/stream_button.dart'; import 'stream_toolbar.dart'; @@ -72,7 +73,7 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { Widget? trailing, bool primary = true, StreamAppBarStyle? style, - bool floating = false, + AppBarBehavior? appBarBehavior, }) : props = .new( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, @@ -81,7 +82,7 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { trailing: trailing, primary: primary, style: style, - floating: floating, + appBarBehavior: appBarBehavior, ); /// The properties that configure this app bar. @@ -117,7 +118,7 @@ class StreamAppBarProps { this.trailing, this.primary = true, this.style, - this.floating = false, + this.appBarBehavior, }); /// A widget to display before the [title]. @@ -179,7 +180,7 @@ class StreamAppBarProps { /// Whether this app bar is floating. /// /// When true, the app bar is floating and will be displayed above the content. - final bool floating; + final AppBarBehavior? appBarBehavior; } /// The default implementation of [StreamAppBar]. @@ -213,9 +214,11 @@ class DefaultStreamAppBar extends StatelessWidget { final style = context.streamAppBarTheme.style?.merge(props.style) ?? props.style; final defaults = _StreamAppBarStyleDefaults(context); - final effectiveBackgroundColor = switch (props.floating) { - true => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, - false => style?.backgroundColor ?? defaults.backgroundColor, + final effectiveAppBarBehavior = props.appBarBehavior ?? context.streamTheme.appStyle.appBarBehavior; + + final effectiveBackgroundColor = switch (effectiveAppBarBehavior) { + .floating => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, + .regular => style?.backgroundColor ?? defaults.backgroundColor, }; final effectivePadding = style?.padding ?? defaults.padding; final effectiveSpacing = style?.spacing ?? defaults.spacing; @@ -240,8 +243,11 @@ class DefaultStreamAppBar extends StatelessWidget { }; final useCloseIcon = parentRoute is PageRoute && parentRoute.fullscreenDialog; leading = StreamButton.icon( - type: props.floating ? .outline : .ghost, - isFloating: props.floating, + type: switch (effectiveAppBarBehavior) { + .floating => .outline, + .regular => .ghost, + }, + isFloating: effectiveAppBarBehavior == .floating, style: .secondary, icon: Icon(useCloseIcon ? icons.xmark : backIcon), onPressed: Navigator.of(context).maybePop, @@ -321,11 +327,18 @@ class DefaultStreamAppBar extends StatelessWidget { // not a configurable divider. return DecoratedBox( decoration: BoxDecoration( - color: props.floating ? null : effectiveBackgroundColor, - gradient: props.floating - ? _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor) - : null, - border: props.floating ? null : Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), + color: switch (effectiveAppBarBehavior) { + .floating => null, + .regular => effectiveBackgroundColor, + }, + gradient: switch (effectiveAppBarBehavior) { + .floating => _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor), + .regular => null, + }, + border: switch (effectiveAppBarBehavior) { + .floating => null, + .regular => Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), + }, ), child: bar, ); diff --git a/packages/stream_core_flutter/lib/src/theme.dart b/packages/stream_core_flutter/lib/src/theme.dart index e2c47825..6e813b46 100644 --- a/packages/stream_core_flutter/lib/src/theme.dart +++ b/packages/stream_core_flutter/lib/src/theme.dart @@ -53,6 +53,7 @@ export 'theme/semantics/stream_box_shadow.dart'; export 'theme/semantics/stream_color_scheme.dart'; export 'theme/semantics/stream_text_theme.dart'; +export 'theme/stream_app_style.dart'; export 'theme/stream_theme.dart'; export 'theme/stream_theme_extensions.dart'; export 'theme/widget_state_utils.dart'; diff --git a/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart new file mode 100644 index 00000000..3cf29d7e --- /dev/null +++ b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart @@ -0,0 +1,25 @@ +class StreamAppStyle { + const StreamAppStyle({ + this.composerLocation = ComposerLocation.docked, + this.appBarBehavior = AppBarBehavior.regular, + }); + + const StreamAppStyle.regular() : composerLocation = ComposerLocation.docked, appBarBehavior = AppBarBehavior.regular; + + const StreamAppStyle.floating() + : composerLocation = ComposerLocation.floating, + appBarBehavior = AppBarBehavior.floating; + + final AppBarBehavior appBarBehavior; + final ComposerLocation composerLocation; +} + +enum ComposerLocation { + floating, + docked, +} + +enum AppBarBehavior { + regular, + floating, +} diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart index 05960c99..cfc173b5 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart @@ -47,6 +47,7 @@ import 'primitives/stream_typography.dart'; import 'semantics/stream_box_shadow.dart'; import 'semantics/stream_color_scheme.dart'; import 'semantics/stream_text_theme.dart'; +import 'stream_app_style.dart'; part 'stream_theme.g.theme.dart'; @@ -106,6 +107,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { factory StreamTheme({ Brightness brightness = .light, TargetPlatform? platform, + StreamAppStyle? appStyle, StreamIcons? icons, StreamRadius? radius, StreamSpacing? spacing, @@ -166,6 +168,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { boxShadow ??= isDark ? StreamBoxShadow.dark() : StreamBoxShadow.light(); // Components + appStyle ??= const StreamAppStyle.regular(); appBarTheme ??= const StreamAppBarThemeData(); audioWaveformTheme ??= const StreamAudioWaveformThemeData(); avatarTheme ??= const StreamAvatarThemeData(); @@ -205,6 +208,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { return .raw( brightness: brightness, + appStyle: appStyle, icons: icons, radius: radius, spacing: spacing, @@ -265,6 +269,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { const StreamTheme.raw({ required this.brightness, + required this.appStyle, required this.icons, required this.radius, required this.spacing, @@ -342,6 +347,9 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { /// The brightness of this theme. final Brightness brightness; + /// The app style for this theme. + final StreamAppStyle appStyle; + /// The icons for this theme. final StreamIcons icons; @@ -499,6 +507,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { return StreamTheme.raw( brightness: brightness, + appStyle: appStyle, icons: icons, radius: radius, spacing: spacing, diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart index 09e93405..f906ee3e 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart @@ -13,6 +13,7 @@ mixin _$StreamTheme on ThemeExtension { @override ThemeExtension copyWith({ Brightness? brightness, + StreamAppStyle? appStyle, StreamIcons? icons, StreamRadius? radius, StreamSpacing? spacing, @@ -67,6 +68,7 @@ mixin _$StreamTheme on ThemeExtension { return StreamTheme.raw( brightness: brightness ?? _this.brightness, + appStyle: appStyle ?? _this.appStyle, icons: icons ?? _this.icons, radius: radius ?? _this.radius, spacing: spacing ?? _this.spacing, @@ -144,6 +146,7 @@ mixin _$StreamTheme on ThemeExtension { return StreamTheme.raw( brightness: t < 0.5 ? _this.brightness : other.brightness, + appStyle: t < 0.5 ? _this.appStyle : other.appStyle, icons: StreamIcons.lerp(_this.icons, other.icons, t)!, radius: StreamRadius.lerp(_this.radius, other.radius, t)!, spacing: StreamSpacing.lerp(_this.spacing, other.spacing, t)!, @@ -356,6 +359,7 @@ mixin _$StreamTheme on ThemeExtension { final _other = (other as StreamTheme); return _other.brightness == _this.brightness && + _other.appStyle == _this.appStyle && _other.icons == _this.icons && _other.radius == _this.radius && _other.spacing == _this.spacing && @@ -415,6 +419,7 @@ mixin _$StreamTheme on ThemeExtension { return Object.hashAll([ runtimeType, _this.brightness, + _this.appStyle, _this.icons, _this.radius, _this.spacing, From 583b7f74e78a61d52555f21da3fbb79e493f3aeb Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 29 May 2026 09:21:53 +0200 Subject: [PATCH 04/35] Streamscaffold --- .../lib/src/components.dart | 1 + .../components/scaffold/stream_scaffold.dart | 343 ++++++++++++++++++ .../lib/src/theme/stream_app_style.dart | 15 +- 3 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart diff --git a/packages/stream_core_flutter/lib/src/components.dart b/packages/stream_core_flutter/lib/src/components.dart index 043f1f51..f6a116fd 100644 --- a/packages/stream_core_flutter/lib/src/components.dart +++ b/packages/stream_core_flutter/lib/src/components.dart @@ -68,6 +68,7 @@ export 'components/message_layout/stream_message_list_kind.dart'; export 'components/message_layout/stream_message_stack_position.dart'; export 'components/reaction/stream_reaction_picker.dart' hide DefaultStreamReactionPicker; export 'components/reaction/stream_reactions.dart' hide DefaultStreamReactions; +export 'components/scaffold/stream_scaffold.dart'; export 'components/sheet/stream_sheet.dart'; export 'components/snackbar/stream_snackbar.dart' hide DefaultStreamSnackbar; export 'components/toolbar/stream_app_bar.dart' hide DefaultStreamAppBar; diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart new file mode 100644 index 00000000..d2d14b3d --- /dev/null +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -0,0 +1,343 @@ +import 'package:flutter/material.dart'; + +import '../../theme/stream_app_style.dart'; +import '../../theme/stream_theme_extensions.dart'; + +// --------------------------------------------------------------------------- +// InheritedWidget +// --------------------------------------------------------------------------- + +/// Provides the effective top and bottom padding introduced by +/// [StreamScaffold] to its descendants. +/// +/// When the scaffold's `appBar` is floating, [topPadding] equals the app-bar +/// height plus the system safe-area inset so that scrollable bodies can inset +/// their content below the bar without being clipped. When the `bottom` slot +/// is floating, [bottomPadding] equals the measured height of that widget so +/// content clears it. +/// +/// Read the values with [StreamScaffoldInsets.of] or +/// [StreamScaffoldInsets.maybeOf]: +/// +/// ```dart +/// final insets = StreamScaffoldInsets.of(context); +/// StreamMessageListView( +/// topPadding: insets.topPadding, +/// bottomPadding: insets.bottomPadding, +/// ) +/// ``` +class StreamScaffoldInsets extends InheritedWidget { + /// Creates an insets notification for the given [topPadding] and + /// [bottomPadding]. + const StreamScaffoldInsets({ + super.key, + required this.topPadding, + required this.bottomPadding, + required super.child, + }) : assert(topPadding >= 0, 'topPadding must be non-negative'), + assert(bottomPadding >= 0, 'bottomPadding must be non-negative'); + + /// The vertical space (in logical pixels) occupied by the floating app bar + /// at the top, including the system status-bar inset. + /// + /// `0.0` when the app bar is regular (not floating) or absent. + final double topPadding; + + /// The vertical space (in logical pixels) occupied by the floating bottom + /// widget, including any system home-indicator inset. + /// + /// `0.0` when the bottom widget is regular (not floating) or absent. + final double bottomPadding; + + /// Returns the [StreamScaffoldInsets] from the closest ancestor, asserting + /// that one exists. + static StreamScaffoldInsets of(BuildContext context) { + final result = context.dependOnInheritedWidgetOfExactType(); + assert(result != null, 'No StreamScaffoldInsets found in widget tree'); + return result!; + } + + /// Returns the [StreamScaffoldInsets] from the closest ancestor, or `null` + /// when none is present. + static StreamScaffoldInsets? maybeOf(BuildContext context) => + context.dependOnInheritedWidgetOfExactType(); + + @override + bool updateShouldNotify(StreamScaffoldInsets old) => + topPadding != old.topPadding || bottomPadding != old.bottomPadding; +} + +// --------------------------------------------------------------------------- +// Main widget +// --------------------------------------------------------------------------- + +/// A full-page scaffold for Stream surfaces that supports both regular and +/// floating app-bar / bottom-bar layouts. +/// +/// [StreamScaffold] composes three slots — [appBar], [body], and [bottom] — +/// and injects an [StreamScaffoldInsets] into the widget tree so that scrollable +/// bodies can respect the visual extents of floating bars without knowing about +/// the layout directly. +/// +/// ## Floating vs. regular +/// +/// The behaviour of each slot is controlled by [StreamAppStyle]: +/// +/// * `AppBarBehavior.floating` — the body extends *behind* the app bar; +/// [StreamScaffoldInsets.topPadding] is set to the bar height plus the +/// system status-bar inset so the body can add its own inset. +/// * `BottomBarBehavior.floating` — the body extends *behind* the bottom +/// widget; [StreamScaffoldInsets.bottomPadding] equals the measured height of +/// that widget. +/// * `regular` for either slot — no overlap; the slot occupies its own space +/// and the corresponding inset is `0.0`. +/// +/// Per-instance [appBarBehavior] / [bottomBarBehavior] override the ambient +/// [StreamAppStyle] for this scaffold only. +/// +/// ## Drawer support +/// +/// [drawer] is forwarded to the underlying [Scaffold] so that widgets in +/// [appBar] (e.g. `StreamChannelListHeader`) can find the drawer via +/// `Scaffold.maybeOf(context)?.openDrawer()`. +/// +/// ## InheritedWidget access +/// +/// ```dart +/// // Inside body: +/// final insets = StreamScaffoldInsets.of(context); +/// StreamMessageListView( +/// topPadding: insets.topPadding, +/// bottomPadding: insets.bottomPadding, +/// ); +/// ``` +/// +/// See also: +/// +/// * [StreamScaffoldInsets], the inherited widget that carries the inset +/// values. +/// * [StreamAppBar], the standard floating/regular app bar. +/// * [StreamBottomAppBar], the standard toolbar for the bottom slot. +class StreamScaffold extends StatelessWidget { + /// Creates a Stream scaffold. + const StreamScaffold({ + super.key, + this.appBar, + required this.body, + this.bottom, + this.drawer, + this.endDrawer, + this.appBarBehavior, + this.bottomBarBehavior, + this.backgroundColor, + this.resizeToAvoidBottomInset = true, + }); + + /// An optional app bar displayed at the top of the scaffold. + /// + /// Must implement [PreferredSizeWidget] so the scaffold can read the height + /// for inset calculations. + final PreferredSizeWidget? appBar; + + /// The primary content of the scaffold. + /// + /// [StreamScaffoldInsets] is injected into this subtree so descendants can + /// read the effective top and bottom insets. + final Widget body; + + /// An optional widget displayed at the bottom of the scaffold. + /// + /// When [bottomBarBehavior] is [BottomBarBehavior.floating] this widget + /// overlaps the body; otherwise it sits below it (equivalent to + /// [Scaffold.bottomNavigationBar]). + final Widget? bottom; + + /// A panel displayed to the side of the [body], often hidden on mobile + /// devices. Swipes in from either [TextDirection.ltr] start side or + /// [TextDirection.rtl] start side. + /// + /// Forwarded directly to the underlying [Scaffold]. + final Widget? drawer; + + /// A panel displayed to the opposite side of the body from the [drawer]. + /// + /// Forwarded directly to the underlying [Scaffold]. + final Widget? endDrawer; + + /// Per-instance override for the app-bar floating behaviour. + /// + /// When null the value is read from the ambient [StreamAppStyle]. + final AppBarBehavior? appBarBehavior; + + /// Per-instance override for the bottom-bar floating behaviour. + /// + /// When null the value is read from the ambient [StreamAppStyle]. + final BottomBarBehavior? bottomBarBehavior; + + /// Background color of the scaffold. + /// + /// Defaults to [Scaffold.backgroundColor]. + final Color? backgroundColor; + + /// Whether the scaffold should resize to avoid the on-screen keyboard. + /// + /// Defaults to `true`. + final bool resizeToAvoidBottomInset; + + @override + Widget build(BuildContext context) { + final appStyle = context.streamTheme.appStyle; + final effectiveAppBarBehavior = appBarBehavior ?? appStyle.appBarBehavior; + final effectiveBottomBarBehavior = bottomBarBehavior ?? appStyle.bottomBarBehavior; + + final appBarFloating = effectiveAppBarBehavior == AppBarBehavior.floating; + final bottomFloating = effectiveBottomBarBehavior == BottomBarBehavior.floating && bottom != null; + + final topInset = appBarFloating + ? (appBar?.preferredSize.height ?? 0) + MediaQuery.paddingOf(context).top + : 0.0; + + // When neither slot is floating, use a plain Scaffold for maximum + // compatibility (e.g. keyboard avoidance, Scaffold.of, etc.). + if (!appBarFloating && !bottomFloating) { + return Scaffold( + backgroundColor: backgroundColor, + resizeToAvoidBottomInset: resizeToAvoidBottomInset, + appBar: appBar, + drawer: drawer, + endDrawer: endDrawer, + bottomNavigationBar: bottom, + body: StreamScaffoldInsets( + topPadding: 0, + bottomPadding: 0, + child: body, + ), + ); + } + + return Scaffold( + backgroundColor: backgroundColor, + resizeToAvoidBottomInset: resizeToAvoidBottomInset, + // The appBar always goes in the Scaffold's standard slot. + // extendBodyBehindAppBar controls whether the body overlaps it (floating) + // or sits below it (regular). Never drop it from the slot. + appBar: appBar, + drawer: drawer, + endDrawer: endDrawer, + extendBodyBehindAppBar: appBarFloating, + extendBody: bottomFloating, + // In regular-bottom mode, slot the bottom into the Scaffold normally. + bottomNavigationBar: bottomFloating ? null : bottom, + body: _StreamScaffoldBody( + topInset: topInset, + bottom: bottomFloating ? bottom : null, + child: body, + ), + ); + } +} + +// --------------------------------------------------------------------------- +// Custom layout +// --------------------------------------------------------------------------- + +/// Layout slot identifiers used by [_StreamScaffoldBodyDelegate]. +enum _Slot { body, bottom } + +/// Custom [BoxConstraints] that carries the measured [bottomHeight] so a +/// [LayoutBuilder] inside the body can read it synchronously within the same +/// layout pass. +/// +/// [==] and [hashCode] are overridden to trigger a child re-layout whenever +/// [bottomHeight] changes, even when the outer size constraints are unchanged. +class _BodyBoxConstraints extends BoxConstraints { + const _BodyBoxConstraints({ + super.maxWidth, + super.maxHeight, + required this.bottomHeight, + }) : assert(bottomHeight >= 0, 'bottomHeight must be non-negative'); + + /// The measured height of the floating bottom slot. + final double bottomHeight; + + @override + bool operator ==(Object other) { + if (super != other) return false; + return other is _BodyBoxConstraints && other.bottomHeight == bottomHeight; + } + + @override + int get hashCode => Object.hash(super.hashCode, bottomHeight); +} + +/// Measures the [bottom] slot first, then gives the [body] the full available +/// size annotated with the bottom height via [_BodyBoxConstraints]. +class _StreamScaffoldBodyDelegate extends MultiChildLayoutDelegate { + _StreamScaffoldBodyDelegate({required this.hasBottom}); + + final bool hasBottom; + + @override + void performLayout(Size size) { + double bottomHeight = 0; + if (hasBottom) { + final bottomSize = layoutChild(_Slot.bottom, BoxConstraints.loose(size)); + bottomHeight = bottomSize.height; + positionChild(_Slot.bottom, Offset(0, size.height - bottomHeight)); + } + + layoutChild( + _Slot.body, + _BodyBoxConstraints( + maxWidth: size.width, + maxHeight: size.height, + bottomHeight: bottomHeight, + ), + ); + positionChild(_Slot.body, Offset.zero); + } + + @override + bool shouldRelayout(_StreamScaffoldBodyDelegate oldDelegate) => hasBottom != oldDelegate.hasBottom; +} + +/// Wraps the user-supplied [body] and an optional floating [bottom] inside a +/// [CustomMultiChildLayout] that publishes the measured bottom height into +/// [StreamScaffoldInsets] in a single layout pass. +class _StreamScaffoldBody extends StatelessWidget { + const _StreamScaffoldBody({ + required this.topInset, + required this.bottom, + required this.child, + }); + + final double topInset; + final Widget? bottom; + final Widget child; + + @override + Widget build(BuildContext context) { + final hasBottom = bottom != null; + + return CustomMultiChildLayout( + delegate: _StreamScaffoldBodyDelegate(hasBottom: hasBottom), + children: [ + LayoutId( + id: _Slot.body, + child: LayoutBuilder( + builder: (context, constraints) { + final bottomHeight = + constraints is _BodyBoxConstraints ? constraints.bottomHeight : 0.0; + return StreamScaffoldInsets( + topPadding: topInset, + bottomPadding: bottomHeight, + child: child, + ); + }, + ), + ), + if (hasBottom) LayoutId(id: _Slot.bottom, child: bottom!), + ], + ); + } +} diff --git a/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart index 3cf29d7e..7fb64b6f 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart @@ -2,15 +2,21 @@ class StreamAppStyle { const StreamAppStyle({ this.composerLocation = ComposerLocation.docked, this.appBarBehavior = AppBarBehavior.regular, + this.bottomBarBehavior = BottomBarBehavior.regular, }); - const StreamAppStyle.regular() : composerLocation = ComposerLocation.docked, appBarBehavior = AppBarBehavior.regular; + const StreamAppStyle.regular() + : composerLocation = ComposerLocation.docked, + appBarBehavior = AppBarBehavior.regular, + bottomBarBehavior = BottomBarBehavior.regular; const StreamAppStyle.floating() : composerLocation = ComposerLocation.floating, - appBarBehavior = AppBarBehavior.floating; + appBarBehavior = AppBarBehavior.floating, + bottomBarBehavior = BottomBarBehavior.floating; final AppBarBehavior appBarBehavior; + final BottomBarBehavior bottomBarBehavior; final ComposerLocation composerLocation; } @@ -23,3 +29,8 @@ enum AppBarBehavior { regular, floating, } + +enum BottomBarBehavior { + regular, + floating, +} From 84bc87e4a0f2b7fc5a85ec91ef0423e2946c750b Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 29 May 2026 13:15:14 +0200 Subject: [PATCH 05/35] Add `StreamBottomNavBar` item --- .../lib/src/components.dart | 1 + .../toolbar/stream_bottom_nav_bar.dart | 273 ++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart diff --git a/packages/stream_core_flutter/lib/src/components.dart b/packages/stream_core_flutter/lib/src/components.dart index f6a116fd..b5203e52 100644 --- a/packages/stream_core_flutter/lib/src/components.dart +++ b/packages/stream_core_flutter/lib/src/components.dart @@ -73,6 +73,7 @@ export 'components/sheet/stream_sheet.dart'; export 'components/snackbar/stream_snackbar.dart' hide DefaultStreamSnackbar; export 'components/toolbar/stream_app_bar.dart' hide DefaultStreamAppBar; export 'components/toolbar/stream_bottom_app_bar.dart' hide DefaultStreamBottomAppBar; +export 'components/toolbar/stream_bottom_nav_bar.dart'; export 'components/toolbar/stream_sheet_header.dart' hide DefaultStreamSheetHeader; export 'components/toolbar/stream_toolbar.dart'; export 'factory/stream_component_factory.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart new file mode 100644 index 00000000..41463719 --- /dev/null +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -0,0 +1,273 @@ +import 'package:flutter/material.dart'; + +import '../../theme/stream_app_style.dart'; +import '../../theme/stream_theme_extensions.dart'; + +/// A single item in a [StreamBottomNavBar]. +/// +/// Each item has an [icon] and [selectedIcon] widget (the latter is shown +/// when the item is active) and a text [label]. +/// +/// The icon widgets are fully generic — callers are free to wrap them in +/// badge overlays, unread indicators, or any other decorator. +class StreamBottomNavBarItem { + /// Creates a bottom nav bar item. + const StreamBottomNavBarItem({ + required this.icon, + required this.selectedIcon, + required this.label, + }); + + /// The icon displayed when this item is inactive. + final Widget icon; + + /// The icon displayed when this item is active. + final Widget selectedIcon; + + /// The text label shown below the icon. + final String label; +} + +/// A bottom navigation bar for Stream surfaces that automatically adapts +/// between a floating pill style and a regular docked style based on the +/// ambient [BottomBarBehavior] from [StreamAppStyle]. +/// +/// ## Floating style +/// +/// When [StreamAppStyle.bottomBarBehavior] is [BottomBarBehavior.floating], +/// the bar renders as a horizontally padded pill with a rounded background, +/// a subtle box shadow, and a hairline border. It sits above the body content +/// and is typically used with [StreamScaffold]'s floating bottom slot. +/// +/// ## Regular style +/// +/// When [BottomBarBehavior.regular], the bar renders as a standard docked +/// bottom navigation bar using Flutter's [BottomNavigationBar] with Stream +/// colour and typography tokens. A hairline `borderSubtle` top border +/// separates it from the body. +/// +/// ## Behaviour override +/// +/// Pass an explicit [behavior] to override the ambient style for this +/// instance only. +/// +/// {@tool snippet} +/// +/// Basic usage: +/// +/// ```dart +/// StreamBottomNavBar( +/// currentIndex: _currentIndex, +/// onTap: (i) => setState(() => _currentIndex = i), +/// items: const [ +/// StreamBottomNavBarItem( +/// icon: Icon(Icons.chat_bubble_outline), +/// selectedIcon: Icon(Icons.chat_bubble), +/// label: 'Chats', +/// ), +/// StreamBottomNavBarItem( +/// icon: Icon(Icons.bookmark_outline), +/// selectedIcon: Icon(Icons.bookmark), +/// label: 'Saved', +/// ), +/// ], +/// ) +/// ``` +/// {@end-tool} +/// +/// See also: +/// +/// * [StreamBottomNavBarItem], which configures each tab. +/// * [StreamScaffold], which accepts this widget in its `bottom` slot. +/// * [StreamAppStyle], which controls the floating/regular behaviour. +class StreamBottomNavBar extends StatelessWidget { + /// Creates a Stream bottom navigation bar. + const StreamBottomNavBar({ + super.key, + required this.items, + required this.currentIndex, + required this.onTap, + this.behavior, + }) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'); + + /// The list of items to display in the navigation bar. + /// + /// Must contain at least 2 items. + final List items; + + /// The index of the currently selected item. + final int currentIndex; + + /// Called when the user taps a navigation item. + final ValueChanged onTap; + + /// Overrides the ambient [BottomBarBehavior] for this instance only. + /// + /// When null, the value is read from [StreamAppStyle] in the current + /// [StreamTheme]. + final BottomBarBehavior? behavior; + + @override + Widget build(BuildContext context) { + final effectiveBehavior = behavior ?? context.streamTheme.appStyle.bottomBarBehavior; + + if (effectiveBehavior == BottomBarBehavior.floating) { + return _FloatingNavBar( + items: items, + currentIndex: currentIndex, + onTap: onTap, + ); + } + + return _RegularNavBar( + items: items, + currentIndex: currentIndex, + onTap: onTap, + ); + } +} + +// --------------------------------------------------------------------------- +// Floating pill nav bar +// --------------------------------------------------------------------------- + +class _FloatingNavBar extends StatelessWidget { + const _FloatingNavBar({ + required this.items, + required this.currentIndex, + required this.onTap, + }); + + final List items; + final int currentIndex; + final ValueChanged onTap; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + final spacing = context.streamSpacing; + final radius = context.streamRadius; + + return SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.xl), + child: Container( + decoration: BoxDecoration( + color: colorScheme.backgroundElevation1, + borderRadius: BorderRadius.all(radius.max), + boxShadow: context.streamBoxShadow.elevation1, + ), + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.all(radius.max), + border: Border.all(color: colorScheme.borderSubtle), + ), + child: Padding( + padding: EdgeInsets.symmetric(vertical: spacing.xs), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + for (var i = 0; i < items.length; i++) + _FloatingNavBarItem( + item: items[i], + selected: i == currentIndex, + onTap: () => onTap(i), + ), + ], + ), + ), + ), + ), + ); + } +} + +class _FloatingNavBarItem extends StatelessWidget { + const _FloatingNavBarItem({ + required this.item, + required this.selected, + required this.onTap, + }); + + final StreamBottomNavBarItem item; + final bool selected; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final textTheme = context.streamTextTheme; + final colorScheme = context.streamColorScheme; + final spacing = context.streamSpacing; + final color = selected ? colorScheme.textPrimary : colorScheme.textTertiary; + + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: onTap, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.md, vertical: spacing.xxs), + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: spacing.xxxs, + children: [ + IconTheme( + data: IconThemeData(color: color, size: 20), + child: selected ? item.selectedIcon : item.icon, + ), + Text( + item.label, + style: textTheme.metadataEmphasis.copyWith(color: color), + ), + ], + ), + ), + ); + } +} + +// --------------------------------------------------------------------------- +// Regular docked nav bar +// --------------------------------------------------------------------------- + +class _RegularNavBar extends StatelessWidget { + const _RegularNavBar({ + required this.items, + required this.currentIndex, + required this.onTap, + }); + + final List items; + final int currentIndex; + final ValueChanged onTap; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + final textTheme = context.streamTextTheme; + + return DecoratedBox( + decoration: BoxDecoration( + color: colorScheme.backgroundElevation1, + border: Border(top: BorderSide(color: colorScheme.borderSubtle)), + ), + child: BottomNavigationBar( + elevation: 0, + iconSize: 20, + currentIndex: currentIndex, + type: BottomNavigationBarType.fixed, + selectedItemColor: colorScheme.textPrimary, + unselectedItemColor: colorScheme.textTertiary, + backgroundColor: Colors.transparent, + selectedLabelStyle: textTheme.metadataEmphasis, + unselectedLabelStyle: textTheme.metadataEmphasis, + onTap: onTap, + items: items.map((item) { + return BottomNavigationBarItem( + icon: item.icon, + activeIcon: item.selectedIcon, + label: item.label, + ); + }).toList(), + ), + ); + } +} From a17dfdae530391d7f863c3a61863f76a191f0dd8 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Tue, 9 Jun 2026 15:43:50 +0200 Subject: [PATCH 06/35] fix default color scaffold --- .../components/scaffold/stream_scaffold.dart | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart index d2d14b3d..4dcbef4e 100644 --- a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../theme/semantics/stream_color_scheme.dart'; import '../../theme/stream_app_style.dart'; import '../../theme/stream_theme_extensions.dart'; @@ -34,8 +35,8 @@ class StreamScaffoldInsets extends InheritedWidget { required this.topPadding, required this.bottomPadding, required super.child, - }) : assert(topPadding >= 0, 'topPadding must be non-negative'), - assert(bottomPadding >= 0, 'bottomPadding must be non-negative'); + }) : assert(topPadding >= 0, 'topPadding must be non-negative'), + assert(bottomPadding >= 0, 'bottomPadding must be non-negative'); /// The vertical space (in logical pixels) occupied by the floating app bar /// at the top, including the system status-bar inset. @@ -176,7 +177,7 @@ class StreamScaffold extends StatelessWidget { /// Background color of the scaffold. /// - /// Defaults to [Scaffold.backgroundColor]. + /// Defaults to [StreamColorScheme.backgroundApp]. final Color? backgroundColor; /// Whether the scaffold should resize to avoid the on-screen keyboard. @@ -189,19 +190,18 @@ class StreamScaffold extends StatelessWidget { final appStyle = context.streamTheme.appStyle; final effectiveAppBarBehavior = appBarBehavior ?? appStyle.appBarBehavior; final effectiveBottomBarBehavior = bottomBarBehavior ?? appStyle.bottomBarBehavior; + final effectiveBackgroundColor = backgroundColor ?? context.streamColorScheme.backgroundApp; final appBarFloating = effectiveAppBarBehavior == AppBarBehavior.floating; final bottomFloating = effectiveBottomBarBehavior == BottomBarBehavior.floating && bottom != null; - final topInset = appBarFloating - ? (appBar?.preferredSize.height ?? 0) + MediaQuery.paddingOf(context).top - : 0.0; + final topInset = appBarFloating ? (appBar?.preferredSize.height ?? 0) + MediaQuery.paddingOf(context).top : 0.0; // When neither slot is floating, use a plain Scaffold for maximum // compatibility (e.g. keyboard avoidance, Scaffold.of, etc.). if (!appBarFloating && !bottomFloating) { return Scaffold( - backgroundColor: backgroundColor, + backgroundColor: effectiveBackgroundColor, resizeToAvoidBottomInset: resizeToAvoidBottomInset, appBar: appBar, drawer: drawer, @@ -216,7 +216,7 @@ class StreamScaffold extends StatelessWidget { } return Scaffold( - backgroundColor: backgroundColor, + backgroundColor: effectiveBackgroundColor, resizeToAvoidBottomInset: resizeToAvoidBottomInset, // The appBar always goes in the Scaffold's standard slot. // extendBodyBehindAppBar controls whether the body overlaps it (floating) @@ -326,8 +326,7 @@ class _StreamScaffoldBody extends StatelessWidget { id: _Slot.body, child: LayoutBuilder( builder: (context, constraints) { - final bottomHeight = - constraints is _BodyBoxConstraints ? constraints.bottomHeight : 0.0; + final bottomHeight = constraints is _BodyBoxConstraints ? constraints.bottomHeight : 0.0; return StreamScaffoldInsets( topPadding: topInset, bottomPadding: bottomHeight, From 34ac0db2f71449098f5b7bff7f4e5057b55afdbb Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Tue, 9 Jun 2026 16:25:50 +0200 Subject: [PATCH 07/35] fix layout disabled floating button --- .../lib/src/components/buttons/stream_button.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart b/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart index 14aa4e42..d9f86e69 100644 --- a/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart +++ b/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart @@ -462,7 +462,7 @@ mixin _SharedButtonDefaults on StreamButtonThemeStyle { @override WidgetStateProperty get elevation => WidgetStateProperty.resolveWith((states) { if (!isFloating) return 0; - if (states.contains(WidgetState.disabled)) return 0.0; + if (states.contains(WidgetState.disabled)) return 6.0; if (states.contains(WidgetState.pressed)) return 6.0; if (states.contains(WidgetState.hovered)) return 8.0; return 6.0; @@ -636,8 +636,8 @@ class _SecondaryOutlineDefaults extends StreamButtonThemeStyle with _SharedButto @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); From 693e6dd4c87db682792e0d6342293a413d2a293c Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 12 Jun 2026 10:19:00 +0200 Subject: [PATCH 08/35] Add option for shadow on avatar --- .../lib/components/avatar/stream_avatar.dart | 6 + .../avatar/stream_avatar_group.dart | 6 + .../avatar/stream_avatar_stack.dart | 6 + .../components/toolbar/stream_app_bar.dart | 8 +- .../src/components/avatar/stream_avatar.dart | 16 +- .../avatar/stream_avatar_group.dart | 11 +- .../avatar/stream_avatar_stack.dart | 11 +- .../theme/components/stream_avatar_theme.dart | 7 + .../stream_avatar_theme.g.theme.dart | 8 +- .../avatar/stream_avatar_golden_test.dart | 233 ++++++++++++++++++ .../toolbar/stream_app_bar_golden_test.dart | 8 +- .../toolbar/stream_app_bar_test.dart | 10 +- 12 files changed, 313 insertions(+), 17 deletions(-) create mode 100644 packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart index 84aad6d6..e32ec6a4 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart @@ -35,6 +35,11 @@ Widget buildStreamAvatarPlayground(BuildContext context) { description: 'Whether to show a border around the avatar.', ); + final showShadow = context.knobs.boolean( + label: 'Show Shadow', + description: 'Whether to show a drop shadow around the avatar.', + ); + final initials = context.knobs.string( label: 'Initials', initialValue: 'JD', @@ -46,6 +51,7 @@ Widget buildStreamAvatarPlayground(BuildContext context) { imageUrl: (imageUrl?.isNotEmpty ?? false) ? imageUrl : null, size: size, showBorder: showBorder, + showShadow: showShadow, placeholder: (context) => Text( initials.substring(0, initials.length.clamp(0, 2)).toUpperCase(), ), diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart index 5efe6b21..50db67ee 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart @@ -43,11 +43,17 @@ Widget buildStreamAvatarGroupPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); + final showShadow = context.knobs.boolean( + label: 'Show Shadow', + description: 'Whether to show a drop shadow around each individual avatar.', + ); + final palette = context.streamColorScheme.avatarPalette; return Center( child: StreamAvatarGroup( size: size, + showShadow: showShadow, children: List.generate( avatarCount, (index) => StreamAvatar( diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart index 9d41655e..c8714431 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart @@ -58,6 +58,11 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); + final showShadow = context.knobs.boolean( + label: 'Show Shadow', + description: 'Whether to show a drop shadow around each individual avatar.', + ); + final colorScheme = context.streamColorScheme; final palette = colorScheme.avatarPalette; @@ -66,6 +71,7 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { size: size, overlap: overlap, max: maxAvatars, + showShadow: showShadow, children: [ for (var i = 0; i < avatarCount; i++) StreamAvatar( diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart index 42dbf796..385b92b3 100644 --- a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart +++ b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart @@ -55,17 +55,17 @@ Widget buildStreamAppBarPlayground(BuildContext context) { final floating = context.knobs.boolean( label: 'Floating', - initialValue: false, description: 'When true, the app bar floats above content with a gradient fade ' 'instead of a solid background and a bottom border.', ); + final appBarBehavior = floating ? AppBarBehavior.floating : AppBarBehavior.regular; final colorScheme = context.streamColorScheme; - Widget bar = StreamAppBar( + final Widget bar = StreamAppBar( primary: false, - floating: floating, + appBarBehavior: appBarBehavior, style: StreamAppBarStyle( padding: EdgeInsets.all(padding), spacing: spacing, @@ -265,7 +265,7 @@ Widget buildStreamAppBarShowcase(BuildContext context) { bar: StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, leading: StreamButton.icon( icon: Icon(context.streamIcons.chevronLeft), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index 7b218063..d3514c84 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -85,6 +85,7 @@ class StreamAvatar extends StatelessWidget { Color? backgroundColor, Color? foregroundColor, bool showBorder = true, + bool showShadow = false, }) : props = .new( size: size, imageUrl: imageUrl, @@ -92,6 +93,7 @@ class StreamAvatar extends StatelessWidget { backgroundColor: backgroundColor, foregroundColor: foregroundColor, showBorder: showBorder, + showShadow: showShadow, ); /// The properties that configure this avatar. @@ -123,6 +125,7 @@ class StreamAvatarProps { this.backgroundColor, this.foregroundColor, this.showBorder = true, + this.showShadow = false, }); /// The URL of the avatar image. @@ -164,6 +167,13 @@ class StreamAvatarProps { /// Defaults to true. The border style is determined by /// [StreamAvatarThemeData.border]. final bool showBorder; + + /// Whether to show a drop shadow around the avatar. + /// + /// Defaults to false. The shadow style is determined by + /// [StreamAvatarThemeData.boxShadow], falling back to + /// [StreamBoxShadow.elevation3]. + final bool showShadow; } /// The default implementation of [StreamAvatar]. @@ -192,6 +202,7 @@ class DefaultStreamAvatar extends StatelessWidget { final effectiveBackgroundColor = props.backgroundColor ?? avatarTheme.backgroundColor ?? defaults.backgroundColor; final effectiveForegroundColor = props.foregroundColor ?? avatarTheme.foregroundColor ?? defaults.foregroundColor; final effectiveBorder = avatarTheme.border ?? defaults.border; + final effectiveBoxShadow = avatarTheme.boxShadow ?? (props.showShadow ? defaults.boxShadow : null); final border = props.showBorder ? effectiveBorder : null; final textStyle = _textStyleForSize(effectiveSize, textTheme).copyWith(color: effectiveForegroundColor); @@ -207,7 +218,7 @@ class DefaultStreamAvatar extends StatelessWidget { height: effectiveSize.value, duration: kThemeChangeDuration, foregroundDecoration: BoxDecoration(shape: .circle, border: border), - decoration: BoxDecoration(shape: .circle, color: effectiveBackgroundColor), + decoration: BoxDecoration(shape: .circle, color: effectiveBackgroundColor, boxShadow: effectiveBoxShadow), child: Center( // Need to disable text scaling here so that the text doesn't // escape the avatar when the textScaleFactor is large. @@ -280,6 +291,9 @@ class _StreamAvatarThemeDefaults extends StreamAvatarThemeData { @override BoxBorder get border => Border.all(color: StreamColors.black10); + @override + List get boxShadow => context.streamBoxShadow.elevation3; + @override Color get backgroundColor => _colorScheme.avatarPalette.first.backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart index 4d74e80a..66d14527 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart @@ -91,7 +91,8 @@ class StreamAvatarGroup extends StatelessWidget { super.key, StreamAvatarGroupSize? size, required Iterable children, - }) : props = .new(size: size, children: children); + bool showShadow = false, + }) : props = .new(size: size, children: children, showShadow: showShadow); /// The properties that configure this avatar group. final StreamAvatarGroupProps props; @@ -118,6 +119,7 @@ class StreamAvatarGroupProps { const StreamAvatarGroupProps({ this.size, required this.children, + this.showShadow = false, }); /// The list of avatars to display in the group. @@ -129,6 +131,12 @@ class StreamAvatarGroupProps { /// /// If null, defaults to [StreamAvatarGroupSize.lg]. final StreamAvatarGroupSize? size; + + /// Whether to show a drop shadow around each individual avatar. + /// + /// Defaults to false. The shadow style is determined by + /// [StreamBoxShadow.elevation3]. + final bool showShadow; } /// The default implementation of [StreamAvatarGroup]. @@ -174,6 +182,7 @@ class DefaultStreamAvatarGroup extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), + boxShadow: props.showShadow ? context.streamBoxShadow.elevation3 : null, ), child: StreamBadgeCountTheme( data: StreamBadgeCountThemeData(size: badgeCountSize), diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart index e3705486..0ccae9c7 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart @@ -102,8 +102,9 @@ class StreamAvatarStack extends StatelessWidget { required Iterable children, double overlap = 0.33, int max = 5, + bool showShadow = false, }) : assert(max >= 2, 'max must be at least 2'), - props = .new(size: size, children: children, overlap: overlap, max: max); + props = .new(size: size, children: children, overlap: overlap, max: max, showShadow: showShadow); /// The properties that configure this avatar stack. final StreamAvatarStackProps props; @@ -132,6 +133,7 @@ class StreamAvatarStackProps { required this.children, this.overlap = 0.33, this.max = 5, + this.showShadow = false, }); /// The list of widgets to display in the stack. @@ -158,6 +160,12 @@ class StreamAvatarStackProps { /// /// Must be at least 2. Defaults to 5. final int max; + + /// Whether to show a drop shadow around each individual avatar. + /// + /// Defaults to false. The shadow style is determined by + /// [StreamBoxShadow.elevation3]. + final bool showShadow; } /// The default implementation of [StreamAvatarStack]. @@ -202,6 +210,7 @@ class DefaultStreamAvatarStack extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), + boxShadow: props.showShadow ? context.streamBoxShadow.elevation3 : null, ), child: StreamRow( spacing: -diameter * props.overlap, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart index 34da5832..771791c0 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart @@ -132,6 +132,7 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { this.backgroundColor, this.foregroundColor, this.border, + this.boxShadow, }); /// The default size for avatars. @@ -156,6 +157,12 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { /// of both border color and width. final BoxBorder? border; + /// The box shadow for this avatar. + /// + /// Applied when [StreamAvatar.showShadow] is true. Defaults to + /// [StreamBoxShadow.elevation3]. + final List? boxShadow; + /// Linearly interpolate between two [StreamAvatarThemeData] objects. static StreamAvatarThemeData? lerp( StreamAvatarThemeData? a, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart index 4a2b8836..1d3124f3 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart @@ -34,6 +34,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), foregroundColor: Color.lerp(a.foregroundColor, b.foregroundColor, t), border: BoxBorder.lerp(a.border, b.border, t), + boxShadow: t < 0.5 ? a.boxShadow : b.boxShadow, ); } @@ -42,6 +43,7 @@ mixin _$StreamAvatarThemeData { Color? backgroundColor, Color? foregroundColor, BoxBorder? border, + List? boxShadow, }) { final _this = (this as StreamAvatarThemeData); @@ -50,6 +52,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: backgroundColor ?? _this.backgroundColor, foregroundColor: foregroundColor ?? _this.foregroundColor, border: border ?? _this.border, + boxShadow: boxShadow ?? _this.boxShadow, ); } @@ -69,6 +72,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: other.backgroundColor, foregroundColor: other.foregroundColor, border: other.border, + boxShadow: other.boxShadow, ); } @@ -88,7 +92,8 @@ mixin _$StreamAvatarThemeData { return _other.size == _this.size && _other.backgroundColor == _this.backgroundColor && _other.foregroundColor == _this.foregroundColor && - _other.border == _this.border; + _other.border == _this.border && + _other.boxShadow == _this.boxShadow; } @override @@ -101,6 +106,7 @@ mixin _$StreamAvatarThemeData { _this.backgroundColor, _this.foregroundColor, _this.border, + _this.boxShadow, ); } } diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart new file mode 100644 index 00000000..ac811728 --- /dev/null +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart @@ -0,0 +1,233 @@ +// ignore_for_file: avoid_redundant_argument_values + +import 'package:alchemist/alchemist.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/stream_core_flutter.dart'; + +void main() { + group('StreamAvatar Golden Tests', () { + // ------------------------------------------------------------------------- + // StreamAvatar — shadow matrix (light) + // ------------------------------------------------------------------------- + goldenTest( + 'renders shadow variants in light theme', + fileName: 'stream_avatar_shadow_light', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarSize.values) ...[ + GoldenTestScenario( + name: '${size.name}_shadow_off', + child: _buildAvatarInTheme( + StreamAvatar( + size: size, + showBorder: false, + showShadow: false, + placeholder: (context) => const Text('AB'), + ), + ), + ), + GoldenTestScenario( + name: '${size.name}_shadow_on', + child: _buildAvatarInTheme( + StreamAvatar( + size: size, + showBorder: false, + showShadow: true, + placeholder: (context) => const Text('AB'), + ), + ), + ), + ], + ], + ), + ); + + // ------------------------------------------------------------------------- + // StreamAvatar — shadow matrix (dark) + // ------------------------------------------------------------------------- + goldenTest( + 'renders shadow variants in dark theme', + fileName: 'stream_avatar_shadow_dark', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarSize.values) ...[ + GoldenTestScenario( + name: '${size.name}_shadow_off', + child: _buildAvatarInTheme( + StreamAvatar( + size: size, + showBorder: false, + showShadow: false, + placeholder: (context) => const Text('AB'), + ), + brightness: Brightness.dark, + ), + ), + GoldenTestScenario( + name: '${size.name}_shadow_on', + child: _buildAvatarInTheme( + StreamAvatar( + size: size, + showBorder: false, + showShadow: true, + placeholder: (context) => const Text('AB'), + ), + brightness: Brightness.dark, + ), + ), + ], + ], + ), + ); + + // ------------------------------------------------------------------------- + // StreamAvatarGroup — shadow on, various counts (light) + // ------------------------------------------------------------------------- + goldenTest( + 'renders avatar group with shadow in light theme', + fileName: 'stream_avatar_group_shadow_light', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarGroupSize.values) + for (final count in [2, 4, 5]) + GoldenTestScenario( + name: '${size.name}_count_$count', + child: _buildAvatarInTheme( + StreamAvatarGroup( + size: size, + showShadow: true, + children: List.generate( + count, + (i) => StreamAvatar( + placeholder: (context) => Text(_initials(i)), + ), + ), + ), + ), + ), + ], + ), + ); + + // ------------------------------------------------------------------------- + // StreamAvatarGroup — shadow on (dark) + // ------------------------------------------------------------------------- + goldenTest( + 'renders avatar group with shadow in dark theme', + fileName: 'stream_avatar_group_shadow_dark', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarGroupSize.values) + for (final count in [2, 4, 5]) + GoldenTestScenario( + name: '${size.name}_count_$count', + child: _buildAvatarInTheme( + StreamAvatarGroup( + size: size, + showShadow: true, + children: List.generate( + count, + (i) => StreamAvatar( + placeholder: (context) => Text(_initials(i)), + ), + ), + ), + brightness: Brightness.dark, + ), + ), + ], + ), + ); + + // ------------------------------------------------------------------------- + // StreamAvatarStack — shadow on (light) + // ------------------------------------------------------------------------- + goldenTest( + 'renders avatar stack with shadow in light theme', + fileName: 'stream_avatar_stack_shadow_light', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarStackSize.values) + GoldenTestScenario( + name: size.name, + child: _buildAvatarInTheme( + StreamAvatarStack( + size: size, + showShadow: true, + children: List.generate( + 4, + (i) => StreamAvatar( + placeholder: (context) => Text(_initials(i)), + ), + ), + ), + ), + ), + ], + ), + ); + + // ------------------------------------------------------------------------- + // StreamAvatarStack — shadow on (dark) + // ------------------------------------------------------------------------- + goldenTest( + 'renders avatar stack with shadow in dark theme', + fileName: 'stream_avatar_stack_shadow_dark', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final size in StreamAvatarStackSize.values) + GoldenTestScenario( + name: size.name, + child: _buildAvatarInTheme( + StreamAvatarStack( + size: size, + showShadow: true, + children: List.generate( + 4, + (i) => StreamAvatar( + placeholder: (context) => Text(_initials(i)), + ), + ), + ), + brightness: Brightness.dark, + ), + ), + ], + ), + ); + }); +} + +Widget _buildAvatarInTheme( + Widget avatar, { + Brightness brightness = Brightness.light, +}) { + final streamTheme = StreamTheme(brightness: brightness); + return Theme( + data: ThemeData( + brightness: brightness, + extensions: [streamTheme], + ), + child: Builder( + builder: (context) => Material( + color: StreamTheme.of(context).colorScheme.backgroundApp, + child: Padding( + padding: const EdgeInsets.all(16), + child: avatar, + ), + ), + ), + ); +} + +String _initials(int index) { + const names = ['AB', 'CD', 'EF', 'GH', 'IJ']; + return names[index % names.length]; +} diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart index 65be76e7..e847e686 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart @@ -112,7 +112,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, title: const Text('Details'), ), ), @@ -123,7 +123,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, @@ -156,7 +156,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, title: const Text('Details'), ), brightness: Brightness.dark, @@ -168,7 +168,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart index 26aacc1a..113e9363 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart @@ -116,7 +116,7 @@ void main() { body: StreamAppBar( automaticallyImplyLeading: false, primary: false, - floating: true, + appBarBehavior: AppBarBehavior.floating, title: const Text('Title'), ), ), @@ -138,7 +138,7 @@ void main() { }); testWidgets('floating: true uses outline button type for auto-implied leading', (tester) async { - await tester.pumpWidget(_withStreamTheme(const _LauncherScreen(floating: true))); + await tester.pumpWidget(_withStreamTheme(const _LauncherScreen(appBarBehavior: AppBarBehavior.floating))); await tester.tap(find.text('Open')); await tester.pumpAndSettle(); @@ -229,13 +229,13 @@ class _LauncherScreen extends StatelessWidget { this.customLeading = false, this.implyLeading = true, this.fullscreenDialog = false, - this.floating = false, + this.appBarBehavior, }); final bool customLeading; final bool implyLeading; final bool fullscreenDialog; - final bool floating; + final AppBarBehavior? appBarBehavior; @override Widget build(BuildContext context) { @@ -250,7 +250,7 @@ class _LauncherScreen extends StatelessWidget { builder: (_) => Scaffold( appBar: StreamAppBar( automaticallyImplyLeading: implyLeading, - floating: floating, + appBarBehavior: appBarBehavior, leading: customLeading ? const SizedBox(key: ValueKey('custom-leading'), width: 40, height: 40) : null, From 0fd3fbab74c3515e2ded084579f194799c697e2b Mon Sep 17 00:00:00 2001 From: renefloor <15101411+renefloor@users.noreply.github.com> Date: Fri, 12 Jun 2026 08:22:47 +0000 Subject: [PATCH 09/35] chore: Update Goldens --- .../ci/stream_avatar_group_shadow_dark.png | Bin 0 -> 19382 bytes .../ci/stream_avatar_group_shadow_light.png | Bin 0 -> 24730 bytes .../goldens/ci/stream_avatar_shadow_dark.png | Bin 0 -> 13451 bytes .../goldens/ci/stream_avatar_shadow_light.png | Bin 0 -> 15545 bytes .../ci/stream_avatar_stack_shadow_dark.png | Bin 0 -> 3815 bytes .../ci/stream_avatar_stack_shadow_light.png | Bin 0 -> 6043 bytes .../toolbar/goldens/ci/stream_app_bar_dark.png | Bin 0 -> 1795 bytes .../goldens/ci/stream_app_bar_floating_dark.png | Bin 0 -> 6025 bytes .../ci/stream_app_bar_floating_light.png | Bin 0 -> 6993 bytes .../toolbar/goldens/ci/stream_app_bar_light.png | Bin 0 -> 2325 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_dark.png create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_light.png create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png create mode 100644 packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_dark.png create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_dark.png create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_light.png create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_light.png diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b23f698e1d0a98665689bcd2dc01f443d50ed65d GIT binary patch literal 19382 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 z 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 z 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 GfB!dD-872; literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_shadow_light.png new file mode 100644 index 0000000000000000000000000000000000000000..e468ef273a121e9989be6d7910a837ec42656a65 GIT binary patch literal 15545 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 S2Zk*KqOPp1RIgz3_`d<@LAVD1 literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..246ee21d15b4e44643c1f01fa05e00c6ed9fe1f9 GIT binary patch literal 3815 zcmbVPXHXMrvyO5oVnHb)Afh5DNReg;Es9`7suTf%0MY{j5_&(NbO=q9W+(~*5~K)$ zgiroycTb^pNCwT#(LC78`V<}^M7H-xAIQ2p1J0Dwy=S{jdy{d3kP11ybq z8J%1B1PP{lZ1>pKuSOS0sGF;}Y9i69*^BQ)hKJwuN;q8KD~+*8^AO}!*ZQwPc{W%v9sYEF;!L^sdVY>i$y?EECffr? z#!x4(%Q(IW#?3?}l(po}Y_4l`Ogw2~#A-kwX{o8LQzL@c`@3frWP}wI$kX=TN`mF% z(U<>%;?OuIwBH!pwtlX?X}7N|PIvyBSQ@gzvcXnrps0`S+=dj4`v$8D6 zA=#|53%GN4sM>c_R1z}&{ny^X$xfD^kW2+-@|6IwEKPq$IuY%*9D`wlm(|suEDfRr z2_VoymX6zzmk8^SpMjN?PfxI&zQ-JEg8lE!Kkp##xJL4siY8RN;JU#--4&+SCZ9TJ zW=;;IDO`mxK*|`is}ipq#IW`*n;Rv(SIr*nYfIhQ3hjyAF}di71Aeadm)|=QnO`Eg znm6r+kJhswK5c40Egm*^RHI`@dk@N4C3LaD*AFIW2Q&*M2-SD-6JE#&fqtA3lF9s1 z2;cR(+My$?uTl|nEmZEQf8FPd1^L3!;8~G)hre<=k}N>P^n!AfclCGOeuEET>m&{d zU6sbLG>=KO_HBB@Wa+j?D7s^ATxD=}V18F%{dyq9%G00Q+HE4K0-+z-V}&(nk9k~~ z1F{OwhHygl4T^I4QKBbM*)37gv^8+{168RW?UbW z+0W3swzm1DHxL9j$Ak3fF?!!ClO7AW@;X)y9gtiTAe53aY3!uOOO|tcbm616)ZD^q ztCMSON^)|ZlC{^;?Kalk8SfS`Y9jyE-)Prs%D&&1gUtyFPeu0@oIhX5)$5G+kZ>f{ zES2uyk5}jv8a2{Xf%4sRBG=E>%1(;_AB5ck+{iuvoR*jw??t4Ch?=~o!6soZrLE64 zBb}PshX(Lwk{YKe8S=K*K78QO@J^f!uQc$v1<1+CF{`~DyA^g&w%nV$AT*Z2)FGF} z{^F%?VhI<-tA643tX09Yfo{Ap8{9`>_-^9dDNv<<-lwL9Y8c&uxw;0tCi*9l`OdkG zW>omv6OGxz>vy2Dkq+5|D*}Y{CZ6c@Rs!L@^g}nJpKe6d8~b1kYd8UZb+EzbepzN# z7C$tM1OmJc?AW2o4U}fNc6Dxe<HYZp>PgAVQ-<4zNel=|5+mzgh2=SSIHee zfI^{JUOU!-87jlJ#G3PS!#vq+&VSU67{`9l`A1Kc`i{?$G@y@w0t4n?8xAVr57Ow(7Oe)u%-TYk`W~ADQ7f1sb{RG!bP^2RwXEahJ56)gFDZ&Q!P5d!A~r3moG2S ze128}(AuC;Xj*?i6&V&WG*kv?ze_a*o9azkKF+r?ar(}u>WFRYs4_X-OA*RGLpj>h znDgN;-w@?&!uPyRJZ->^)qMIDMF}SLPMfZforLrZ=r0@3`CF_WBB*ToyMsnV)RHq}E40{;6*y2OqwQA~o-&A#*qiZrZuF-QKQ&7y5+@IuJ>!67yS)ITwzm z<=2vSmUqtW&#itx&e`~LKrajunVDaEGpuAbT&(Zm9e6kZ8Mk7WgtT2?0rt%cOf1Wy zP^c^~_w{wa;%*ayqce$fQn9fa=j8{r zMBQ|Dv%oQQLynQ@vs&@rU|S

q;H0tS)MF{$1l5 zpm(~B!l~t9ksD*%%pxKprLrk6D*gTC$wvfrHO8XwD15S;Uhvx2W7=k4ajzTX-CSh3 za{%0p6@ssIQ;;=l$lhH;p3h2-M$mF1|6!fRB~YO%e8{uAd-P34G5Dn)`Ry=qz^oqj zp|p4K%0Aavl>%?vz!r@fTPhpa_}K-acCLB6LbWfYaIf)NVO0AIJ5;Uf1;}r;Pwqx2 zSNjWqq9=T{Bn+Me=MZY2X#Ps68&Va&8m?j|YFa_8J@2ghig?4bnZ&pxrs<%`$C1Ea z03!rJ5@tWE9se+c1(52SJjn^Wef8Pd%F=xm82kD0nsN!+{z@tNVBAQ0@OGXE{&~gr zSh~!}2(h+_zA9G@vhbfM`d;_}dK?R<{M?9W-`8$Go$m>Px@>igP;g8_+^+#}cp2E* z_Hb`4Yp0x8BaDRuVKA6kcKR1kMaS|7B*^}Hw3SG9h^I8u;Zyk1P$H0ePx2L(U1-|z zD3~OBt}@rG&b@K8H`%tZK5U{5AQ3!|)X9{;QBD5~!~oFfhV7QrQ8XIudE|U)GQuJ` zvxITc_F;DB_9m0W$%5o)rt)lr#Id(lWRJqWYfE#!U0&#YIal(vjzs?F zngN=T^R77A^KPj=x(lMOprlTEdY#abHR>u)5z3Lz z4R3zAKt5`2-JcrG@%TM2Cu(Fex_JmGAK%-7N}*VYteS($wh!!tKE)6$`=WfTe@OcX z6eneWE5&Y|S@c%QqSxJ#E#i0*J*}^<4t|I_NfopJ+V=L(P>}989H?{P_vq{`zrYl(-=fg!?YE&Og4nVuDfAnqzEeo`nit#UGz?ewa? zhauCBp^z#2g+J}_8<$9~IPc)~oD*^y$8-xgPeh=yhUXom`gJw1>#v z>Q5q1&!Dt*>*-%+W_`V->I-+^?sAD(n4FfD*3t3XXsd|Av}r6R@_Gm*H|&vsp`4CC zI_O)!CB5Wb%T`K`s?oEefVd92s(sNA;nfr^1ZnVq7D=DF}4uH6OT2IF^JKhI^p)ruuJ=i;Zs zWege<?dT&5)pLv>luvKaz3Hg=tZss>?U6-|lppz6ecx5&Pn3H#W0031wnp;)SDej_yXA z^pRnriAw_`U0mP3*M!cMm6pb(rrtL;9?9kSRwA=Q5fkPEJ6`*WN0|?pzBKfrv-6OA z;N}uPu{5eq)TM+%G}`Q!aFiXG@yybjEq*$?7#2`&zrS>;VG_)@3iG^+b(Lu3;#`_i z%^LjS`HFU!lKJ6%m$SY8vTqe`y61gCw)GS8>fCd)k2k1ELOT14*IHYbadTvYJ=^VV zomE}k*%^j$KT_3aI9T|ulltv~n0Wm=;z}8VgAa&xuG&dm8mO*kfkY|XbW^+>GZ2g| z#{+NQs}ZPtdmOt)$o>)I8KLBR2cNF(4wYI8@`G<;=4xiU?DhMUsRFb#^)yiG HHWB{=cU-5K literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png new file mode 100644 index 0000000000000000000000000000000000000000..cc8d07f6073583475bca231c6bfce817ae42985d GIT binary patch literal 6043 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 literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_dark.png b/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..cb61c5a7663bb8934dbd36bcc469b1ba0ec38399 GIT binary patch literal 1795 zcmb_cX;hL~82(%F zCi?cr9Ko(i8C=W zl|HgF^LK{czXXp-(@95}W=21>?&m6v+stEw6 zo*9BUd0vYEW51@Y1prspnFB!Dx<*i5w+u{l4RQ;3M5b#1z`p;hS`;HZw>$0zM;j>f z7RoPD_pB``lRA=2fJ4iI{*%|rB#wk&4p6DoJW+FNC6!+>SQ(@daq|@AM}+sUr0M13 zIsot?_hE6llbg##)~f@xh^~+BkuMuA3{1(ncb>sKri8Rz;D>orc3qg>$oN z5)N$-kDX_9fw;Q0R5$Ho^a=6h6}8gr{;&mxyCKTrk}Q5q9tp#bU*HGR9Aa9G8-WJH zM!@gyYL@|{oLyh`1$M@6CQ1}HpTLN6Pagy8jYJ6<|HcUbwt072Sk9(y(3Pk{1}j!V z{OJbV&LswWCbG03A+qpJeXzlH!MKIGzvhhUsr^5tu%2%~R~(z|Ixf~)QdrFq+%QsO z!q^T+=Qgz1WHUA;KI*=Mo0n#tU9jP$kh!4{5Iuf0=)5!q>gLj4GqfQwRF4t|p7QZO2Z)6WrJ&tt_t z@XfU+>EOGcrjU9Z8gh)4_lB^^uDtg*#&YHEA#7PFABC*gJ^oJsI! zE5$IygA4kuEhb<}t@Mtt>}hu!ds60l4toX>8dQEIL>&%Z)HBJd3<@q0cJhq3?gf$U zX&us5T32`Kr6uJ0Xx>^dvNadBhe|R!v!>C^3ZG)Ob#97HyT_uc!9;Z~ntA0dzt&-P zc_YXQS7L8f;kd~)x8E6RQ*=RGU9nnp9?4#{_#RldH_DAX-myDmMh~g~B$9Q`1V_utrq;DK1c1N4jp24SyFs7 zKb-Fh=ra#7g}FH&nXw04?%jGJIL#BP%uj|@qh@LKc;|4}DSkAx-DE3I-3+^iAq9N- z>aUm{9QXC07NyBcoub_k?-y*CtkKv zrVbKx)F`A^mV$U%SfMwc zAjTF}{vlIMab&~i;^#)aFMd4 p94(*>UYu|sDg<8KH=qmje|AJf`(Vhbf)60D0VKi~&hUyz{|9$#>}3D| literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_dark.png b/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_app_bar_floating_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2cf37c52b9955a0ffba3ada6a9c9e2dbe86b6a60 GIT binary patch literal 6025 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 Date: Fri, 12 Jun 2026 14:00:12 +0200 Subject: [PATCH 10/35] fix badge size on nav bar --- .../toolbar/stream_bottom_nav_bar.dart | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index 41463719..501f2ec0 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../theme/components/stream_badge_notification_theme.dart'; import '../../theme/stream_app_style.dart'; import '../../theme/stream_theme_extensions.dart'; @@ -209,9 +210,12 @@ class _FloatingNavBarItem extends StatelessWidget { mainAxisSize: MainAxisSize.min, spacing: spacing.xxxs, children: [ - IconTheme( - data: IconThemeData(color: color, size: 20), - child: selected ? item.selectedIcon : item.icon, + StreamBadgeNotificationTheme( + data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), + child: IconTheme( + data: IconThemeData(color: color, size: 20), + child: selected ? item.selectedIcon : item.icon, + ), ), Text( item.label, @@ -249,24 +253,27 @@ class _RegularNavBar extends StatelessWidget { color: colorScheme.backgroundElevation1, border: Border(top: BorderSide(color: colorScheme.borderSubtle)), ), - child: BottomNavigationBar( - elevation: 0, - iconSize: 20, - currentIndex: currentIndex, - type: BottomNavigationBarType.fixed, - selectedItemColor: colorScheme.textPrimary, - unselectedItemColor: colorScheme.textTertiary, - backgroundColor: Colors.transparent, - selectedLabelStyle: textTheme.metadataEmphasis, - unselectedLabelStyle: textTheme.metadataEmphasis, - onTap: onTap, - items: items.map((item) { - return BottomNavigationBarItem( - icon: item.icon, - activeIcon: item.selectedIcon, - label: item.label, - ); - }).toList(), + child: StreamBadgeNotificationTheme( + data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), + child: BottomNavigationBar( + elevation: 0, + iconSize: 20, + currentIndex: currentIndex, + type: BottomNavigationBarType.fixed, + selectedItemColor: colorScheme.textPrimary, + unselectedItemColor: colorScheme.textTertiary, + backgroundColor: Colors.transparent, + selectedLabelStyle: textTheme.metadataEmphasis, + unselectedLabelStyle: textTheme.metadataEmphasis, + onTap: onTap, + items: items.map((item) { + return BottomNavigationBarItem( + icon: item.icon, + activeIcon: item.selectedIcon, + label: item.label, + ); + }).toList(), + ), ), ); } From 9b781a8a48917fe2853f15b44ed61e8e0eb5f51a Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 12 Jun 2026 14:05:58 +0200 Subject: [PATCH 11/35] Add gradient to floating bottom nav --- .../toolbar/stream_bottom_nav_bar.dart | 87 +++++++++++++------ 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index 501f2ec0..99fdc6c5 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -143,38 +143,73 @@ class _FloatingNavBar extends StatelessWidget { final int currentIndex; final ValueChanged onTap; + LinearGradient _buildGradient(BuildContext context, Color backgroundColor) { + final safeAreaBottom = MediaQuery.paddingOf(context).bottom; + // Approximate rendered height: safe area + vertical padding + item height. + const itemHeight = 56.0; + final totalHeight = safeAreaBottom + itemHeight; + final f = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; + + return LinearGradient( + colors: [ + backgroundColor, + backgroundColor, + backgroundColor.withAlpha(0xE8), + backgroundColor.withAlpha(0xA8), + backgroundColor.withAlpha(0x40), + backgroundColor.withAlpha(0x00), + ], + stops: [ + 0.0, + f, + f + (1 - f) * 0.55, + f + (1 - f) * 0.75, + f + (1 - f) * 0.90, + 1.0, + ], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ); + } + @override Widget build(BuildContext context) { final colorScheme = context.streamColorScheme; final spacing = context.streamSpacing; final radius = context.streamRadius; + final backgroundColor = colorScheme.backgroundElevation0; - return SafeArea( - top: false, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: spacing.xl), - child: Container( - decoration: BoxDecoration( - color: colorScheme.backgroundElevation1, - borderRadius: BorderRadius.all(radius.max), - boxShadow: context.streamBoxShadow.elevation1, - ), - foregroundDecoration: BoxDecoration( - borderRadius: BorderRadius.all(radius.max), - border: Border.all(color: colorScheme.borderSubtle), - ), - child: Padding( - padding: EdgeInsets.symmetric(vertical: spacing.xs), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - for (var i = 0; i < items.length; i++) - _FloatingNavBarItem( - item: items[i], - selected: i == currentIndex, - onTap: () => onTap(i), - ), - ], + return DecoratedBox( + decoration: BoxDecoration( + gradient: _buildGradient(context, backgroundColor), + ), + child: SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.xl), + child: Container( + decoration: BoxDecoration( + color: colorScheme.backgroundElevation1, + borderRadius: BorderRadius.all(radius.max), + boxShadow: context.streamBoxShadow.elevation1, + ), + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.all(radius.max), + border: Border.all(color: colorScheme.borderSubtle), + ), + child: Padding( + padding: EdgeInsets.symmetric(vertical: spacing.xs), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + for (var i = 0; i < items.length; i++) + _FloatingNavBarItem( + item: items[i], + selected: i == currentIndex, + onTap: () => onTap(i), + ), + ], + ), ), ), ), From 682d15f4b23cccd4ca0943b07883fd80d686d8c0 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Tue, 16 Jun 2026 12:54:34 +0200 Subject: [PATCH 12/35] Add accessibility for bottom bar --- .../toolbar/stream_bottom_nav_bar.dart | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index 99fdc6c5..eb0014bd 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -236,27 +236,35 @@ class _FloatingNavBarItem extends StatelessWidget { final spacing = context.streamSpacing; final color = selected ? colorScheme.textPrimary : colorScheme.textTertiary; - return GestureDetector( - behavior: HitTestBehavior.opaque, + return Semantics( + button: true, + selected: selected, + label: item.label, onTap: onTap, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: spacing.md, vertical: spacing.xxs), - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: spacing.xxxs, - children: [ - StreamBadgeNotificationTheme( - data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), - child: IconTheme( - data: IconThemeData(color: color, size: 20), - child: selected ? item.selectedIcon : item.icon, + onTapHint: 'select', + excludeSemantics: true, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: onTap, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.md, vertical: spacing.xxs), + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: spacing.xxxs, + children: [ + StreamBadgeNotificationTheme( + data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), + child: IconTheme( + data: IconThemeData(color: color, size: 20), + child: selected ? item.selectedIcon : item.icon, + ), ), - ), - Text( - item.label, - style: textTheme.metadataEmphasis.copyWith(color: color), - ), - ], + Text( + item.label, + style: textTheme.metadataEmphasis.copyWith(color: color), + ), + ], + ), ), ), ); From ceb2d0712e4d41ef28dc4e8c66ee787a12a6ff2c Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 09:17:29 +0200 Subject: [PATCH 13/35] update changelog --- packages/stream_core_flutter/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/stream_core_flutter/CHANGELOG.md b/packages/stream_core_flutter/CHANGELOG.md index 0163a543..631f3296 100644 --- a/packages/stream_core_flutter/CHANGELOG.md +++ b/packages/stream_core_flutter/CHANGELOG.md @@ -2,6 +2,10 @@ ### ✨ Features +- Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details. +- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Supports the ambient `BottomBarBehavior` from `StreamAppStyle`, rendering either a regular bar or a floating pill with a gradient fade-out beneath it. Items announce themselves as accessible buttons via `Semantics`. +- Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `AppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. +- Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. - Added `StreamSnackbar` and `StreamSnackbarTheme` — Stream-styled transient feedback snackbars with a messenger-driven queue. - Added `StreamIcons.megaphone` and `StreamIcons.shield` (20px) to the icon set. From 9a9de3761b2723295f67abb035547c3ce06e3590 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 10:15:20 +0200 Subject: [PATCH 14/35] fix composer in bottom --- .../components/scaffold/stream_scaffold.dart | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart index 4dcbef4e..4ee81448 100644 --- a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -199,6 +199,9 @@ class StreamScaffold extends StatelessWidget { // When neither slot is floating, use a plain Scaffold for maximum // compatibility (e.g. keyboard avoidance, Scaffold.of, etc.). + // The bottom widget lives inside the body Column (not bottomNavigationBar) + // because bottomNavigationBar is not repositioned above the keyboard on + // Android, which causes text-input composers to be hidden behind the IME. if (!appBarFloating && !bottomFloating) { return Scaffold( backgroundColor: effectiveBackgroundColor, @@ -206,11 +209,17 @@ class StreamScaffold extends StatelessWidget { appBar: appBar, drawer: drawer, endDrawer: endDrawer, - bottomNavigationBar: bottom, - body: StreamScaffoldInsets( - topPadding: 0, - bottomPadding: 0, - child: body, + body: Column( + children: [ + Expanded( + child: StreamScaffoldInsets( + topPadding: 0, + bottomPadding: 0, + child: body, + ), + ), + if (bottom != null) bottom!, + ], ), ); } From ef83513b075246cb662911926ad49ada2a07f595 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 11:33:43 +0200 Subject: [PATCH 15/35] Use null-aware marker --- .../lib/src/components/scaffold/stream_scaffold.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart index 4ee81448..6b4fb745 100644 --- a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -218,7 +218,7 @@ class StreamScaffold extends StatelessWidget { child: body, ), ), - if (bottom != null) bottom!, + ?bottom, ], ), ); From bed95c6a61dce641a1807cf642ebba66494ca6ec Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 11:51:55 +0200 Subject: [PATCH 16/35] fix(ui): avatar shadow, unified floating button disabled state, shared fade helper - Fix StreamAvatar.showShadow: themed boxShadow no longer bleeds onto avatars where showShadow is false; the prop now gates whether any shadow is applied. - Unify floating button disabled state: all outline/ghost variants retain their pill surface (backgroundElevation1) when disabled, matching SecondaryOutline which already had this behaviour. Solid variants are unchanged (they already use backgroundDisabled which reads as a pill). - Extract streamFloatingFade() helper: removes the three-way duplication of the alpha-stop gradient (0xE8/0xA8/0x40/0x00, ratios 0.55/0.75/0.90) shared by StreamAppBar, StreamBottomNavBar, and the floating composer. Exported from the theme barrel. - Add golden tests for floating buttons (enabled matrix + disabled matrix) to lock in the disabled-state surface behaviour. Co-Authored-By: Claude Opus 4.8 --- packages/stream_core_flutter/CHANGELOG.md | 4 +- .../src/components/avatar/stream_avatar.dart | 2 +- .../src/components/buttons/stream_button.dart | 10 ++-- .../components/toolbar/stream_app_bar.dart | 30 +++-------- .../toolbar/stream_bottom_nav_bar.dart | 23 ++------- .../stream_core_flutter/lib/src/theme.dart | 1 + .../lib/src/theme/stream_floating_fade.dart | 44 ++++++++++++++++ .../buttons/stream_button_golden_test.dart | 50 +++++++++++++++++++ 8 files changed, 115 insertions(+), 49 deletions(-) create mode 100644 packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart diff --git a/packages/stream_core_flutter/CHANGELOG.md b/packages/stream_core_flutter/CHANGELOG.md index 631f3296..e95471f2 100644 --- a/packages/stream_core_flutter/CHANGELOG.md +++ b/packages/stream_core_flutter/CHANGELOG.md @@ -5,7 +5,9 @@ - Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details. - Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Supports the ambient `BottomBarBehavior` from `StreamAppStyle`, rendering either a regular bar or a floating pill with a gradient fade-out beneath it. Items announce themselves as accessible buttons via `Semantics`. - Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `AppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. -- Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. +- Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. Fixed: a themed `boxShadow` in `StreamAvatarThemeData` no longer bleeds onto avatars where `showShadow` is `false`. +- Added `streamFloatingFade` helper — a shared `LinearGradient` factory (alpha stops `0xE8/0xA8/0x40/0x00` with solid-fraction support for safe-area zones) used internally by `StreamAppBar`, `StreamBottomNavBar`, and `StreamMessageComposer` floating fade effects. +- Floating buttons (`isFloating: true`) now retain their pill surface (`backgroundElevation1`) when disabled, across all style/type combinations. Previously, outline and ghost variants fell back to transparent when disabled, losing the floating visual. - Added `StreamSnackbar` and `StreamSnackbarTheme` — Stream-styled transient feedback snackbars with a messenger-driven queue. - Added `StreamIcons.megaphone` and `StreamIcons.shield` (20px) to the icon set. diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index d3514c84..4720ad93 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -202,7 +202,7 @@ class DefaultStreamAvatar extends StatelessWidget { final effectiveBackgroundColor = props.backgroundColor ?? avatarTheme.backgroundColor ?? defaults.backgroundColor; final effectiveForegroundColor = props.foregroundColor ?? avatarTheme.foregroundColor ?? defaults.foregroundColor; final effectiveBorder = avatarTheme.border ?? defaults.border; - final effectiveBoxShadow = avatarTheme.boxShadow ?? (props.showShadow ? defaults.boxShadow : null); + final effectiveBoxShadow = props.showShadow ? (avatarTheme.boxShadow ?? defaults.boxShadow) : null; final border = props.showBorder ? effectiveBorder : null; final textStyle = _textStyleForSize(effectiveSize, textTheme).copyWith(color: effectiveForegroundColor); diff --git a/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart b/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart index d9f86e69..66410211 100644 --- a/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart +++ b/packages/stream_core_flutter/lib/src/components/buttons/stream_button.dart @@ -526,8 +526,8 @@ class _PrimaryOutlineDefaults extends StreamButtonThemeStyle with _SharedButtonD @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); @@ -566,8 +566,8 @@ class _PrimaryGhostDefaults extends StreamButtonThemeStyle with _SharedButtonDef @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); @@ -676,8 +676,8 @@ class _SecondaryGhostDefaults extends StreamButtonThemeStyle with _SharedButtonD @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); @@ -746,8 +746,8 @@ class _DestructiveOutlineDefaults extends StreamButtonThemeStyle with _SharedBut @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); @@ -786,8 +786,8 @@ class _DestructiveGhostDefaults extends StreamButtonThemeStyle with _SharedButto @override WidgetStateProperty get backgroundColor => WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) return StreamColors.transparent; final base = isFloating ? colorScheme.backgroundElevation1 : StreamColors.transparent; + if (states.contains(WidgetState.disabled)) return base; if (states.contains(WidgetState.selected)) return .alphaBlend(colorScheme.backgroundSelected, base); return base; }); diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index d79b768e..3f57f9f7 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -7,6 +7,7 @@ import '../../theme/primitives/stream_spacing.dart'; import '../../theme/semantics/stream_color_scheme.dart'; import '../../theme/semantics/stream_text_theme.dart'; import '../../theme/stream_app_style.dart'; +import '../../theme/stream_floating_fade.dart'; import '../../theme/stream_theme_extensions.dart'; import '../buttons/stream_button.dart'; import 'stream_toolbar.dart'; @@ -349,32 +350,13 @@ class DefaultStreamAppBar extends StatelessWidget { required Color effectiveBackgroundColor, }) { // Compute the fraction of the total bar height occupied by the system - // safe area so the gradient fade only starts below the status bar. - // Above that boundary the background is fully solid. + // safe area so the gradient is solid through the status bar and fades only + // in the toolbar zone below it. final safeAreaTop = props.primary ? MediaQuery.paddingOf(context).top : 0.0; final totalHeight = safeAreaTop + kStreamToolbarHeight; - final f = totalHeight > 0 ? safeAreaTop / totalHeight : 0.0; - - return LinearGradient( - colors: [ - effectiveBackgroundColor, // solid through safe area - effectiveBackgroundColor, // solid at safe area boundary - effectiveBackgroundColor.withAlpha(0xE8), // ~91 % - effectiveBackgroundColor.withAlpha(0xA8), // ~66 % - effectiveBackgroundColor.withAlpha(0x40), // ~25 % - effectiveBackgroundColor.withAlpha(0x00), // transparent - ], - stops: [ - 0.0, - f, - f + (1 - f) * 0.55, - f + (1 - f) * 0.75, - f + (1 - f) * 0.90, - 1.0, - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ); + final solidFraction = totalHeight > 0 ? safeAreaTop / totalHeight : 0.0; + + return streamFloatingFade(color: effectiveBackgroundColor, solidFraction: solidFraction); } } diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index eb0014bd..c3c2b752 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../theme/components/stream_badge_notification_theme.dart'; import '../../theme/stream_app_style.dart'; +import '../../theme/stream_floating_fade.dart'; import '../../theme/stream_theme_extensions.dart'; /// A single item in a [StreamBottomNavBar]. @@ -148,25 +149,11 @@ class _FloatingNavBar extends StatelessWidget { // Approximate rendered height: safe area + vertical padding + item height. const itemHeight = 56.0; final totalHeight = safeAreaBottom + itemHeight; - final f = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; + final solidFraction = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; - return LinearGradient( - colors: [ - backgroundColor, - backgroundColor, - backgroundColor.withAlpha(0xE8), - backgroundColor.withAlpha(0xA8), - backgroundColor.withAlpha(0x40), - backgroundColor.withAlpha(0x00), - ], - stops: [ - 0.0, - f, - f + (1 - f) * 0.55, - f + (1 - f) * 0.75, - f + (1 - f) * 0.90, - 1.0, - ], + return streamFloatingFade( + color: backgroundColor, + solidFraction: solidFraction, begin: Alignment.bottomCenter, end: Alignment.topCenter, ); diff --git a/packages/stream_core_flutter/lib/src/theme.dart b/packages/stream_core_flutter/lib/src/theme.dart index 6e813b46..235131e5 100644 --- a/packages/stream_core_flutter/lib/src/theme.dart +++ b/packages/stream_core_flutter/lib/src/theme.dart @@ -54,6 +54,7 @@ export 'theme/semantics/stream_color_scheme.dart'; export 'theme/semantics/stream_text_theme.dart'; export 'theme/stream_app_style.dart'; +export 'theme/stream_floating_fade.dart'; export 'theme/stream_theme.dart'; export 'theme/stream_theme_extensions.dart'; export 'theme/widget_state_utils.dart'; diff --git a/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart b/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart new file mode 100644 index 00000000..6787ba62 --- /dev/null +++ b/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +/// Builds a [LinearGradient] that fades from a solid [color] into transparent, +/// suitable for floating app bars, bottom navigation bars, and composers. +/// +/// The gradient is solid from `0.0` up to [solidFraction] (the fraction of the +/// total height occupied by a system safe-area inset), then fades through four +/// alpha stops to fully transparent at `1.0`. +/// +/// [begin] and [end] control the direction of the fade: +/// * top-to-bottom (`Alignment.topCenter` → `Alignment.bottomCenter`) for +/// floating app bars, where the bar fades into the scrollable content below. +/// * bottom-to-top (`Alignment.bottomCenter` → `Alignment.topCenter`) for +/// floating nav bars and composers, where they fade into content above. +LinearGradient streamFloatingFade({ + required Color color, + double solidFraction = 0.0, + AlignmentGeometry begin = Alignment.topCenter, + AlignmentGeometry end = Alignment.bottomCenter, +}) { + assert(solidFraction >= 0.0 && solidFraction <= 1.0, 'solidFraction must be in [0, 1]'); + final f = solidFraction; + + return LinearGradient( + colors: [ + color, + color, + color.withAlpha(0xE8), // ~91 % + color.withAlpha(0xA8), // ~66 % + color.withAlpha(0x40), // ~25 % + color.withAlpha(0x00), // transparent + ], + stops: [ + 0.0, + f, + f + (1 - f) * 0.55, + f + (1 - f) * 0.75, + f + (1 - f) * 0.90, + 1.0, + ], + begin: begin, + end: end, + ); +} diff --git a/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart b/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart index 7f12e9ec..d86d013d 100644 --- a/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart +++ b/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart @@ -144,6 +144,56 @@ void main() { ], ), ); + + goldenTest( + 'renders floating button matrix correctly', + fileName: 'stream_button_floating_matrix', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 400), + children: [ + for (final style in StreamButtonStyle.values) + for (final type in StreamButtonType.values) + for (final size in StreamButtonSize.values) + GoldenTestScenario( + name: '${style.name}_${type.name}_${size.name}', + child: _buildButtonInTheme( + StreamButton( + onPressed: () {}, + style: style, + type: type, + size: size, + isFloating: true, + child: const Text('Button'), + ), + ), + ), + ], + ), + ); + + goldenTest( + 'renders disabled floating button correctly', + fileName: 'stream_button_floating_disabled', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: 300), + children: [ + for (final style in StreamButtonStyle.values) + for (final type in StreamButtonType.values) + GoldenTestScenario( + name: '${style.name}_${type.name}', + child: _buildButtonInTheme( + StreamButton( + onPressed: null, + style: style, + type: type, + isFloating: true, + child: const Text('Disabled'), + ), + ), + ), + ], + ), + ); }); } From fbcd55ce6d3fcc8ccfc60ebe76249c795b32cad7 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 12:10:46 +0200 Subject: [PATCH 17/35] fix golden tests --- .../buttons/stream_button_golden_test.dart | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart b/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart index d86d013d..be6beea3 100644 --- a/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart +++ b/packages/stream_core_flutter/test/components/buttons/stream_button_golden_test.dart @@ -123,8 +123,8 @@ void main() { ); goldenTest( - 'renders disabled button correctly', - fileName: 'stream_button_disabled', + 'renders floating icon only button correctly', + fileName: 'stream_button_icon_only_floating', builder: () => GoldenTestGroup( scenarioConstraints: const BoxConstraints(maxWidth: 300), children: [ @@ -133,11 +133,12 @@ void main() { GoldenTestScenario( name: '${style.name}_${type.name}', child: _buildButtonInTheme( - StreamButton( - onPressed: null, + StreamButton.icon( + onPressed: () {}, style: style, type: type, - child: const Text('Disabled'), + isFloating: true, + icon: const Icon(Icons.add), ), ), ), @@ -146,34 +147,32 @@ void main() { ); goldenTest( - 'renders floating button matrix correctly', - fileName: 'stream_button_floating_matrix', + 'renders disabled floating icon only button correctly', + fileName: 'stream_button_icon_only_floating_disabled', builder: () => GoldenTestGroup( - scenarioConstraints: const BoxConstraints(maxWidth: 400), + scenarioConstraints: const BoxConstraints(maxWidth: 300), children: [ for (final style in StreamButtonStyle.values) for (final type in StreamButtonType.values) - for (final size in StreamButtonSize.values) - GoldenTestScenario( - name: '${style.name}_${type.name}_${size.name}', - child: _buildButtonInTheme( - StreamButton( - onPressed: () {}, - style: style, - type: type, - size: size, - isFloating: true, - child: const Text('Button'), - ), + GoldenTestScenario( + name: '${style.name}_${type.name}', + child: _buildButtonInTheme( + StreamButton.icon( + onPressed: null, + style: style, + type: type, + isFloating: true, + icon: const Icon(Icons.add), ), ), + ), ], ), ); goldenTest( - 'renders disabled floating button correctly', - fileName: 'stream_button_floating_disabled', + 'renders disabled button correctly', + fileName: 'stream_button_disabled', builder: () => GoldenTestGroup( scenarioConstraints: const BoxConstraints(maxWidth: 300), children: [ @@ -186,7 +185,6 @@ void main() { onPressed: null, style: style, type: type, - isFloating: true, child: const Text('Disabled'), ), ), From 7eaab1675f83191cea8a11c77a014cdb77a36480 Mon Sep 17 00:00:00 2001 From: renefloor <15101411+renefloor@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:12:21 +0000 Subject: [PATCH 18/35] chore: Update Goldens --- .../ci/stream_avatar_group_shadow_dark.png | Bin 19382 -> 19265 bytes .../ci/stream_avatar_group_shadow_light.png | Bin 24730 -> 17355 bytes .../ci/stream_avatar_stack_shadow_dark.png | Bin 3815 -> 3800 bytes .../ci/stream_avatar_stack_shadow_light.png | Bin 6043 -> 3792 bytes .../ci/stream_button_icon_only_floating.png | Bin 0 -> 21023 bytes ...eam_button_icon_only_floating_disabled.png | Bin 0 -> 21312 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating.png create mode 100644 packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating_disabled.png diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png index b23f698e1d0a98665689bcd2dc01f443d50ed65d..2e8ce0e521f74413a0e0fe8053714c71d4c04bbe 100644 GIT binary patch literal 19265 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 F0RXm-F3SJ_ literal 19382 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 z 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 z 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 D1f75` literal 24730 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 literal 3815 zcmbVPXHXMrvyO5oVnHb)Afh5DNReg;Es9`7suTf%0MY{j5_&(NbO=q9W+(~*5~K)$ zgiroycTb^pNCwT#(LC78`V<}^M7H-xAIQ2p1J0Dwy=S{jdy{d3kP11ybq z8J%1B1PP{lZ1>pKuSOS0sGF;}Y9i69*^BQ)hKJwuN;q8KD~+*8^AO}!*ZQwPc{W%v9sYEF;!L^sdVY>i$y?EECffr? z#!x4(%Q(IW#?3?}l(po}Y_4l`Ogw2~#A-kwX{o8LQzL@c`@3frWP}wI$kX=TN`mF% z(U<>%;?OuIwBH!pwtlX?X}7N|PIvyBSQ@gzvcXnrps0`S+=dj4`v$8D6 zA=#|53%GN4sM>c_R1z}&{ny^X$xfD^kW2+-@|6IwEKPq$IuY%*9D`wlm(|suEDfRr z2_VoymX6zzmk8^SpMjN?PfxI&zQ-JEg8lE!Kkp##xJL4siY8RN;JU#--4&+SCZ9TJ zW=;;IDO`mxK*|`is}ipq#IW`*n;Rv(SIr*nYfIhQ3hjyAF}di71Aeadm)|=QnO`Eg znm6r+kJhswK5c40Egm*^RHI`@dk@N4C3LaD*AFIW2Q&*M2-SD-6JE#&fqtA3lF9s1 z2;cR(+My$?uTl|nEmZEQf8FPd1^L3!;8~G)hre<=k}N>P^n!AfclCGOeuEET>m&{d zU6sbLG>=KO_HBB@Wa+j?D7s^ATxD=}V18F%{dyq9%G00Q+HE4K0-+z-V}&(nk9k~~ z1F{OwhHygl4T^I4QKBbM*)37gv^8+{168RW?UbW z+0W3swzm1DHxL9j$Ak3fF?!!ClO7AW@;X)y9gtiTAe53aY3!uOOO|tcbm616)ZD^q ztCMSON^)|ZlC{^;?Kalk8SfS`Y9jyE-)Prs%D&&1gUtyFPeu0@oIhX5)$5G+kZ>f{ zES2uyk5}jv8a2{Xf%4sRBG=E>%1(;_AB5ck+{iuvoR*jw??t4Ch?=~o!6soZrLE64 zBb}PshX(Lwk{YKe8S=K*K78QO@J^f!uQc$v1<1+CF{`~DyA^g&w%nV$AT*Z2)FGF} z{^F%?VhI<-tA643tX09Yfo{Ap8{9`>_-^9dDNv<<-lwL9Y8c&uxw;0tCi*9l`OdkG zW>omv6OGxz>vy2Dkq+5|D*}Y{CZ6c@Rs!L@^g}nJpKe6d8~b1kYd8UZb+EzbepzN# z7C$tM1OmJc?AW2o4U}fNc6Dxe<HYZp>PgAVQ-<4zNel=|5+mzgh2=SSIHee zfI^{JUOU!-87jlJ#G3PS!#vq+&VSU67{`9l`A1Kc`i{?$G@y@w0t4n?8xAVr57Ow(7Oe)u%-TYk`W~ADQ7f1sb{RG!bP^2RwXEahJ56)gFDZ&Q!P5d!A~r3moG2S ze128}(AuC;Xj*?i6&V&WG*kv?ze_a*o9azkKF+r?ar(}u>WFRYs4_X-OA*RGLpj>h znDgN;-w@?&!uPyRJZ->^)qMIDMF}SLPMfZforLrZ=r0@3`CF_WBB*ToyMsnV)RHq}E40{;6*y2OqwQA~o-&A#*qiZrZuF-QKQ&7y5+@IuJ>!67yS)ITwzm z<=2vSmUqtW&#itx&e`~LKrajunVDaEGpuAbT&(Zm9e6kZ8Mk7WgtT2?0rt%cOf1Wy zP^c^~_w{wa;%*ayqce$fQn9fa=j8{r zMBQ|Dv%oQQLynQ@vs&@rU|S

q;H0tS)MF{$1l5 zpm(~B!l~t9ksD*%%pxKprLrk6D*gTC$wvfrHO8XwD15S;Uhvx2W7=k4ajzTX-CSh3 za{%0p6@ssIQ;;=l$lhH;p3h2-M$mF1|6!fRB~YO%e8{uAd-P34G5Dn)`Ry=qz^oqj zp|p4K%0Aavl>%?vz!r@fTPhpa_}K-acCLB6LbWfYaIf)NVO0AIJ5;Uf1;}r;Pwqx2 zSNjWqq9=T{Bn+Me=MZY2X#Ps68&Va&8m?j|YFa_8J@2ghig?4bnZ&pxrs<%`$C1Ea z03!rJ5@tWE9se+c1(52SJjn^Wef8Pd%F=xm82kD0nsN!+{z@tNVBAQ0@OGXE{&~gr zSh~!}2(h+_zA9G@vhbfM`d;_}dK?R<{M?9W-`8$Go$m>Px@>igP;g8_+^+#}cp2E* z_Hb`4Yp0x8BaDRuVKA6kcKR1kMaS|7B*^}Hw3SG9h^I8u;Zyk1P$H0ePx2L(U1-|z zD3~OBt}@rG&b@K8H`%tZK5U{5AQ3!|)X9{;QBD5~!~oFfhV7QrQ8XIudE|U)GQuJ` zvxITc_F;DB_9m0W$%5o)rt)lr#Id(lWRJqWYfE#!U0&#YIal(vjzs?F zngN=T^R77A^KPj=x(lMOprlTEdY#abHR>u)5z3Lz z4R3zAKt5`2-JcrG@%TM2Cu(Fex_JmGAK%-7N}*VYteS($wh!!tKE)6$`=WfTe@OcX z6eneWE5&Y|S@c%QqSxJ#E#i0*J*}^<4t|I_NfopJ+V=L(P>}989H?{P_vq{`zrYl(-=fg!?YE&Og4nVuDfAnqzEeo`nit#UGz?ewa? zhauCBp^z#2g+J}_8<$9~IPc)~oD*^y$8-xgPeh=yhUXom`gJw1>#v z>Q5q1&!Dt*>*-%+W_`V->I-+^?sAD(n4FfD*3t3XXsd|Av}r6R@_Gm*H|&vsp`4CC zI_O)!CB5Wb%T`K`s?oEefVd92s(sNA;nfr^1ZnVq7D=DF}4uH6OT2IF^JKhI^p)ruuJ=i;Zs zWege<?dT&5)pLv>luvKaz3Hg=tZss>?U6-|lppz6ecx5&Pn3H#W0031wnp;)SDej_yXA z^pRnriAw_`U0mP3*M!cMm6pb(rrtL;9?9kSRwA=Q5fkPEJ6`*WN0|?pzBKfrv-6OA z;N}uPu{5eq)TM+%G}`Q!aFiXG@yybjEq*$?7#2`&zrS>;VG_)@3iG^+b(Lu3;#`_i z%^LjS`HFU!lKJ6%m$SY8vTqe`y61gCw)GS8>fCd)k2k1ELOT14*IHYbadTvYJ=^VV zomE}k*%^j$KT_3aI9T|ulltv~n0Wm=;z}8VgAa&xuG&dm8mO*kfkY|XbW^+>GZ2g| z#{+NQs}ZPtdmOt)$o>)I8KLBR2cNF(4wYI8@`G<;=4xiU?DhMUsRFb#^)yiG HHWB{=cU-5K diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png index cc8d07f6073583475bca231c6bfce817ae42985d..5f990dc02ada5bab00171e84055c814849ce3b68 100644 GIT binary patch literal 3792 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 a1r4v%&c(^|ko#0g3eeF6KdsVu6Z#*)A%05$ literal 6043 zcmcI|XH-*5)HWibB8t)l1Vt2(UZjIck&e;{O`7!Hn;@Wa>6cy-g4EDMFH%Ag>0JoD zg&sl(5K18Mp1aof`}^~*_pEjHoO9N!nb~_k`*~(g)JHAl`xHzRBqSvFRaF#qfVKy? z4epQwHgrJe3DA&v$*bz!0j}UXHva(cH@tL|SawKA7?e~M-|6{7Fpz)@y{YWe zH$HBdAguSKx47u=METmt8o30&gkr?F2V`604xFb+Bkyq(lSowjpVKKy+n4;7qK-o< zhgyH_O|`Y(a(pGdFM3}StLdhs@1u`2KT`J7|GB;YtFhD=5-_qA5d0U0J%yT_E@34R z%aRDM*ED|&d(N3G-<&GL2-JTlzx=#kg6I47%R~!b2oc7!Q*NEc$FP-pHxa;BI8V4R`vDSW? z4|3k60!o6UOmXjneN3OKC}qe$ReATnHqr*1a&xHMeG6t2UzYWXIO#F_m5Fus%PsS%g!_dVtKp)K?5PS}wKom?dElgZjXR*(84OtHoOI#0_T; zLCuvgDHN5zjx|Q0CUIIk3B{)b(%>eaH*O(S5p8%rQPBon>B8`x*Bhn*{h*;7@yGe^ z((zxI;vjCq6v}xE#8Ckp_?qDV7qxE`aO-rjLFW9L&3UO8UzWqc5*1tg*l^uukS!#9 z%9*5N@=Zs5BM~y{_k^XsVk@U9dyqfl=35!ot!4AzoZGCSpY?__y`20%FEZ^Jpo)7- zEX&0n_k_8$Jn%rzZP`0wnD9mwydKxt$g0Dvdt*CSho1YAV*|UluOb#N5(-?fP!sri zgWIRzuEBtVKJER$?SO{;;typA{15eJr>Tt@zR>1IO_#P{ET=$?$I*Tr!Rb2i5!J%E zCdE;?LxR5gi1=g7n}z=J!t0Fbhf246U5%>mkX*n02OE6tP}#hJ)4qSh9m_XZopoO^ zUufydpGsGt>3PL7Tg@^HTys6iaTB3=C5sLAnyh21<$*9h{B`R^KeVnFszy#~$=`fs znYMW5Zmd9}m?s1c*m=_0euHuMce@Wd+0=hHBAW8X!H_z3Vi8ULls?95kP0bs&3wu& zOx8iTzWjPJBFDH}5OT2XCW$%>qJ2!dl8O`)B6dliZ45HgJ%Oh|GOgUcFvnCHtHTGu zCo`X9eML41)Uke+38N&5m$Bw`py&r|BC_);M-WowP=ee#I- z#S4>+`gQ)@T`=8skqXCvPor$-AlyZ}{QT9>EwqwD~7fl0r%n)Emq^Y`Wfi-?v6qAOWvQWDaAH4z6gevcwlr z7p^VTUtK=2tgZSWbpKA5BFyAHaw9CbhT0M?f2fESsiY5NUF77q2(-;2)Glv6qc=ZS zSYXY0wMb?7spmM$Gs`&WtmQR&d)u>Q0)9U786pYGsx+rsZa-pRky$8G3+;|R0@b+F zL$7WaEMD+R`|*e$ySJWLL_dXt>CRs#J7pI z{dpk0G=|j^0_bSvC|Z;$?uWjDi|i4YYPLarc1(`iurd$=9~5U@!%4)zi9*m2#49tO z&v(T`(DGI|iRHGf^g7?;;)!%xDWfB*bW(Su0;0&g@L4(i^JRpCU_$W9wQCQQB0IC^0ssW)@M?(3>^t`=lthM4^5^w*~%=N4=Fep1!v*Uu=x<#p^TP50pE< z1e~kWt-spWALJTp)JBf|i9uYe)Q5=f2OV$Jt=8$(i1lg*20=C)Bz5qF11JdR@BQGK9*c@Uuaq*B?&p5-g>;F{QTjaYLCGy2!zK;H<)0zp|CPkLPIiR zvaF_I$)y7_|K?-AyWc%L5bGUmf{z=}1jjEU>R;P!4bZxUzV(?Qty(EBA*ri7J-jLs z&_|DEyuMq(3nVE3e}5y&C){D`vk~8W(oR7ETMM-pm-Fh_^>rB#*s7Z?b#y2rHjw0j zsBh^s%hB1HXU^fXWgDiyUz!oB)i0mSPiS0+(6u58`JXTTRsBp7Tq9d6Ay;zU3U&8C zE;(Aw5H46g>3K$oj~g!NDXIwSSDH(&=g!mK@GyPKXz=CgtsvQ3!GisFl$4aap0Z|s zrL*lkwGS(sI&QrEl20%t``P6FF|?SQXxwK{c+R(*6jZ;?t}`-6t3C?OKbxt9cHYW~ zqKVeCmk|^_(gvBAn~K*p>6wU_1549?HOIz7SlBJHprNHoojSYhEI+=fkeyT zKyF6H$T7DFd3{#fIn$!nQ=AfCyZH)B@+W!#ckA)aub|t?3v0n9283Xk_ zeg0nl%e7>!;k}iq2Wt$&P#-~NHYr12SKV)UMIDs7+LtM)qy+LUf_zNNNi^rqr#*P} z60K`5$^;Garn611u_W%KFW+35W#%@t zhaL$R>Di^5w4N-S3U2o{*nsYOIq?WjVCJNa_QZpXZHwmg#S3!G!^9%Q-Fl&&ncbkt zS5+VpW|s+%D@l>D^`A>`oOFMqJj&^55MLbY^H9tFp|{yW4I()lnnLm7TmqWQUiZo5 zFDDU~SPUQcK^Ap{QQ4u{5%#^vpe zM0=+vVHW>Hj0dXD#3*pdbc&F6!g?~@_%roId%&z@DPFB>2O<(&~Z6UTc zd5o@WO~&GDK)0UKM!TcT(09n>hq8qdvqJ;FP1?R1y;o%bZsI*A%w zI%DvquXEkMF^Ey79WQ$mlVaz-?5B1b*Sm%4&fdux0A%gqS0}iH^mC$pMqD62LZuB9 z`JD4s7$0B627{NKhRqf@;ouZ$D!Pj^lXVR_M~mP2E-$fX01fef0WUYnHZ5k3fM_CzYr6N}V>T+`cIC(&yJn0FMTuE(G( z{E7>s5Zq%^QAAp%?!b7zM_^FUI2sRhehJSV-B|5deIR$WN5Z_cpf+3}TxlenAY!Yp zZM@!rk^3>Ykylhi9%1Q@H0Po%DyaZtS`rQjLDCX4Gb4@sIip=7PXEa<^hn^jxvnnF zs(VIPmpnwv?$7Bf25D^GI9CntB>K?()<*8&p zC!mZkophT_`ANe_TpO8lMwNYheC8N987U`_NM$!Sf%!%^yAg=w5L8y$p*V4Sch}0o z;;UJU@3TSSt(;IfvH9&)@hG8Jh>?=T0kalf7W&QY?Rhw)rvUXq;PR`(Yr0@tN@&z(1 z<>#c@z2&It(`-zBh^2BVlybCi|h^?w(YhM{E4Lcp_Kda9}7Vh zJ3CGc1_MyPMZNJ|@(6&8)YR3vxw$)?#qyEpamV^^-In2i-Q__?;}`nQOb7 zEF1wVKYY!aU^Ve)rfC(X0hNHdb9Bw+v<<-ZoL{I^`Qj;D5jZOj)h>)L%D07^k536U z7@YPof84&t++1c!R}6eVxnI%G&rf)i@d1De8CF<90a=Cb0ksS(m8PbqzYNs!b+r*? z#hcZQI zYWw?m(5_qcevMuiMD!#wqsLm$Fm6i)^$g-mLm%_qj*ZBVb(I2xuXaF$FJX0r(rBG5 zFcUX-optT3|2otO)b7u}OziaX#~%_68j^-86c$*onMjYCt`^; z^O$~fxrcY24hjQb^T$;=lxz5Ur2qgbS$E_{8=t(PwS*wBWPDQ;qX z{GF<*sxac{{C2VQ%%AD($eHHTJGYtU?42bCVoT^Wz@{UYlTH~rnWIhe%s78YeEfsM z!@~@j0AZ4_xBve7A=VH&+jp`Ux94PExO%X{=~|?pumuT7&J?drDoGv~bF2r{6hQv= z{(ccq6mjn(x>r?vvoilpKIli`R*p(|bYc|Qk58bGmCWHyZ7(t)e2Ch77~Q!%d5>FSQ^lE-rkxZtWPh$g)xqi9~Nd zzsZFK4S)^k=;;1VPnYhxQxp7UMw&cON$2+b8i_t|y4LX{M zS|St6Gy(BU6ZLp~_h32eY9qj7V60jvB!9U9Pe4Gx4CZ8Ag-caOSm5Y_C@L;KIW?sO zNZrq$Uk?vG0|NtR>Ktf*YA-E)#qvN|M_^DG;COclfFEFmh2Mc_101gf6De744G=LX zO9i??v^d}A<2Z;N9V8VM6?Kh`G*OCG#uX{4spIqWgAFe8g5Y65dy;Z;a{fBi8?z^> z=wLmY-J4ATzT&07r=+CBsgYFxF4vZy{xEAV`clC3K2RiASBT)fw`EgBam$)7X+jX! zWFm!VI_fQ1xo>J5yN+Y_qDH*dWXP@_~T?3Ew@V8V1%lMSqZn<^&l{`=r zJ8Y}|5@lN(Ff;Rp4m|vxi9-1=x!U`82PFiP-DGtomiX7dNUIjUbX07vPo5KOg zqo(+t6bMR74vgp&bZ&B~HwFO7825+fILapzh5v62k2`*Q%qAuKzlBX&HqI+UB$KfD7u zh;inr90o}QlmRSDdGO6f~U-hG#fC-LSi=7eT0y2naYGp_>9 z1Dxjp*|db!r>?n60BrD_KE_fEte@~RN@?sjA%4z$$+dA3*uaP~DZ!C;Q-f&lU$F|6 ztBkdh?<)*q49fKJ)-(!LbGHj7cgA+SOS>pkliCfM!;Jw(2THlgbhrH$_-)!}pakV| z1o9bPUFX4Q4cGSTe08(sntzOd7(h7ba zNQv!!0GrHAU9zne^4Zl>68Wb)@r;-`ofr2_u;i-^<9Jx`RO8wIGY88qGMg^bb@_F`-*pmIB`w8Dd5iG>0oHgG@&Et; diff --git a/packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating.png b/packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating.png new file mode 100644 index 0000000000000000000000000000000000000000..04e82477f1602724658548078a64148eca079433 GIT binary patch literal 21023 zcmeFZWmuJayY_n{3R5Mf0Z0orrF0HJLFw)mmG16P6jUUnySuwfkrt4aZjr7**S?0& z^Q^Vsz1P}ny~nYSWA6{kFU&C}6j+z7;#k;xW zCI?$1)n%x^tL0pR`m`vq8;HKY_)JAfoG7x_64DA&eN20j-qGH= zMMO%PSy1rE?)Q(!W}{_xYWfI!bR*8(r%!mbTkZ7DCp$x-k&$ZCrm!ClOzghl5|daOuYc?%fk1=QQtc_9OQg z{k5==?y_F15`0fa`Dk~QGUf(i9M`@Z_~5|zjBUJP^Aj;;-13CdKZs zrWsAl!I~}|D{pF=6UAnfgiGZp*w)r&-+2isYi(`)QDW40oq{4~bGBuajUu{GJ=b~G zj}vpD5fL}sc83ixzsMeX%cXTGXB06esm5=OjEp2>)&B(dqr`ZC&V_Q9)1v;Q%)DY6 z$B&X%nUs{&UVtAtmebWu{M8wq&S5rU_~p$79=F31t$=!`ZGHS3j|5T9XxS%E-e?8j zBkb>rom;JDn;+2AcdWJGTIyx)dYYE1W6r$Pd|ch4b|(xT!%FaXK{2rpVT>BP8pZ0e zvQq^%SQ+CpGc)~VW*SoQ{8~;ELR276N_?8fbejHbW7LkA*~N+yE*_A3$a0NHJRNyhRzbh&5J1%`*G8}+4S+AMU5 zOGwy^IALiXFlkmK!1FNK-xw)yt^APF39`4+# zR;<5xe6TIeYhiAlmnI!6PI$3FF_gNOh?+W|M#%dw&~$IlZ%}XA(o-j_Xc4 z7UY{b9&D38m?h8Ts{blP#bqh@`Sa(){n-G!?M_aW&1gh0vZRC!bMtTsC<=@`1kMht zO!{>OHq+uRnG-Rcc{bBA>?)#kGN+Pk3#VeNyHb|ZgJboMzK+gKjlcJP5RdM zA`OEgRd&m1q4X-o-`-zQI^aPPQc`a3{O%Dl=!(eaJluKEKO3)_(1r48t2V!O zfwSy>%ICS&I|oh@cCNQAWEP(!zGBQuKmN+WL*DbOe1b!>a>3VjX2ZUAdug)7W1TZ? zp~7)9>8^B4#(sT{y@^YE)k|5~wk?znzx{dFWb?Ia=T^-o zgm#yQWKIr4cLLwNdpA zmrTc%Ro~C7Y%Gv@ocQyTPk^o2S&@fUxTx6W)Rcvk7u%D*V;*NGRl6f51GO%D?eThQQNoLYS>HWlLPJyGCem?o4mslbruQFE%dhVQc@$9II?d9i&s@Ko*=G~f#AOdN z?QnP1wfIgHlE zDz`Qstq?I9#Z&T7@U%Cmb@0ak{)@klZ$Nc_5fsDmV zVQ=lOj&@pXZf|@(G`;V_Qd-QmtYj}8tWhyLGlSk4(&2qb=t*`DwiH%_F1FlNYN2zy2M=XAE?VTy>k7I zoy%y+@z0k5-0TFNQF=@LneA$x z@%ghY0lW{dBZ|Rlghqv`*I{nvX~j+oJ$w3eakaeD1+#H*vlAkF^3$F*j+-wid2CxN ze!2%;XZeOzXxi`m_WEIl?gM6Kx%}GQsJ>fRmL4BId{D2l&D70>)%_z?ogg-C43&gg zRM@zA1;ZMBqqDnvU7X|B9sxZp~_%+%~@=CJJAM zQ8t9;j}cpTgfX_awmxE-;L_R3vp5`<-{w`x`et1(Hr<<0XRxK03j2fEc$HH5gmboA zBa%@FyC47YhEU_k&z88)=^n7YvYh5D@+dylUw&1s-}{ZU1ATC~hqp|xoHI4vij0kf z>$n?@2zABss_ZOB?*(?Ln_vds&!4J|xNo5_G8!#2tC|nfSRu#p9Hrm8wACI;?{|4e zUEFN^_a5o$Ju$mH4u(i~T%@#jq|`*OR2|>M>lrG$l~_8!HZrg|NF`R#kMt}>x3*@o z3(J%D(Q>_dnQ3O>%N8C~KxA9+y=>TZz1f{b6YN|6h$<>6!Q0NZbaPZ7CQm`aXsV!|Y|#C9Q{>L=+gzw?$j_vV z3{jJzJocQ*K1d6e8 zdabOOy6ufSFnu`RP#Y2wVhFe1yY%&*q-;Wc->pdFt2edKmj~lVNCm`?d>__XI^RVK zn&7tKyNEt~_^_NJu*Hx3o^Mly&se!dyaWrDC1oGh0jzn=@3LJ)>-;EhWPV&K4a{3I zRb@G0LX1NjeF(D)3O0&X-QC@{Ol)KG*bi0@&e91t~uZma*?MID+#z7f=@Dv=%a%dHH>}Lg_0K z`-^Hfv0s34sGu({EmKIBmhOH*4-z0;(OuB|XU}V^tjtY6?`X9#BqOFYp@Z>cd~K=l zHamXE63%(j!JwcZMS1xdv?L;X1wQ^#WN($mqUJNzRY6j?te=H1o8Ng;Qrt+7B71tn zoZlIp(U*)^3g|DZZx0T2WRDpfR(t1%+vc@)Z=hmf$K|n_c`IR!CFtaSxOlH|m2=F} ztFQPc9qpSx2MpUlFZMORb7rK311`P0Vcyl=ZtZ*>S!-E|joHDD&hQWDoBjE%TjLTw ztN9oUD{E{VE<*QWP^ips8fU$SRX5DfjyS_j68BZ(JynUIfan_RruXYg-qAKTHnCI} zJdfJCyE(_!78Sb9aOZgV<%9K`{i27DVz3%QzYmV!;FEEod~@@vK4MOWvnKOzWTT!B z^(lO*w^u&h02En8P$WU?>FM2v=W7kE^@b_0>yw*v9G*~lj>QJ|Y-@pv#SF9lwa+HictEdpSDMT~28S8?? zben4Nx*VpA60{D|E((6tZd6ZxX1@R13@O!a^v1_8uinPa|4zm5jPPPVKa5^j(JeH& zPIBQO!D3}Ue#oYaU`@GyA1sXzppY#juVaQ{P;rP?2a4nHfnzB2uD&>a{sgg11*y`w zI_bV#hnkzHZT5I?3i79~7_nsR!x~2Gt)=^s{9PVc+G1JETOUE?xgC*vVYJ*eXVxHw zD*eeKckcnk>^+O(JSd&D5Pn-T%fQc+Ds_%A6TgIDL;`mJT@A;O0lh z-fns1La(Eszk4C}yOr~8p(B4W@(C?d)#b_h`ZsUh#Kc`hO!WpmP8I~#hJ>Q@SXRBT zG<(`914aDE?)WxYJ59Sr*>1!Wd{Pn<+rDk`OD~#{*mte|%spKA+*F)--GP1|J-JD^ z^pHbK4Amk_rkecpL7%hBqJ;O((OPx)VkB%e&jP5-ehQ_fr5S@5U}}3cSGf?Upr2+% z$nA_a41aZQN?m)N$ji$M3RwrYodK0_lD+OAb^PEZO|yM9-{N1rHUbhCJvbS57W;g% z84xB`pYWG9$EaGozrngZ*jD%ZLhISp3zZ1LO0iZysGMCcQp3e zc_iyT7nf>JPtV7IfchK`kY4zdJc=qhW@AD;Cb=gE3-Rm*T@;P#l9G6++p-d&E*I2- zPIt@eNl89#rC2oc+?2nw>ZnS`;f`J@?&e=cb0K4sAfgrP-Q5~TLVC)L_j=@su5+Wp zZX4~%J#gAfAE`7e);(#v7atNIAKzz#C8!6Qaoo~HTRX1V-_DKj03KOZLPLd53{;_* z=SWCI(8|orj46Mum{+eYHf$5T*GoPr1bu@i0RlZ8WX&(MC^Du4`?Y>IhdYlgluOF> zT;lO-4$cge(&4=_aX+rT^vnO7(_~N*N;Mm2CM4q{i0YI1haSv1Zd+~loTuNB#KbKI z8N|COYm}KX=YTTRLI(;mDo=Ydh~?L8eXOai_47SS6T9b^Z_Cx+)|pnWd~|rYG#{>G z?|d6!ZOG$x=PVBT!a6b>n?|m@wPpV z+NIH6^`Zjtbp1La&lbOv&W1Bj+V)A2@z`d(^g=viOO5)TfsetF6B-iodw0}gXl=Y} znZ{vlEVFv8N+LBC_Ub+v0V!DNtU2&ogV5(p~Fg$M+hdhT&{G%4lM8WTfdw?3g2@Ahk-YAZQ_U%opIWw)E-L};{IZG@Ei zbYd65jp9F;yT)$R`_0kkMRtjkXGlqd|K_RX@mucRaIcQjQ9&3J{3mDy^T+3(7dQEm zz^*+~Ld82PmV31Dh>}ZxK*c8|=JGE0dg8U-C5x1J0{3KI=Q3q+@sHE)R8&;XXD547 zI#L&qwY(&%UgJ{Z22U*Yf(B+(%7F1e47UxNe&sWs8b!KV)swe(p7s(-r0l7O)T+0?EiW%0%-6}+?~GD9i$RR>Wn^UBHooA3 zG-MuM7nB>;ER`z(um{WFImdF4C)VEIdTL0`~_7MG`TiddQKYv9l<0mMxE6blYxq zLel%d%0%XyD5v8Tj=9gG(V!pC5_AqN^Fu|b>4T_BcfN%kO*fA6(ICf z&zDPnhS5%BoE(k^oB1F_+1=W)$%rWv?5r#dhZ6Z}s})AvRmFK3Qx`-H9*VvrN$u?| z(&eJh&j|~;>lSv?Op>8TWwdVKO^f+JY^^#yGfm={Cdjsd6tQ564L_`ggDU&gEY3;S z;xRYrI6h2Kn&q_pD+=XO=6*0AE*^jH&YhL$_8(jGp&o9cu$mn1t>=5;nz^{zg`bh6@_Ufx z{xajq>KQPbQ^`-fd}MW^Rs+^c z@HTVzu@^PkPlx58W`;R_w@;-M5!8G8_O0Pio)%_3T|8nw8(PzvG~COxU>Y?qRF#Ym zRKEgtMy^)1GByrgM(+Yv!}!k1utK%{syw)`W=k}1iZA-2G)ZC5e^)#tUOpQD+Yd}y zjD7mK=|!PV)+I+rN5ijgFM?P2LKpkF%Ffb2AJ~tjhCQ?c`8xIDEg4Ie6qJ;?b91k} zUm_|sAe8Ar7lOWYa3^upy!mwG=E(O(CT4=N3wV^?H~04_HHDud2N z)LeFc-5(pU6n9PnGt}1Wj-)S>Foo3D*VhspMZIwiejz5+0zp_83y(H2CY|><&a0Eds*v<} zclCQRas63J*=)AIW!VjXB(%3&#>4C1m~Jd}-Z75lvU(!Je~`k5LamaLB6Mt)Q-UYx zKAFRHkF)F#*Y07)z7l^JtQjv}yg)By=Yx`!vZ&egK8KCH8byK_lfm+V+WyWeE+cc6 z>x1{#Um07QOgn*AR#xy%IvCN#bOI^ad{|gmWc;ob-h|XlVuz)?;mfH=Dk4z!fv6BrVvK8Yi<%z2Ni1YcOUbzv7N87}`b$3&y?E?b zz*I_5r(n5xCTD1v@kB@{c1wdFvGksrdVT>Hce!lT94G@)@uElQoFzx~#0z{3LlKl} z`i~Jz;M~sOmQr5Vl)T+mkQODDC#91nUplMWf>QKQ*-EmA(!KSV?3W2w#Th2H?lW53 z;Wg-MUx*ypGfVpDE1^l*r1zWVHGOcZ&{4Fw7Uem?&R^tXjRRNQXVqM_sVYTm*IfOx zlMxR32M<2`;Bwl1iQ&yH4w};nO!ReXc~z=y31`Y4QJrh%!ddrxvzE6cxf&{j{Cv_{7HerBL$V$}PY{>5 zV`1@-h$Or<%HwgQTBNx6&-_x8nG(0*Sn!OiN zoiLnKP#~MnaG0*`yhu&Qu&_rvF)=YxVib%iJ2Pi}CTo+_50DBH*eRB-ha}E-=oB2V zE-o&9{PaoD*|}x!#%Wvs3`4|pN$KA|JD7oSLpEQh@OK(Iry$r zmOY`GtZc%&%OpU!oaRq|{Tv`msQE0Km+IClaHE?I%&4X-%or3cmM!2bnWxkRt2C@QAFl<5^Z7f81q zn3t2ou(LXg>@>&*aa0c{|?tT`8OaF)CR_$~X5*Uf?)(I8KNvDTkCd5ZuU7A7g1+)Tf@H(*F5dOI z(%Xn}3gDW^-9UVDj($K5nGY1wxY)d)u!ZS}kqU4EWNS7nKbfUsxOx(~kqQAYBB1(? zo|svfolPDvnNaBO9AAm;?9c7#QLp`l>KnCy2mpXBA^}EX!PU^<;N(bFgQ&r9CKn;* z6Pzq5(PFyVvP>2-+(DJTY%-(q7IMk_xRkWCC9s$r3<;2eayY!nc$J+uJB%c=p9PP> zl#=e~%T{>^FTRxcXx2KH+OLkxm+&ED0l?P)TAEgjzbG_ZB)7=2S%_YV&3?i;-v2cJ zc$vNL5a`yfF^6ZA*}w3XR6Mf~r^udsE4x%o*u8?sD0b7o6S_If>4T-CMIdEYI{59G=TB7;FP89{0DfefW!RwJpS>v4#nq=yABg}g9O&^Iu-8oqh zuD*Z6U_$)!6t>bQY%`4j2OiW4w@*lT=o8$vs61t&^P!U1GC9N_Ztv93L)wFUad!QqYi-A1D0<^3%46Xcz@H`!qQ{>E;?0n<&+rQ>Gix$(&T3Mjd}s@GgZE2_QT~BVtDjW~}j8MPc8zV#-rr z;-#_S{b6n}QCAffu_}dp{QbWxFn*5ZAvHI!!cMRreDk=RFf2UXr>3^u%{;MhAYVg- zl85YUIsl8*vzkT2gf|jxvd7cU1_}9lHMh`RNqP0+ADOGmI z*Khp%fx&YrK|xpHf;~S*)1q{Tg0txMG41!eDBc! zD%2910hW~Es=>o5jxEa`mw=Ah#l=K^zJVj8q5U(#PA+1E-H$N1H#4Za?fD)ncw{U;v$-_Y-0

gCgUd0!3(FlZi%jX<+}sUw!oU8qbS4I>2ha@S4p37_cfa)Y zCGic7ih7~Sdc==RiR+sL508IXy9seA%W7Vo9h|8faH!$jy8_XCj$bHKBKSO8C?_j% z8xDYY)zoNeG1&KERaU4@u8tb0+O#qEZ}NKqEtUoUBz(0x#fIL_xqAh zzB*to_Tt4O{Bj>}ZyprP=9gu8ZhNcRpe|P-tzkeiB_?mlqNkm;jy=`Jk!^3_Dvv^WmaY^>TAF)uZmS+Syh~r7e&3 z8wQu~@s%ts3ozsal2tpbV|7ac^op{wz^(PW7BoWLcod8>Gs6e?`1tzEEp#vg`y+%0 z+hK#PbFGA_I~Qy1+-j0vJGkhCR47-jKXwOi8oxYWYdbG_OK~`g-O78kFW>8|{ zSa{`UlOG*yIUdR^Fsa7IwY6sEP@EVvX?T|c{(}+KidpQG^-qR8PPeJk4Km-W-7V(7 z(GZ$DhUEmyO_3@?xY-$C6!f8q1Vv=F{OLijFHdZ!-LO4`YmV0IC+|ce73t9yb;BF& zn2n0KcE5(D=o9tFdCAHJrr)O0Wnst5N{xq*5`eW9ktKyt7RL&Wf`S6ZaSVUOvNdMY z{eYEqyJ!{aX!xJ@Vt0|ec_nRT0AJ(P4nrzBZgy&BUyc{p=DK*ng;r?nzI&T{LF`@T zg9pHc-g%euyB%7FUTDyJ=0}$L^XJcwva_SoJ7jieUR7Cg3FnpuDsxUdtY#-OhDRe~ z_@vxT-~2ma3&KXS=>9{(=2kjw5L-HUdc55o#cJTM%Xs&$H_VIF_S!cLVjf4MlX&Iv zybjU|cTWbcMAGSPrL-uj%05?hfgmV=cF&{eN4js8hVm^`$(@Iu$F{aYgzQ6~jaYBn zC)PvzZt12Lol_q%F=v2V^9u_LnCe2UFI|RnEDl7|pP)xKHEMs#i|)}PjX`JBJj5Et zgx+CW1F-@0{z~;|eIb4^wCT)Nm?@gC-m=TrLj?c48%9tXa)bxfa9zoKeE=ChQ)pRwlE~TnExQL zFGnIqlXVuWQ0|vJFg42ElnM`nJr8}?_er=-B{Xutr5t7HC_h0h3J`xj1 zi;?}%rvCC_da+Gtw1alz8dcIKyxGL#v}p6*ABjSgQP{{zE(F=4_?(J#b72W6pLDOb zU!Pbl;p25!>(_D^*BcQ6cGZW$kOqB#mx>L#l>rvwnHY4(4J5qAMmPPE+WoHoyBI%y zX;*+y5rTKRsDIKoN1$&yf9TsI_Z!MkB^)-Rdqmco7B^&CLM<3=MZK?)8rag^5^}3@ z=z~fCZx7Vk>zSEPI(m?8Tm$pD+K4a`s(4rdm!TxIar6)1KNLl|?Dh{A8{jWPA~vl) z8b{XUC*MsB2Zcu}2TBre`N9Qd{OScJ#>4cN=4MRy3znKl;)XI@L^2W@_ED)YWDa2$ zt-Nr>vy=FtcFynLhJA{!K2II$PJj=g( zlD&_B{$o@irz<-V(tn<4Cr~+C2{6TvHy18bSi3`!2{A3hjj1n1>fpeKbpOIq3(Bkf zMdk)qo>qV7b4sO0fYScXYROD&x!vYWlQAv>9bIp9$E55x{Au+^XWV@!KzU2uPn;nR zmNT*ddyJ#A^AdRdvZA8z7x^vf4$@Bhd4%I#_v_@{xl<T^j+I^^Vq#)r z2qR+ff2B-nn$P)-dOG%-67m3Ob_O*pLaVzo6&9UeZ0QUz*VM-8aOpt8FvGS0;$@xj zoGP4eb@C13oS&%SJhVE~f$W%UIFlBg8x>;MpYa)^HX*7Wy%roFpD%KcKZ)F;LiuP>ex1k?dcn(3-6xNF)_&*84W**v0#*4tGwLKW1}pPn!3DDV!Jw0 zszE65NM26M9EN|`*@`!;9+t%270uE+Tr=Cw+RL**(R#EeA5 z6OYTsoR=+1-<-?dU71M6#=UB{vJj7f7OOw&I@4xx&Y%Ac#kBI?+IaRB`*rudk92MX zo-SKVT&dEJN!9CWw(<$Zq@U~r#Nz1BDt6TF+YLP6yXLJ9?wF!Yol2ransY*kD;zt;e(f%w!( z%-Qy*AM64J;vV)u*f2m%YB}*X2A5sAa;0jmYWX@D*U1aHBNGlwAV3X4Eg+-dX;u(W@nv8H@3AW^5bA|5-p$O; z4ixE0_{0+;V^9p^qeo2gxodq~Ap-+bJ0fe>(^U*JM?f%P8VI)b_R5EJJrv5#wQ4uM zUIsA5<`zzc{8WHS2oos>kA$9!>*rcaxhjJ*lrwhw8@ljOH%xm(|9R*WxNw;`LpqiR zUZZY%wik?g=IH2zZ^25nJl7ViUTPfbO+c9i`=a83BlMtPK$>#CcJ8%%(!ViD7KmM- zZea_)!y%x^h<85}J3CqTz_^VNBduv~0XG!$WHI0j1oxsJ=Y%XscdhMnf>NL}G7aLK zo`Km{zY_?EPKkda^^f}i?*L&nRi5{;4ZR1H8VbK5Acl9uCOyt-G2v_&O#pz6U<8Dt zLTF&S;vBaPhR`z6l`DyuKsZcW8(}^qgU!Oi0%Lx`?H>U0nFW}Y9(r)V&jLOx51k+2 zQF!b{HZ%xg0s+u}gLz(Gzkaoa-jgbj&7RfS;{VJzj;TSYR~8;AhHv@`;miqOicP?G z3ho`aNY~%cy8`ysxc#VEp8q*Sg#kEjm;R7O&Y$k7jLiR}T`H(%LcOkifK)R}TDu6- zesn9qcft1Va*gr!NSGTsV`(nd#tu*M$%iHls??`>{#ZZ1XWvvfs*_TLf+st<0&+=~ zdPTN|9txS+LWpOrqtiia_mIv)*Fpu)rRT+<2b~-(6-bN;1nR4T#P$Ax>k6V%yj&Qx zxeZvgVqqU{?#|Dv;j8^Nf`j;9yYHKFbv~xk8mL|Y{i)_3^7#Kv&)0u~=_*tNV>YZm{AU^-*VA+#F)bezZH6=FhwUCYC?Ke*5a=xpdUa0V{EI9ax*B? z25trLC0)FB_dX~ZIXSF`yHIySrufCS3CG z%EaYBzJZsE8R_SP79VI+3JD5&0;?p`io35J(DP?t6hrr!F+`s^7)|wI5dw*!3XvvZ zLcR^ppy1%uC?doZ%B@7G93Fs@fC*e~#KrNlRDGwJ+yZllqA{JwZs34g zIaWWDJ$WE2D=WMH_Zx6O3szmq_BwzYK_5WG%2R&WEj)n(l3~gjQ z4r?(d@=7-!K9qqxpTa^{Y-m{6uafO^6{iXfG#R z&!q3u5!*sh1Bp(bd60?OVBe}k>(;YRH{?R|u@TH(0Zy4M+_6%nCX zkGm+87ED73)o_lt0CsRc!>U>qt|G&uxOp~u*nT#sK^M9@(`Ku+e`uoD>8u<{$!q+r zi}En@jm9y6o^0q7Qd#2rll^+Ny?zcEnE&_aSMdQWFrw4b(~o|Bm>gU?H(Z>e+1g^!8P)$D zkqGU)^}P${5Qi5Mgxr|O(ncep^HOGd7Ur{%%Y<-as*n#sCP<&OBj{>0nre6r1x-pj zUkW`vy#%c9N*K91uF%U`XNPu zAYs=k7pS1xj9O!@J44(e;xfxvPt#0hl-tr*<5#TLyaPTB#TQ90?n2sawX6C+;BZ8{ zfpKw|z$8ZFLCk3MCF6f zyWj0eeN#61-JLt?HkO`{APCXrd-->;WN*QS(N*GO`m-Rh4kQyM>YGRk#18;& z9_%|09zFVD84vuY2jQaNmGZ!@T&e3Usx_h+-F*UW1zR~_~;R}8@@&afr*lL}FV5@^((+NO*4HIP+ zlX(!&C&f_365U1|=tkvbl!2B_%nSGf&}#+(L3?gS08KCZJdfeglbe@|I#)_-J>|0E zs=M9WCvo}sSZX-{wHu+Zjbx~$NjF|POGS_?g_!RJh|Pj*Z{x@(AL>Cya{j(jYOeM2 zdi*u&+y)Jco@T1r>wo|KyrLW0cI}S$t3K;y_nn+Zz1n%QO1i>@nR;-unN9;vX|(CpKm_5u(15$UYzBhpg5omAf@02^#sxg zVM5}NQ;3+5jtvZKpx^aW&l$t2EGbd!M(xGuGB&*EndNu)Z`UiXKitoZYg_*e8_YV! zTbqRI(cAT|4kyE1T)LCr-Z#f->_0fy0>?VfxNNg`cLK#f~j_uwb~wtsmnck=B>MWagry?ge5{;epK^_|H6i) zpitv#IL?mKg@f>c-rn94yJh8Z=jB}c&T|RBiqvxt;c?-c1mobzHf+vj?Jd0awkx*F z$of9m2Cvy>R~<@5`ua9P?}MF?fv*0H)ewmpmSCB|KA)viU$=;HE&n497wVBp?HQFj zM&C-WlE*gYp6lb|?ZmsA$R5f((xRdgS)<J~pBXlpEO zm@YL~Yq&84^wr?Tr==f{cZ5dU>J4Pl4Op(0OmX8gvDZl~v`~8}g75(k(~}V*4kh-h z>Wxvn_$}d|NLiaLkDxEj#F2#1lRkRUvj)^QrWbt!yRnAysBSjv#?tDoWMvlEohRM) zVlQ9Cvg8CA_Q%0ALzjNp!Z%q*OX@F;xfU;(ji>zx{JZgxM8|a+jOpjTa3HeXKy7Vp zbMBh~NIbJcvNW+&#zs0R#17nY9z_=sa~*_>RqGjvCnfNbjQ@cTr5>SSN%)AS@;^; zH}R&NRDvsQ$~CX-C~P^eDbO`{ew1LVo@lsiD~$W}R>n<3VZq)!o zx`!_8ZN|VfJM73jtDh+EUcBD*PDSUf#}Zx>EBDn$CU++yC?3YJMoNBMprN()&RGN1 z{cY-t7g2X#FxYzET6~Ap2LpxO0y^-mb5brUd2!`Bb~7`X3!ld|d8}^AU`z95 ze3ML|UZ;zcl;4cndr`Mn%Oe|D?mrF>9>k^JtNP;gdcCeO;jvd$r=7k14456-ZBK>g zT4AYpJBulLF~^jQxcP6#gaYYei;tMUg1pyXxm=@AKofO85nj5*8*CFe?(Z(t)Z*$G z&BTD`{o~QJrh-E7jMMw~&a~My;GPh5&oHQQe-lkTjJX!OASpa&R#eIXN??5hH&k&~~;tqNEvEDq3{m!i5KM@80)|l;x?t zIj3u8D9abXT4m0bw41l@M>V`oL%Vf%c;vPVuN=PlWE~@g%C>?9?G~Pq7lX^d+()h2 z>a;;Idt0U1NEhK0J^-dm%f5Neb{wsP&Cg=0te#Vq-#Q9D$bI;%w@Q&;ld90w z9aJxl6Z&`0*Ue((?0egMA?v0yrZ`@YHyMOe_>1gT=XRD0GB?g@1~tk(t*i_!EY>-I zSolEnB7csS*7_CnY<=B?1{J!vCbjwb`LCPMf`GY<8i|pc9RxOK(oOh9Z6kN!FMdG_ zr%(*5%UaLkthw)m&Nw;uo_5lV?d}kDS!vy(Ee*<*DY~nO-`?K-cD88y^M~J?cgzCy zE`NO>b}b7h{Z6L~d~3y@!2w?tK}R8Ad2ls{F}FfRBir$=$jGkSyWrEAv#oy|X&_J} zfJzBQMcv7+#x&QEdQx4>JkEg(M>e{?Zo;-rzv*ck{h;R9`@axy?cN$_jhJ%u zpPbEyYO@|7+=;})!A3jR!hjNug;I=$V$wYsD=dqyX}i_-c>QeJ{wrHQJG)(UpK+OL+kwt*$~ZWhN23mO>}_z15!g*Vy+0!SGc=6cvG zXXs42jv39NpFh)3oYiJtW%S5u9{0i}>b~7uVM|(8R(fdxoXRU?WLb`PX=x4GmhvIJ zLm!uVuSl|pC*nPo1pztc8&?e3qReM^?8(dQ)%hYj?wk!8H50yJ4P+<7CuUHc3Y8R2 zk(NR2glx2VkDIsfEThK0YfXo05*m;1+=;@*mUAo+<`Mt{wu$x1l}cJxRs~g|!NEaV z0f9;SNMZi{DQvcj6a77gY^~qFqs8yiZsocA-`#OWL4I%p7_4n{$2!}~umD1D!*3{i zyTE-sK8I@KVqLGNu6!MUG&<55g!`qQJ;Rv*yucwzsrv9UpTotgiLCj)u0pZkkqtr_jvds9EWa$pP;y1XsGnMb(Ywkdb>#r6K4UIzh za*3wxV@+jcVg}+(^3NUN4^`lSW(o!17xfqltE)#@u6b0g=?0VNlxkZr&t}a1%p}ov z#F7y>DVd3UFM0yO`_JLw_hPcMvxU}l1U{^vJv-P*KIoImurU7S`_$v_E*~GCmy5lr z9~Wq8m++H&-ouwUNOP4#a4|=_R((@)FITnj98@b`D=Tdlio9g>OD!Ue8~+50X2V)V;Tti#eW2x8; zw%DEy_{Ap~J6~c7h(GV*V{j(D)wsUZQ)NNzu4RSe=jZp;Buz5%4H|75@arb6bve|4 zQ_%BE(lu<#@jVVj4qQf-p&RtVBTy1QFGN?LYY4g{fm!^lq}f{$_#zu0vEaKG7t~km zk6*fw6F7|97;q$dY3)6#uf@*|dS?dJy(9FwqvE{YQ@K4$z5+tzD|d9KcZiC1bDqvA zim4e-L_{r8goW+6gO*KMN3baK9KgV<+Se#3K0#&SJa_crJ>M$evGBpb&dyFzaq+KU zjG^LQf~FOfmTrdMdAkjcb;zkj)cZq%bn;gagIXD{CIL6>tJCF`{dE88eZ{Sj?Z%=8 z|F6=lMZ9ZYX`SpT$jCl|TH7QNrnMe{%IOpEg2m&R$=t>)ozx_!4ucAgy`cidSeuT$ z32hzErPo5T8?$poG zth@>VW4`bDR;Biim1M1p0yZN-=N;(nf4FQt46Mm7vHSR zy>JjT8-p~owBUj)_=}Lxp|Sj`oK9lj;s!(sXzA$0ojZYcJaS#Ge_6h+Gp+vX92=tx z?rQ3IK>f1V&_K4~gOS%!)3>aqf6E;=UXzO`<5M|g!$zQ<^a4Y^d48RiR{olSF=qdV zee@iB?~|~~P~*Bq-|+AU@XLfj5{-pMvEROeYE8u}W7r^`yC$v8ywTc*_v)y6 z!NiMaURpKNpKcAAam;Ca7d5T+;R&DfYG<~{gglB)7XH(0@bKPIa-4Sz!w5*GHND~6jO z-j&ZVDv$cvlI{C`L){;XkEDjy)44CNaJ?*@i5d8)9*s|8svKi!ZLpG%aC2q27#CPl z?E&eHqnR>oH~;tjZ7tT=!B5Bwor;%ReEMNIXJ;o;Qc{xEqNXPCL2vx^&Did*`o1>_ z(wBeOUgPhPE0{RMqI`{IxHd!>j*D)Y&SSbB8lIS&o7-|^T&nI0UvHvX^y))LJr?4A zG~toFVk(r+FCjdKSFe2S^nf$?bKw*xlSf%e$#o+mBk5cpBrqoC6Zp8#;rpW=-N5tM zRQ4M-ZH8F0EbP2dQDhO4cheo3_3_1o1srw*BBR`;HSdMMM_}eO7_udmm6f$D2WV7V zj&-&?Zi3AjzDuGvSsfPTD?~)^p!mE6VF+jbUtaA}cSE8j$D7$p!&9qQ_P%v@6UKX- za_e`+40rJUeI--F+M30mTEM@*UoqXd74w}2gRfKyyl>NzhU*l%|A1V*oSNDP6>X;r zWPZ(Vna&9V#-C$j@q^pGz4LoNMtAcj0=fgTqax3rKhIz58U4k@%zOoc0eUu)!U45l zAuB2?&%j(zuJQif)}{;BBTqPRbGExB02;IYk39k!-_hM&?61Y1l$;zG76v>=#!Nv$ z;lShj?!Z=Q*y^Lev#A0?LtB9p>J@)}18a$mxwp+^tV%e5W6g5^?Ua;EIr#XFsn4%j zRKW{eI(`6{bC<~Na@?n{sK~h7fBrFd`C1lxd;9Xc-_(JlS`mAzOtrMNm!`i2*5i}o z)*lC+^$`#g!?QQ;{kPxQCQ>P>sS9`Qk^-(uEC2nsvqO&cd-e(766r+XG-lp@`)m)T zqSo6|DSv+Mm;xMTS+H-P9B}C*u+DWaC@5I}UR+413AhR)5jZckqwcR2a6F!8uHW-> zCxG1n;6X-Wz{3t&fV-=uEG;cNdV1b`-3uJlNHCECj;=NA+GUklSsh^TA`sNKf&gHj3k)vy-%t>SFgH2^+jJoC>*9arLjR1w U(=7&XLHqAKUHx3vIVCg!0Iokj761SM literal 0 HcmV?d00001 diff --git a/packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating_disabled.png b/packages/stream_core_flutter/test/components/buttons/goldens/ci/stream_button_icon_only_floating_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..bb67068233a047f1584106a65e3f1a41f6f8346b GIT binary patch literal 21312 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 Date: Wed, 17 Jun 2026 12:58:28 +0200 Subject: [PATCH 19/35] improve avatar theming for shadows --- .../lib/src/components/avatar/stream_avatar.dart | 16 +++++++++------- .../components/avatar/stream_avatar_group.dart | 2 +- .../components/avatar/stream_avatar_stack.dart | 2 +- .../theme/components/stream_avatar_theme.dart | 8 ++++++++ .../components/stream_avatar_theme.g.theme.dart | 8 +++++++- .../avatar/stream_avatar_golden_test.dart | 2 -- 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index 4720ad93..e6961973 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -85,7 +85,7 @@ class StreamAvatar extends StatelessWidget { Color? backgroundColor, Color? foregroundColor, bool showBorder = true, - bool showShadow = false, + bool? showShadow, }) : props = .new( size: size, imageUrl: imageUrl, @@ -125,7 +125,7 @@ class StreamAvatarProps { this.backgroundColor, this.foregroundColor, this.showBorder = true, - this.showShadow = false, + this.showShadow, }); /// The URL of the avatar image. @@ -170,10 +170,10 @@ class StreamAvatarProps { /// Whether to show a drop shadow around the avatar. /// - /// Defaults to false. The shadow style is determined by - /// [StreamAvatarThemeData.boxShadow], falling back to - /// [StreamBoxShadow.elevation3]. - final bool showShadow; + /// When null, falls back to [StreamAvatarThemeData.showShadow], then false. + /// The shadow style is determined by [StreamAvatarThemeData.boxShadow], + /// falling back to [StreamBoxShadow.elevation3]. + final bool? showShadow; } /// The default implementation of [StreamAvatar]. @@ -202,7 +202,9 @@ class DefaultStreamAvatar extends StatelessWidget { final effectiveBackgroundColor = props.backgroundColor ?? avatarTheme.backgroundColor ?? defaults.backgroundColor; final effectiveForegroundColor = props.foregroundColor ?? avatarTheme.foregroundColor ?? defaults.foregroundColor; final effectiveBorder = avatarTheme.border ?? defaults.border; - final effectiveBoxShadow = props.showShadow ? (avatarTheme.boxShadow ?? defaults.boxShadow) : null; + final effectiveBoxShadow = (props.showShadow ?? avatarTheme.showShadow ?? false) + ? (avatarTheme.boxShadow ?? defaults.boxShadow) + : null; final border = props.showBorder ? effectiveBorder : null; final textStyle = _textStyleForSize(effectiveSize, textTheme).copyWith(color: effectiveForegroundColor); diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart index 66d14527..f599b2cc 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart @@ -182,7 +182,7 @@ class DefaultStreamAvatarGroup extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - boxShadow: props.showShadow ? context.streamBoxShadow.elevation3 : null, + showShadow: props.showShadow, ), child: StreamBadgeCountTheme( data: StreamBadgeCountThemeData(size: badgeCountSize), diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart index 0ccae9c7..5597b157 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart @@ -210,7 +210,7 @@ class DefaultStreamAvatarStack extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - boxShadow: props.showShadow ? context.streamBoxShadow.elevation3 : null, + showShadow: props.showShadow, ), child: StreamRow( spacing: -diameter * props.overlap, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart index 771791c0..2157514c 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart @@ -133,6 +133,7 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { this.foregroundColor, this.border, this.boxShadow, + this.showShadow, }); /// The default size for avatars. @@ -163,6 +164,13 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { /// [StreamBoxShadow.elevation3]. final List? boxShadow; + /// Whether to show a drop shadow around the avatar. + /// + /// When set via [StreamAvatarTheme], this overrides the per-widget + /// [StreamAvatar.showShadow] default, allowing parent widgets such as + /// [StreamAvatarGroup] to enable shadows for all child avatars at once. + final bool? showShadow; + /// Linearly interpolate between two [StreamAvatarThemeData] objects. static StreamAvatarThemeData? lerp( StreamAvatarThemeData? a, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart index 1d3124f3..5cdbb6cf 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart @@ -35,6 +35,7 @@ mixin _$StreamAvatarThemeData { foregroundColor: Color.lerp(a.foregroundColor, b.foregroundColor, t), border: BoxBorder.lerp(a.border, b.border, t), boxShadow: t < 0.5 ? a.boxShadow : b.boxShadow, + showShadow: t < 0.5 ? a.showShadow : b.showShadow, ); } @@ -44,6 +45,7 @@ mixin _$StreamAvatarThemeData { Color? foregroundColor, BoxBorder? border, List? boxShadow, + bool? showShadow, }) { final _this = (this as StreamAvatarThemeData); @@ -53,6 +55,7 @@ mixin _$StreamAvatarThemeData { foregroundColor: foregroundColor ?? _this.foregroundColor, border: border ?? _this.border, boxShadow: boxShadow ?? _this.boxShadow, + showShadow: showShadow ?? _this.showShadow, ); } @@ -73,6 +76,7 @@ mixin _$StreamAvatarThemeData { foregroundColor: other.foregroundColor, border: other.border, boxShadow: other.boxShadow, + showShadow: other.showShadow, ); } @@ -93,7 +97,8 @@ mixin _$StreamAvatarThemeData { _other.backgroundColor == _this.backgroundColor && _other.foregroundColor == _this.foregroundColor && _other.border == _this.border && - _other.boxShadow == _this.boxShadow; + _other.boxShadow == _this.boxShadow && + _other.showShadow == _this.showShadow; } @override @@ -107,6 +112,7 @@ mixin _$StreamAvatarThemeData { _this.foregroundColor, _this.border, _this.boxShadow, + _this.showShadow, ); } } diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart index ac811728..84163aea 100644 --- a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid_redundant_argument_values - import 'package:alchemist/alchemist.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; From cd94bd39f92842366af1249380ae4e1f4db0078d Mon Sep 17 00:00:00 2001 From: renefloor <15101411+renefloor@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:59:58 +0000 Subject: [PATCH 20/35] chore: Update Goldens --- .../ci/stream_avatar_group_shadow_dark.png | Bin 19265 -> 19382 bytes .../ci/stream_avatar_group_shadow_light.png | Bin 17355 -> 24730 bytes .../ci/stream_avatar_stack_shadow_dark.png | Bin 3800 -> 3815 bytes .../ci/stream_avatar_stack_shadow_light.png | Bin 3792 -> 6043 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png index 2e8ce0e521f74413a0e0fe8053714c71d4c04bbe..b23f698e1d0a98665689bcd2dc01f443d50ed65d 100644 GIT binary patch literal 19382 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 z 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 z z7@cm|?k_8wnj}6LT7umzuR{N1!_AL7MZI4T01rdB`o;_gE-(Wfs9>Pp!AEl5N>?N4 zTks>t+38b9))_Qmp`msgbd>4Dph|&PPEUGB%n%yS2=<=1ko9VqdAf|F5T9!Cg`yCM zxnWYqapAOs1$}yy8{3B{bJ}wQrcB`J2Wcwt4nM*wK94xO?hFdl1fPv6toF(o zrUUd|nAu`2?E|YulNlkvj8kT_0#D;zfeWs1o-}T9<2K4GFu2gLE;V)rIvk-fEK?F6 zICsQSWuhKuiaovX)*H)Ez=jT=ROj?omUn?f5>#HCcz&kXf*(W+~x%fn( zTbN|XMBv*q??sFyk^IGo&0=6uyHS21JdxQr5vJo;MCUOuMDlBmh#Q3tj9l~=OARA?!_~yw%dkgPUnL`WY zCw?VNWy&TdBzwGjX&)s|{|VR_BPJravR1)MJ;&%n?BAZ^rdwiA@6-t-+*a}rPC zC#5V{phWk_<8D;&OFl->t|DKlB(pXE*2&fuZCvOIusO1S$n=kx>1B%YL`g!Gmxo@* zBV{%cK~16b2RuJedjs`B%KjVx$^X-|`i|ck7nV}+Hx?O!khnCwMq4K|@yi&GVtQQ? z%PZ}U$2%uUe&b?Aub&L|#Z>&Chf}$djmq#Gabl<1&Br_17uv0PS4fx|G{b<~zz7hJ zYN6mMTP55oE&5N^OYB->_*V&TBDhib77AIBZ|OA1aJOHg+J)cPN~E;(;tg0JOLkKO z&H*r@A7PXH_R!qGFKf%7fa)Rz;VQPr9t}>v2nv&Ee6}~-+=u)gh478bF)Sw6uUHZT zLl1wgD4R9Rj2I$?nCxygz2YH@RcqWW`kF|c=iGWA7~L(DK_*~yrw7QC#@JDQ2!=-w zU9C9NU^b1Wm!pwnUA)5bP&a2?zKXF6bonk*WQr#7d z@S~?nLd=)AV3f3ve>NK3Vr>aY{`%7nXgP8ENpt9|?dQ+XAlRP8$JsK=k?CBi7Kdit zcb^=9-!v#NJKyNmc1KQ5Od~EsR1{+050*pC8@F~rE`Xt|=y+IK&ZR~gGiTFz##}ur z6R-P3F75+N3HZRG7*J6Bf&}{2?)XewPVcHiFDhdDgefbzpde|W(2dQw$nfX`9e9@> zjh@Q;=0*V#3s&?uPD6tm|ACH@7PK_$ZZQ^zgC1p;RHq;R_FZlEk(DKn)P8jY7~gA4=*X;Z zEY0#)^i!?^>P2t$sC^(SfliP6+^9Ac)NdR(n$mt0ckri1z(zU&_)!O`uQ(Hc_hkVL zD%yUC_y-Wk037w#i1r5oz7W5($oA`o!#UrtZ2HGujZfZjyy4E9_LD`_0Z^K0kx{L7 zm30m5-KHaJjm=|K;)7E&JsOISSHBW!Zi~)^RoK0OBD530Qcee&cKKUG%^?8{M2j9t z5_kPG_Y;a*UN5B1VS46;&!ylP9jyH{t{Hi$yuL<8V#ifrcRR<>D$ZKaL4ZT!-B?aW zahUpSL>GnboGP-|o*jyXeWgjL(rA2K0s^Jcc#F0ZjdrjROOtLoOtu^@{`)DX&_sXt z704%`Hn)pCL_Juelz89#M1}%&r}Br+Dry3iH37$~&)F~j-nW<7^PZtlPu$LfoLq!D z$iN!j2$ei)nbHc{BC8p74efdrP7U1W+7_!hiAZ{GnK>Cd)Y$Mh9P)3a5SUTE4tFv4 z8t(dW-(F?WcPS{_!Vi7B%5vVlFE{LNJCkzuysKDKQCD|E7VWQkYx^Bo!Ja$UXxivt zq~ojVhWrQH$lBq%YRu&2+`c-AO3hLbTkFaSVgIL8)fLb|%#HqdkTg zYmmX~X9~;)n{q_WA@0e2R$ZgsU3@TQzvYQc$)g8twR01B;fvYVEG%8FHsr@)ZxMu9 zD~?556!CJ6U<`6yG|@fWh$^_IeZMQFMfq>w+f08ahLLd0RHXKVtM=2gbzk%dF=+1) z`7wRe$&7gYd+bF9B?L9vw~GuY;%eFO{F&dPmiY`JWe(AdTL*}X<$P%-E`|_vvqoVo z6f{B6-GND;a_-0N%)8arv(0D0SIp-_|A1kGd!1L-S;->@VpTUn9O$sHy;u5n=e^jX zcHLBrEs@FK9vW67WRTY*Ityf)7Zkv?_7HsRmR;I-tK^3KKH?}{$vS6yWIP8(pj|?5 zJ}|%Wdmk2cnj1?8bJ+EDRL5K=N_higD;yHyXpIszj>FM!hQ)GSo$pHFV@qsa4dHT> z*;R8b$t4+A(}cWLo(;dHR7uNwFD^2u;E9ToWpktj-|{o=t}2Jc z{L24sEh>N7SHLN~_D(E^_MY;~6U)CGGpqV-*JGghQQcnc*z<`y{|PZHi2o__>f)^L zU*{jbHcS2eWd^_OpdBk#bzQw0x+8Bxx}$=`SbdHdTq--7)I^Rcz=i4=1)^V(*0bkFahVZXQC?W&oUM)yk_@(&%ezQYh$;3 zmOmu=Fy@ZW!Qz^lp5ERB`3JkVZELIAtGAo?Q{)n$i?1IyDSvn9#gv-WnOnRwp1%L+ z-E!{ewb>at|5y)wNn;7=RAq4eIsg9T4%JKhuGY_T{Ca=+;;MsktqVS!d|DI{7sq!e zwt3gOU=V6ReE=Z@4<%F~6Sm&?6D9%H?tE zA0KRH-%LtE$UvF#qr$nOVrhESTWQ(+LuUhx~h0#%M$y?gL z&2TxtI8$ocv}qeQY-l)o)U~I-|MxxT_16!7`)2m-`}fN44?Cn+ZYVv}dh@1p?PLFr zbhU}IY8aC@uU8WDpZ_?2zp@PTuaDsdR;m_N?UxlzOxC@2u#IZ|_QLzf`ZEf~f0c}` z$J-f;R><|;Yb^Vtdgk82R<}th*VU!O6j{8M3IVr!8ra+S1MT(k^{tHCelsVjx?1{b zmgxuXZztuICAP^GKYWp!@ylw<;?g5Rl1GlOQ=T`=!N#_+B8{taqa=e~&RRzI{KJO3 z3eM=stmRBBwwST!=`OxE2L*pMD}UkN)Uo`S;CWzgIzod-1&a!Qm9)?3j`-faCZpq!QI{6-8HyFaCdiiYg~eR2yXM{`=2v&F6Ls+ z#rZC#7i;yRU!mTr>e~DH?WYKr|1OSHt%~NSPw432PqSt6%5Xuv zMyML5EQuP^oZb9F)YRj2ravXCE)VDVBW`%^35{8nGjB2v(Z@a{(UP1P^L!;zHO)R? zGy4S&vMZEMehgy?=DI|Od33JME%Rtca6~u8YUC6Dg2jj?qGCb@yz&hVR{p)uq4i^- zqoc=%;53B+FV=w?Q4tZ5LedcWe@Bs-t$>5*=3)Agz(EONBrV{e2;Tp(OY2RC`o-=A zl4djaY=agx&7AN>aHT-};$h#T)c*I|7uRZV4O!qhVzyW1(R+k7BA`eY^m`M3 zt+|F`a1lYJr7Izm8GM5ok=Xebaxj>pvvtV%QN}Dkne9)0w(OpqGP|t1$z*>+Z*+Dp ztymAgU#jejD0&yMbnGoB#! zu*8-7;C^YY3hA!bUUWZ?Ay{`9p0>Y?z2rZ(q;287 ztNS10v3OW?rcmqVpZjDzu6fa?I$CXml$uI$i}<>qnmz0|%>$!=dHwG5>MI$0$!xhq=k*s1;dT>|KqOrV zn+T5T?(QPuZ`+$H9NKVxZoYm@k&92&4fE}2B|X08y?DI#cH3EGWBSRetuO2yXQ6L- zRm1FNeLU9C^(ibrj3c#L`0>i#qER%7xy$?XwdHy9IRQ^eO)ENQ-H{fwJq1fNJlVXS zu8K-YNvU3MPiy63s(FLfGFq$74LzmnO|HdZ-R%jy%;b15(eRYU z>&gDsV24|67hk3fuT@3Bxa4!yil+ntQmx#AHjNQ)d<=_XcVE?T`>ob3>#<&dx*6$4 z7lO#piRHTC9s8v-DJf}tzv!}@1v_5z!fU%Z?W^f`MZ^4fIG0o9u@ystRtR0Zo)0`#GGa%}x;>v5C1b&LkA`%f zH!A9Ms_XCd;>zcyV@WhPY(5r{)f98tlNUW3_Y|&+*r4pkt*wH*F08;%q~Xe~ZrR0b zpeyC{U0am15}&FX`ctUW?Jm8;=@(>&UQu6=@<*(DsGpOQWBW?u$rFj1uUh#bK_*je zXyjr@YMs?NueXn<*6*eqQwbB=vilH+8%Xg74$`o(p@`tA%|qj{b_A)6FMyqWx>QdvCY zv9PGxZ^W|G_IMIX4{AAgakkmOD9TExdY?jFIR1@u!1&N*;)rp)58M3t-AI`StKa|C zQ@@$pZo})mOIz+>zT2o~{lx%@hB)(YOBQz%1c>VUPygP)MlieC!cjb$$Zg7q{8qBd zN*hV9w+xH54KU~PadoCg?=zn3ii1#}$;hg{b8nBKix3wDlpK1ENjj>j3;@TKO*ADpW&ocSV!ZOD?2 zN_%FSg;z~KR_He4%@_ab)|CT#Y@Cs|GE9IrDSoO#+^- zvU0#1)ELuEg`@pcW+aozI?b?EwZj?~vX5E*09&!!gX3%-BSj-@!>eM|fZJ{ATNb!u!_cX-@&_D^8+#>hAMaCtfw( z6K#{vwJj_A0x3~sFL1Q0vmFGA$lngJo#-7r{N4|HSuN@IvdPO`yVJS&a88c8{Zdaw z#P%l9?!sghUn`^y0X!ZB??sZN5-A*{%VmXttaTPu=XvQmOmH*0B#gN(c(qZxQ+J8` zOIHv5Ru{tay|b?pIy8i^Sk&;onocZDiR|zSvmpfN)2Fo>_xTbx$7>vwxe+gG!sdCHVNAqJOx5+9H^~f-<@X}C?YhRZdEbduzC0bo&Q|gM zev$zVGXI>M^L`TBvcL5AZotD7eEKj;za{jIKuE!!X6mOW8+%P&U3PqsJkfz-cX}}MIvwK1!0WbLw&A&cAXo2vQ4t~2PeR3w z>3-XzUw40=eDInNN%Ca?*?o!@d#r$+OAoC38Sv7kRjxVhJIcNtG?PqDSlZ2J$Zp@=UqN@+e>`~H4#2?=Mp}dsQjOr17-~XbUe$4y z5Ta<_bbEeQwSM5q%Y_CNh(`;7{pR`wPb+R1hM#<`<=kFI;>oW{OtB4icG+;4?3l{# zE_*2tvr=4U$P}g3dO~y7U0vt)7&>?HqHx%-l0W6_xW>MVEoS?;txcN4(&rPE1y!oE z2DBc^$eCLWE=}7#%Wgq~e)!zFUj4zp%x`I-K6aOqlBzMc{PcZ4W+lo0g|HG08Upq0 zK`%)dZUzU*)J(OFcR}5E=4|f`i zXffVM;wa!v<%pxpUOkzfU&d>%h^3W}_a=__6dFr}l3U&IYi*VG*bQQBw>^7*QZo{0Wca80V{OD(036*{ZV_}_qS(! zyH}NZQt1;q=^bm4GW8At2~Yo*c)nLVw&Ez_DA#3cF$GAq5}l{DucfQqu)xZ_1IE@- zsf<-Q<6f-(MCB$1N_TECs&^4`B}&!>LS+u&AjGEz{)&y%|TW>J1$(B#3-w+WXRx#^KGkWa8x_Y2F#?v0E9KUnlG7Myv+siUPEXd37t+GaQk^5}^ zqGoT6W2=1COXT=zW8PQNV+c1$iUCvWD!00^qf}R{VLnyZsUlOb4&8*vWqR;9rk> z5z?=;*x<5PX}PQ~N8xd(+yX;lI~TuKoa=B}QZ@}F3DVV>Idd&?{9riHH^aLh$=oOG zo_AL2l`fOhx)f5$bmJqnh^x@_PC1@O_UWvMnj*Zc$XekoZ`}MdRu|>nkGwB`AVTO_ zmQZcFzaBGRt0TeQT?TJl^f=!rAzFr~@w{4jb?671++Y+HG&ErLhaf|N=zg@wFSgpY z>;RcTjeftpu5N5d$Oo0f&s+&lsYwY=y}{TP?Dv$ZI%VK>k#IDTuN~Qmm)Q5lva%c9 z53tC%@iRV-ztZ{k=q3-Sq?Uoj!}-@&g8?}06ZtJ;x0OE!2j=X}!>5Z@Hu(b--NaZR zR$?n?5b#9F&z$MB;_W2jNhpG7aXC5F(v=+@9Z7dp06OV;v9HOSBYOPA}IzC6mGSIXjYJ{?K%LF3T zA3qR4W_&At>B64K=6MboZK3xcjcF4{jhqk{B5{GMs(t|dP_9<$_=2jy_11cHDH&U< zUWvnI!egW{v}S95PXulZ)Q@CQ5*HV*t`hf-1X{N2a_$4Z1V07?c^#$2BDZZJtIY+a zE-c9E%_wk;(0Q$^^W!Ys{Yw7C!t89`n$1N-J`mrFkx;c}C2*!+j^CAY?ti`ee7sgy zzI6{zXskE*dZ$L&&3>|Ky8#!u7=dh=ns*}5c;da`x;zPlwn8k)1hkoB(h>oHOB4l` zgvShC)xdyadA+b91#h#Z{<^yCj_Pie{QEx2W5OU-wNf10Lw!K$b6)mE?G^Y;^fF3V zcGuwb$o=4z$gVaKwoqp{9HXNW`oz%h8VBq5pXGfxB)0h%%NC5OoIi!RQwNj+!rkSs zo@t^M)b6LrJ;~_yz3iMlVqagZQ&omuU;anvi;mNa22XP?H#Gj2&E@&*Pzg&F6_umq zYT~i6F_g=Ps;2aGJmn(0{h!phxc0_~pt3vV?bFmL$y1`veCjmU(bm$+-4xU$cdWNZ zSGT8Mp8@&vV-B_ZWpWUII{E?gA0w4|NNVvezFq_(u$?7$WLbm>JvgM(x+ zUn~n`;!cH8@LHg&8$ox=`$6IGz1#aMavHl22>3cn#!|9KvEmJ`Hd@+WZ40U#TAP{m0KcF| z4k~A*9;vf@v4RkAG(;|zJ&NV$c~$N+e7pLql;$%g&_J+Y!%s%m=v8w;ABC^!cYC@e zeRLZyf$1Fm4lnU5>U|1%+2HL{JzAug;zh;?b)G!j>2me(!DI${Y)P{S1yQWw&B5eK zjXso|JjsU9Kzb!(;;uc<+f|m^!7uUu_r=fZdDqcOz5C-@(@W&m0?nz@)0+KjvT1=Y zm`Ns+1m05WX%x*C6^E^28>wV|OQx3v{_a&pq^Pn=U~yncCTbpZ_iGJXG$ z^LUg^umr{}o2PcE=jQ@Mc zDx{RmKx!B`4IOyG{1edJ)U z4rulu1e}e^iRXuTD;(iOc2X@yHv=iANNwx952Xp_=&N$yGEK*ITk;XoHAa2^`= zRDNp~JE9%{C%&WJ@+8N9z>ihQiB`#3^BZ&*pdi1C{%}Vx&a;p*=LQOc$v`W81u3=& zx93DkPzHce)VhDw9L91T@N8FC&`OIuf*+LMbKa8g)&a zFbKc3JYJn^$EfF$R?DVaVa#GcxUg0!m|p5M$krR9R#U)CD} zRZ(Ym1>ROp_3V?&Scq?Vzm#A@Z02G2C43dwFo#fIhiZqyPH5K_N|J=0jar{o6Ko*x zeBG_3u7lp{`V_aPpOzJDhsuc>V5ZQ?VS4<_4zv88GMxI8i8ut%Tq%nv%Lg9K!K^gn&Kt3}^gN!3CLnFp??-Kr zXc*-z*2w{B!EbvmAZhMPr}KtB28%jZAr4Y!ddF99H>fRU3yY!buEES`UhcDEp=7(r z2P@4m4BMZWo9;FmpC%CHM78`y`cC*2bY3Z&zL>iy-bkxel4b9IAczR+;`HS!p86(t z!zE(z46c4lbDFWRD(%1V^}z#O?ZM_O@Bq>Vk+Bm&Ek+GENBko+gtVGZrjxwKX>@As zZKN+bKop4IIwaJvrH)@y!@CNTFIiC zH&u`2CyD!CZE5EX=dB^p6VYyIAb@cAb|#XBN`x^hYYzS{H&Pi_19;EO9x}h_ek4{yt%2%R z1Up_~f`*Tw%R=-XR#N8}E}2_u;@V}6N-=}p*J#cV&}Hr8sUQ&7-cSW|!#?E}$E~b+ zD1D^==;p|(NVo%LjHLOxsTLm$s3F)<`GQ(705oeMZ+*fIOfE?!W@{-5pqUfR zXwK956pp0RP#RL;2IX3>yp12LCTm1BNRk<0BJy)R8HFGHciKkZcFD!CC^G9AT3opqfwWt#T*?mR_`tj zXW^3`6TaPU_oFW9PmVQTU&`?d-Skoo?AZ@MWgV@yp#^|L5T`ez-k?70WO8Ef^hF-# z)s+5j*;~`p+P-NlXe`2IP(yLJ`4gX!>f3icOs1Jh^SUAu{!wNrX^4#oL5p1+MQ?jH zJ75&@%1VJN{BM5>`9EN~XFL6dn*ErwRnTFArqa zn_-t&yrFzPv$EAI(kCtc{<2Tf*FC(=24fAlE$3CRS3A#^a^LuHkVtTla;uu2X!m?y z>cyFFCLCkdh;7LemY@@Pi|l#Tnq*WByV0EPx6I8@lOE?#v?9nX9fm#nJ z3I^1|t0R-?!H(%kqsdKXW_8~FS*x!Mk-_)T026_89fCO=${FKdy9qYg*3PdD#(v(^+~x zT#z0Nof6Z*8SV)7X|4TvhWg|8`}eoQ=}5cBS#H!N5XPPZH z3b>vY3{)c;19j^$BJX}dIq-hBSoz)D(e zg(q@3QkWBFVH2B=8;ryMteWeM*yMf3Y}5Uiv7&R$N#u6b9I89)9AC&L8Uf(*qnY%6 zyO9+ww+N$&#JD8wIUhV`tWvcibX{?7hODoI#J&%FKR9hNUEX9@7B&3@B&6KG&z^`~ zjL@=jLu6B<&rV%5Qoe8gW&FWq$^|r!$!LZ8FZVv4@jFN1KU)xpjzfJqT{W zC+*M5;w3|W!eFFclls-^XWgFtRNa)G(gk{tW6JgS0$X#p!tTjIMyasNWkr%oZv1ZU&Yy4-u%_ut9?w^@Qh-_OnH5 z2FIuG167Qha^_xKn4BT%H44ohNgK+o)mY|RfqG1j!3}kEd-3nCsG#lBWiPoKAR2FF z@)IkWW|p`U<}*HD2g*?qCgI_qpz#097<*8DIk^5TugdoWi0Pp;2p65Fp^~WWdKddR z-%1H&qn+K(n!D!;8~2VYd@gBGd(a4Dzo<2VU|hHCX|vs3^c4%R-fv*e*4h!>AA=u` zg=5R+r6Aw_u1BVEH4$GnCfbP96E6R7bcU?vSv8D(!35}7VoBD|xd-LfqfPOvy|rrT z?PQS?^*?{=-F|a)2M&9mHHI}VK3{>0V{2URU7Q-4`z|eEL78uj^M2J?A$L!NEr-v` zg^Pj18KLVhkVyE2f^6iIUhDuplW#`OtA7)O8iq6Zm!jaUT#Wadli4m+MZ zFYms!cMZe*Da6-EvAcHvTC=lfE&lqrM4zL#_-9#OO{>Tq)kl~6rOQS6ax2i8Hr1e~ z$6=!NK}sggX?15=qAm(R^82aIQV|yV(h8XCtiB8m;y)1T>yHYnQw_Dv*1BK<%!ckX zU$HCO$4pqP;u(Pc!kX?W9Io^-r2+6MO-Xjl6V~grj$?|9kYD6)NpTg=FHBDI{BEJT zNcE+9R^3bpj&q(MT0-YWm4~&j@4+d4xNG=lVdIcoF5Tg7YLWW93NDK7jLir%c=%vC>@a1SCg6_1d$rtMOf~q4!Q3#24XMK7v zuhku%@KrOOP{eoAl7_sS_LV>aS}VEzxiJ2)3W*mJCSQwXsYB<}HB3>sDp`u<@QP0{ zVi!D1T>xYo;7m-mUPqWsdf039eA22im)A&QBJQtBpP9r~!cTVYiChkpAHU@3C}6TK zE%znwi3yj#HKTc^S+|CXx$}`73!_12+7IDgd2~PhthLj3K-DWc4Z*j07|Yo|IN1F= zFE<>5jE_PbB%1^$+pL^QMrc<31L^%uC2lXT;O!^D`Q{fP*0n~fouHUckm1V7yT4#6 z>0!}hhvQRC*Hh6!X!PHOPnEWIuifN-{IGJu|E&Duht~v?gcDi1HkeCsK{vW7LKJNh zWyN7!-z6CkYQ#ie(xbIFC|4gtNUh<8EQZ5a7hH2n()LCJ?Ux&S*1`(Qcly8j`f>=O zF*zN{1N;npq)Hum5{jtgxp`Us?!{*uPj(yD2+TbX`Z;lX zd*(Bjy_95%ew*fk+@2M!mn3a~d|roD%Pkf2kqz$gL_|n|K$VlSUpSHoI8$Dje~A1V znVe*63oc}`QeXkjtrhUjsgU&+Z>VQKX2vT2w7JeRV4#q6fO}usI>1O#h@rsxvPVq= zUSh-@zv`y16$tci#BGxB+*uk+8j{WAK?cQ{avY5iXzbeaiVXKw5>w-b0O`mQj3~Qa zsvai_r_FCiodvZ4sA!t#4A0SJ2oRxcyUGPMa~`HJnZlR8owFzJOzYQ#TA(c;Kw!(? zr)M=1AL%4MQE5bwV9D^=X?uZHfFjqY9Nz$g>bK^P!joD+4)3id9%_#&UDS7ZkG}zF z93KUz6@SMI_u*D6?DXJp9qz=hcW~*F_R;}tcy~teh z^r0{-9$Q;

@hw1!AaC1#k<$fcDE4m1Yaqmu*jwqNh|8^(TN7?2m6rdaTP4dmx!a z!esDi2C`W$S;|7pOK&E7h7<(Wpm6~IQ}^S8uQA^5cc=?#hM*{ zc;1}}dUA6N6#q7oSve{0X+E?D{s;k;cy`&>Vd2WFbI;Ib)KU2eOhK)EgWu6z2ton= z(rB_*D4l48?I|Q!WtW>)o@Y*(8eJ{J97ZkLHF z$Vz@v9b$X0sDfSdd|xe6^JchsKrW?1hXs^i@X-*0qipu6{RKdm-S2$6_E1e<@+(s9 z^~=R;E`%G@x>A-Lg9=FL{nyJpJgBJs{<0Y_0LR9(Sc?B!|bjI&w9*V zR&_zSzEa;_Eah&w&}maQ@Mk66QOFvDg-9#ZYayMToyD3VL8aBz!(}SvEDRvUyOEl; zF!99ytUKkVXbxjjer7Hdtlwi`&`UQ)P|?QR6nxnzuz^sVJ7$7OCg|E zKHs0}WO$@Tp=j{}S$l&DU4WTOPl^^weK|B$BtDfmAErhC!L1;G%do737Sv!kr)-In zL@{ym4l3c;Y=cJ+{ON6RWbPo-Dma!8SYZeNnmM0NlYD4CtSk?+c(XF4gMl-IcT;u;V;gtxax*Hcl zBs2bYh2sE!XZhHVH9KlQ`QPe+{Qu-Bg$MYsAafghzRbS4P9Vdj$Ur5~8A3_^n7@}h zBbp%8@HgNThW?ezx0C<(4Xj30>K#2tMAXRtq0k;|G+2Fa&ar)4U>hgeBuKScv!rQ{ zo+EY-PJlv>>I@oI3(T&#i#5-l{&)LD@izoe0rWE(kD9m$l{g6ntdb_;q#zO^3xCWD zKg?_4h$qtERg&R;v1XYm~RMrE||a#gE4`hYrzN?GNNli1XobRy61_K*jENCc*u!6 zNPuqj=&+&$=y6?0S6;C6XuB-r02!G44Z8^U9XXK=6sBlsarj^IFq40B{V>{(-gd=a z*A(F0b)FEHv%Ubm)6W58SHBL^2Q0N?;7mSDk1jeaD}k1x zk3fW%(%p`(k^}eq)ll}F5JFGq){?%OFYH zrp^YL9w#*%FoSvQkkcTR{cz*@&aa5oVQJR0uYuAW$Lx7wvYzS@o9<%9j#UnrOR6hKs z^*pX6rhdMpib0*@c9NlUK8f1r>ZLL0YqVMvX+;)QPvlrgaCx*)zL?;wY zftm}$0j^V$FcUzn82meDni$6Qku&5@;CP+_9zGw&oxFO+;3VmHbO&U>r~%+U5B-@n zXm`smyPSS)hYw_7FraS{pZgBzmmA-%!%Uv@v{*ZeB;I$e?OZVId=0X>M8fj;(xX*k*ttWuj zw-BhF^~$g_0<-x@OIZQveJpv*l^gLsg>T=tp5Xr=aS~Hm#>`sFBPb(lsZRGaaJbJW zOloD@Z>g5r+9PMe&l)T@7Gs`^6dDqPfO$gzXK+vzJ4VBe5dby;JoPvbt^K#1Cy1b( zrYzuV(4UcP!g3h~6o35{b9X!WAOId7`o5LYI9}8qpYQa^_t-3`@+l#eukSr_83D0hlE58YFp_(` zzD9`_r19A^L4u|_|9V(~KObxIEAU>T&Yt-#@}kX7X%=YZQO!ex|;BO2it8nq-9Q+?PT^QgSAvQal&fZiR(Co>(PPj;I>zga3S|-f+bj zXN+4i-3GT94Y6@rGFEhxf@8!3RLS5z@TfPM?c_j!N+w#6X4PHJ?y1twYxYfs<_D5+ zRQiBIo7qSPg-XDv!vw}kc!R+-hY5dqBkk4)(6`8X%g+`W%{=8kCGt-{UW<=)>MI*z z*1A?8L;J(iW6s*rPfkiMmza}?fcwzfw&2YleZluEKHH}zsP>#phkCAco&F90-m?mn zV;z2NAQuOcjPKBi$oYdso*S;Ij1VB1Ob0H_)t9zqxlpsoop>h=k>r~FnQdsNN=~-} z%wrK&Ze*~s>teetU_h2h_t#Uq3#RuWJ>jn496FopI+#h;m78S}J}DXB{leS^BPGA8 zKW^j<72q%ar%(!wR5KH(hI{)dtVRFzid*Rbx1#4~>6cH}U>|o^tI**MKA);Wg3`I_ z9ox|_q*Hn4P_^zlpmmaePTYAFXyx+tSjexecHMpj36P{b%E1#Sk~mCP^7ZY0S?n}f zeB*@+Zri>+$gAQk_4H;_=k==N(<&rxLTZ_=!b)7U2CO`=Y3HpW3)a@wA3)H3;P#SC zv$45ciSVySQxaO1h#->gnw7YxGPHrSj`{`IqE}r>)}ufXhqrx8ptwgQbgDI$Rx=&k z*9@+EKPzsVlNAO6jleWlE5U%0*f~4Tste4=aeNWiSGa%U?z&SIJ}DQCFg{c=Nctwq zVuISzw|j9f!MbiP;oUf*cvm%gCJl7{&e^K-y~K6c^buBRvl3>HU%B+);706Rb0d4d z75g#J11$Zj)t`q8LKf)1oWN^=9ZimEsS}vr->5l{Lo3bhLg+cuH@3{Exg|cl@YbtW z+Ie<_4d&Z%*WH^_auTt(!OW#woh@$pb@#_TStuBd9$`^K02k7|9ngr@KjR}Chq|q# z=^pT^H9HW1+gX)%=o56NOPzxUDS<5JuE_*=3Nihau@AsCRankk%zl_-7q@gtga&UG z!Y46VOz@z%OO}H%f4tx7cUi|0ql##V>?b;nr7f5+!J=l?oM8~6;8spoI(b_s#H8GY zOGXI*a=Ps%To%TdiV&eECzauKLBq6-rC3=t?twe z$DzBsikPW)!sgu&X-+5R-wc=B-GGuLy440ON#_l^(l7q!j#j&Gid&y)=el48?k;@f z!V%eQzy2P{cAV~p{^tmf_(8g0yaQ7u?+E1m@&U>k6M(`*5ubHqE1r|Bv9AX{Bqkje zmfzheyu(n$1f={U+9iW-fa{h{0AOd0dDa9Vz8B&7N~hzqg0D@z>+eIor(JxtUGY-vD!*YFWU7n4gvDX$0FtD}Wy zpu^Fc-3`X?G4<|Y?$nLdgfYV@!pSyrD`?chfY74F6mE`hYOrJc>)qxgU5(Z1-++o) zt;L`ss0W$j4dl9h5&! zNI9dYjh3_me~!om8Q@lSD@BeVm_GWNzPsb%#AYSbVEP(G(qqNwNAC)ECb~xgH|)!^ zdBOm-F1{6_fC&$1{VuSn`!clw874o613ySi~R-Xd&K6BT*1TkJp!wY(7Fb)t#Q0X!%{iAT1Y?^*X4# zzFNB!nWdsPzaQ|m0`z?Ee|hP=E@IUm)`@Gkht}+ty;1XWuO8ah#JyGITdtbrjxAQ8 zT_0Q9mYle>)9xC-UR6h5l5VX=s2WXQ%lAIX0YNt*SCLC`d#f8^Q{Qp%=XX)S2|hYZ zEH*sF0is5mbW!IGjQgthAx`WYCNu_+N$=2Q!-+=Z)qA|=HF6?p|5b6QK-^i90y0?N z{T#sD`_LP`thaIE3IYj-L<=2{)Yr7@h*?5`3hzX+`Ej6_K<PQ z1(=q4vj-nA2x{|BZzQ0<;@}0_f)&kJ-_Cb-9k&bL>!)(YUElXVs1tmbE8SnYEZGZ{ z6YJCl)L_&qr0;K-umS(wTjMqF*~$w;2YI)@-nScK>i7ad5pUQio4|zJ)v`PFTp~q^ z`n&ZLGu!?b+UeoMSbiiy)?N)3cz44t|IE6t^9Y){RB3d8{Uh+jei^TBB(YAoW@o6EgrZRIafzDSa5+d7z8N(t`ly-$}eA{#$#-o zhzB1qeiTiOioCKNRcJassAetlf-e3z-d6hR(PMI=NPnkU51bBmJAw#UVtgxJr5E{+ zz!gYtJyQRtrvs3Q>D8=0yF>;8WUtOOJ^&!gccKw(;-_beBfy(tvZ~A3 zb^nJY%i?BMO@&S;_reGHx(X{ui*_-Sg%U6`{R3mbGyQYA5OT^j14SULX@TF-Z65@3Ls0-UH|Kdx7{+V+}ngc%rdGR%jUEC z*LsN;{^AYac5oetKoHupTFT%kby?tRk9Nrg?4V5|lfAP5x?|OqUU2iMydmvvg{=q& z=reyZQ9YMW{n{=mHjQ#rw!c4_ZFIp!U`lTp&SZUg#8(Np86MJ!She_KFBQ;t^-{=s|uv$IW5|p~_2WaIw z^!Nxc&?DgChDD$Y$X45Bj*y6b@$-~Lx$ejpI#h1mCHd2>qbNnafTBlKNBoVl_n*rZ z%m>s8f6VKCqe*|)k;k9TUU6n(7h&#ZTdir&_UJ%Os+F8!wy~H1wZGez5`cw^U#WMH zRc{Skut-a+s36&haW)W)(cZgMMrbnNJ>N@TaK={2^ ze2tQX1lnZwS8L{@#CtvCToYoJm#z`7EJiryb)NGxKZ$sQcP9IK8%FIE7qEqnC~(Ov zD+&ORo>!cJZuo!!jo~1!<9;Nl_X>Ub1_QX!KnL=ix#j}{L0QVyxTPTE0{qP2m;IKHfu%3o`vMz zQ_BiQPO6oHBO1_hkDO@qoMp0vHfumx9q=jj+7Dc;Yc27WYa+AB@Ev-BK=-*CX5|mC z-M{_{=7S+T-+ZwOPj6lSHf2=x&k-V+WI98*JpXa3&MD2l4=dj?hqHrqe@bvGg{fTA z@hf-20|M*!2hD2XzS0CHtAmLL-qWU09F>n^G7df1T-T{t07e30@h%p1XH*qp#;*3H z+1eYzi%R*TyQV@ss_tT)2Q1X*Z(B@C05tfIkoz#gyqy=#+fG|+HA)NY96}#fi$xd{ zxqFER3Sj@Fbm7QH$lG@z%R%XP&ci!tDPCq7hSRaM+{JzqRi@So#G-6Ne(FyE0a}W{ zMz45J6D-GO+5T+?0~ll)thC`0HxSF431afE(Gq`{Qc9ykTk-?;6UYFNTDN(+a|OFA zn6BaJeQNNJcbJ)TFOzSCJ_v*`|L^|-oZyyvZiphjLu#bh51mQNgK=g$eae17$%&gT z;{9t`(Lnz{mte0^@SqBU=MK(4qrzo`p-gwp6fGIXXM~=#IVOVyzolH<*(tmrtuN?^ z><*`iI#Yf%i^2f)6QF*<6_U*nWL?vD_}y=G+hcUoV>BHMR)7-_1iYLy>ku@%p@0V! zp;0g<^!-No8v?1>+dzQ_bRrC32m}fh07vCg*fTFvuFwW|asnm=q?siX3DjS}I)IKg zDUY-QOgq5)gMO<96cof_)}rkl4+NP07}7%ofTHM+2Ts_^XOE{VZh|Daac`OxV?s$? zm&ik&3Wrz!gjmicrdYZ6<2F5^iSM{=SS}H)#CCeR^a1W3Q)h|$r(+iGNHj!NoQ)60 z5Rroc^;0|;SdK$pg;{aHc3a%9rUthsi(!K;?*_VYf*A@$7bC&f;64SWp(8Ab&-q~Z z-omZcKwj0(XDpCjUm-4>i?Qy?*bt+FQPlO`F!^WkPT1)_5B*$33Ozd`kpv!DcsQ-B8U$XTTmLQ0jPao^UAMhL}_c3L!$f_Ex1H zaBZ4mj7i-gh6-aS zYDYV!i{!aKWzg6Ok>;z$24FVlVp?-V{(8}a?rB|>f zF+P(gTz`Q@P07fuijnPSHUs+;Pb6a*cxG6!AKtgl4Z;eTX_F=mkK}F3YLRC4LJJvbrtR;_75gFs#84$y)h zDd0jXXsj$xedZc-YoHU1CKM1sjnH_vm-*cD-WD>p;2lG=_7nA- zqmUZxsSbXdV_@tvrI z#O@!y%*K0YeLJ@1MiWpx#E$Kbse%-(O0(rXf2SR-YFkIO8#$6xO#GO!qNt#!fbVG158*D$wJ-65mo}0 z#V_E0FwBJ$pb9eUozI>*9txpBdvzT{wPdOSWQlgYZ61)#fx$wZr)8$L&+bQNon%(d zzED#P@l9u^KNXi3J7n+E0loXpcuqM;NE=5p!8`Kzp7!Lw-lfAqBEyQr1%}X|7AK(h zOxyS6eXTupi@l5qVS6}M<}9g0N>hqSK^HEdOsd8}fkN4NIvqyaxi{fGkP?4M!cSSn z0tWI|T%lr5Ua7!b$Uuxz$#;U!-*=k{J&Cfp=@L|xtyjOf9ZanpHcxwPNw_#TZV; z(u6b!Hno2y&sk&zl1`cEm8?BnxSZ$dr=>z$6w`_Pjs5Vc&!1y9Xitx;?dmPNH{{Fp zuj;bzU)o{*_{mU_w+A;JCEe!+y4%|9fW)k!id6-3T?Jfd8I3HAaT;a8)^X778TV)& zw}j%BU3_@GjnjO?YPvrD76%M|kugjB5l?pnbV{ikAKZHm4t9J~bviv3mvmyJ;AZDM z<2amURv`UORtb?hZ<#^co#V?!%{M<57rE=SNF?c$#Ce}Np1yaYetW=elp*Z$3kZI` zXR^Edmh=`@aI3XAGBs-B&(p_*M3E?&$?f{xg;qR8hKk$d9G9>{xETGO^^}uFi7m9~ zAa&+9SW~;Qix+l&$1>du0>-=gJgZej3)qOAJ2N(BUA35>LPtmE#$JIF;y);Qd0t$y zOov#se+jW;l?xa9L!jo8B1lJge|BIqE1E%Rs|&TW zjiDX+4~~jTyaa_&vpq$)2xR)frms(_Hy48y1lHJS4hZ}FJ7#grpMK(2>TJJP^Uk?` z;!OIJ8~yExPY;3mIPDr|Hg7vtuc=HH_@)2X^8aZ9jayM+)0cEH+Imm-QKd(P-_IQh zs4h*oamzYt;fx)syL;8Wyv=P(O;~TPzj)^i07G}Q~85Yc%H?8is)8@b%zvoqbJf&MSwQ6tQ%$brAdUKTi z>npM>x|nf1*4#z^+Qvlg-;LV)f5^5x`y<=3EXt+sVf1lv=gHeMj;2nTmS?rAP0Qxf zyL*Bn(+=c4D?k3)ewpa>K(9MZs(W_sn0Y5XJ)QmY=g*sNS1i1FGxAB1B`}2@wzA4e ztgrP+e95+@=+wqpQJSqukJSEmTv%vwmFW}reTNt4dK-TIVO;sO-2C0U{#QGzMVj`g z12=tTWt}Q5=Uug`>*PsKmC5gB>{CxKy7zKLbkN>7ttehCl0r2eRm+qksHAZx{v zWidOYC*3(~WGa$${i1b^*x&p*jvq|zKUQ9o+{&{m`?A2X%fS+xUJGvx)|-C#$PpI3 z*j+6TA12;>yC6g>v8qaH)vG_PU!L&Y72NjC^tH8yPF%Z@MO)*>eunz$xcf%DA=lqI ztY32blg+Czu`NkLRhq3IPImkA+2^tc>n@r!t7+xbn3(x1YNdMF)YR1t&CJ?9ek}a* z{k!!&=dDq|viI<YgXX|?%G6YUN$ZYYCX|TU=`%-YrO2@lD z*`q93gLR9oT5cWNo@WmzkrbO@ODLVZ()-CyA?6XGF0si)*~8;b3AZw4! z2SoQPE%>4=Am!%pvfbXKBOyb=_PF1{kkc7it?71)|9{^h2y)5MO*%_1X9AH%SCfZI z)5VK{Er$~|x|m!8FI>KS`BO3P;f8guFO#)TypFVJo^z{^YrU_K3}doZ^%NImIbO z8M13h8gh!$O~@%uC)^;XIGI6a+&2kAww3jgqV<<}^i!59LCdGCz%#HIJYD@<);T3K F0RXm-F3SJ_ diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png index c8f00f7aeefb47fcbaaefefcd89272c93debfd65..f6b017b3b591cab4f962847cbb1fc41b80df011d 100644 GIT binary patch literal 24730 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 D1f75` diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png index d9aa91213c04c77fffffcb7b00745a9611e8f429..246ee21d15b4e44643c1f01fa05e00c6ed9fe1f9 100644 GIT binary patch literal 3815 zcmbVPXHXMrvyO5oVnHb)Afh5DNReg;Es9`7suTf%0MY{j5_&(NbO=q9W+(~*5~K)$ zgiroycTb^pNCwT#(LC78`V<}^M7H-xAIQ2p1J0Dwy=S{jdy{d3kP11ybq z8J%1B1PP{lZ1>pKuSOS0sGF;}Y9i69*^BQ)hKJwuN;q8KD~+*8^AO}!*ZQwPc{W%v9sYEF;!L^sdVY>i$y?EECffr? z#!x4(%Q(IW#?3?}l(po}Y_4l`Ogw2~#A-kwX{o8LQzL@c`@3frWP}wI$kX=TN`mF% z(U<>%;?OuIwBH!pwtlX?X}7N|PIvyBSQ@gzvcXnrps0`S+=dj4`v$8D6 zA=#|53%GN4sM>c_R1z}&{ny^X$xfD^kW2+-@|6IwEKPq$IuY%*9D`wlm(|suEDfRr z2_VoymX6zzmk8^SpMjN?PfxI&zQ-JEg8lE!Kkp##xJL4siY8RN;JU#--4&+SCZ9TJ zW=;;IDO`mxK*|`is}ipq#IW`*n;Rv(SIr*nYfIhQ3hjyAF}di71Aeadm)|=QnO`Eg znm6r+kJhswK5c40Egm*^RHI`@dk@N4C3LaD*AFIW2Q&*M2-SD-6JE#&fqtA3lF9s1 z2;cR(+My$?uTl|nEmZEQf8FPd1^L3!;8~G)hre<=k}N>P^n!AfclCGOeuEET>m&{d zU6sbLG>=KO_HBB@Wa+j?D7s^ATxD=}V18F%{dyq9%G00Q+HE4K0-+z-V}&(nk9k~~ z1F{OwhHygl4T^I4QKBbM*)37gv^8+{168RW?UbW z+0W3swzm1DHxL9j$Ak3fF?!!ClO7AW@;X)y9gtiTAe53aY3!uOOO|tcbm616)ZD^q ztCMSON^)|ZlC{^;?Kalk8SfS`Y9jyE-)Prs%D&&1gUtyFPeu0@oIhX5)$5G+kZ>f{ zES2uyk5}jv8a2{Xf%4sRBG=E>%1(;_AB5ck+{iuvoR*jw??t4Ch?=~o!6soZrLE64 zBb}PshX(Lwk{YKe8S=K*K78QO@J^f!uQc$v1<1+CF{`~DyA^g&w%nV$AT*Z2)FGF} z{^F%?VhI<-tA643tX09Yfo{Ap8{9`>_-^9dDNv<<-lwL9Y8c&uxw;0tCi*9l`OdkG zW>omv6OGxz>vy2Dkq+5|D*}Y{CZ6c@Rs!L@^g}nJpKe6d8~b1kYd8UZb+EzbepzN# z7C$tM1OmJc?AW2o4U}fNc6Dxe<HYZp>PgAVQ-<4zNel=|5+mzgh2=SSIHee zfI^{JUOU!-87jlJ#G3PS!#vq+&VSU67{`9l`A1Kc`i{?$G@y@w0t4n?8xAVr57Ow(7Oe)u%-TYk`W~ADQ7f1sb{RG!bP^2RwXEahJ56)gFDZ&Q!P5d!A~r3moG2S ze128}(AuC;Xj*?i6&V&WG*kv?ze_a*o9azkKF+r?ar(}u>WFRYs4_X-OA*RGLpj>h znDgN;-w@?&!uPyRJZ->^)qMIDMF}SLPMfZforLrZ=r0@3`CF_WBB*ToyMsnV)RHq}E40{;6*y2OqwQA~o-&A#*qiZrZuF-QKQ&7y5+@IuJ>!67yS)ITwzm z<=2vSmUqtW&#itx&e`~LKrajunVDaEGpuAbT&(Zm9e6kZ8Mk7WgtT2?0rt%cOf1Wy zP^c^~_w{wa;%*ayqce$fQn9fa=j8{r zMBQ|Dv%oQQLynQ@vs&@rU|S

q;H0tS)MF{$1l5 zpm(~B!l~t9ksD*%%pxKprLrk6D*gTC$wvfrHO8XwD15S;Uhvx2W7=k4ajzTX-CSh3 za{%0p6@ssIQ;;=l$lhH;p3h2-M$mF1|6!fRB~YO%e8{uAd-P34G5Dn)`Ry=qz^oqj zp|p4K%0Aavl>%?vz!r@fTPhpa_}K-acCLB6LbWfYaIf)NVO0AIJ5;Uf1;}r;Pwqx2 zSNjWqq9=T{Bn+Me=MZY2X#Ps68&Va&8m?j|YFa_8J@2ghig?4bnZ&pxrs<%`$C1Ea z03!rJ5@tWE9se+c1(52SJjn^Wef8Pd%F=xm82kD0nsN!+{z@tNVBAQ0@OGXE{&~gr zSh~!}2(h+_zA9G@vhbfM`d;_}dK?R<{M?9W-`8$Go$m>Px@>igP;g8_+^+#}cp2E* z_Hb`4Yp0x8BaDRuVKA6kcKR1kMaS|7B*^}Hw3SG9h^I8u;Zyk1P$H0ePx2L(U1-|z zD3~OBt}@rG&b@K8H`%tZK5U{5AQ3!|)X9{;QBD5~!~oFfhV7QrQ8XIudE|U)GQuJ` zvxITc_F;DB_9m0W$%5o)rt)lr#Id(lWRJqWYfE#!U0&#YIal(vjzs?F zngN=T^R77A^KPj=x(lMOprlTEdY#abHR>u)5z3Lz z4R3zAKt5`2-JcrG@%TM2Cu(Fex_JmGAK%-7N}*VYteS($wh!!tKE)6$`=WfTe@OcX z6eneWE5&Y|S@c%QqSxJ#E#i0*J*}^<4t|I_NfopJ+V=L(P>}989H?{P_vq{`zrYl(-=fg!?YE&Og4nVuDfAnqzEeo`nit#UGz?ewa? zhauCBp^z#2g+J}_8<$9~IPc)~oD*^y$8-xgPeh=yhUXom`gJw1>#v z>Q5q1&!Dt*>*-%+W_`V->I-+^?sAD(n4FfD*3t3XXsd|Av}r6R@_Gm*H|&vsp`4CC zI_O)!CB5Wb%T`K`s?oEefVd92s(sNA;nfr^1ZnVq7D=DF}4uH6OT2IF^JKhI^p)ruuJ=i;Zs zWege<?dT&5)pLv>luvKaz3Hg=tZss>?U6-|lppz6ecx5&Pn3H#W0031wnp;)SDej_yXA z^pRnriAw_`U0mP3*M!cMm6pb(rrtL;9?9kSRwA=Q5fkPEJ6`*WN0|?pzBKfrv-6OA z;N}uPu{5eq)TM+%G}`Q!aFiXG@yybjEq*$?7#2`&zrS>;VG_)@3iG^+b(Lu3;#`_i z%^LjS`HFU!lKJ6%m$SY8vTqe`y61gCw)GS8>fCd)k2k1ELOT14*IHYbadTvYJ=^VV zomE}k*%^j$KT_3aI9T|ulltv~n0Wm=;z}8VgAa&xuG&dm8mO*kfkY|XbW^+>GZ2g| z#{+NQs}ZPtdmOt)$o>)I8KLBR2cNF(4wYI8@`G<;=4xiU?DhMUsRFb#^)yiG HHWB{=cU-5K literal 3800 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 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png index 5f990dc02ada5bab00171e84055c814849ce3b68..cc8d07f6073583475bca231c6bfce817ae42985d 100644 GIT binary patch literal 6043 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 literal 3792 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 a1r4v%&c(^|ko#0g3eeF6KdsVu6Z#*)A%05$ From bf3d4fa5c45230ade7070338e72b85b8b768379b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Jun 2026 13:25:57 +0200 Subject: [PATCH 21/35] feat(ui): replace showShadow with elevation for avatar components --- .../lib/components/avatar/stream_avatar.dart | 11 +- .../avatar/stream_avatar_group.dart | 11 +- .../avatar/stream_avatar_stack.dart | 11 +- .../src/components/avatar/stream_avatar.dart | 81 ++++--- .../avatar/stream_avatar_group.dart | 16 +- .../avatar/stream_avatar_stack.dart | 22 +- .../message/stream_message_text.dart | 216 ++++++++++++++++-- .../theme/components/stream_avatar_theme.dart | 18 +- .../stream_avatar_theme.g.theme.dart | 18 +- .../avatar/stream_avatar_golden_test.dart | 16 +- 10 files changed, 297 insertions(+), 123 deletions(-) diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart index e32ec6a4..ead09bcd 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart @@ -35,9 +35,12 @@ Widget buildStreamAvatarPlayground(BuildContext context) { description: 'Whether to show a border around the avatar.', ); - final showShadow = context.knobs.boolean( - label: 'Show Shadow', - description: 'Whether to show a drop shadow around the avatar.', + final elevation = context.knobs.double.slider( + label: 'Elevation', + initialValue: 0, + min: 0, + max: 12, + description: 'Material elevation applied to the avatar (0 = no shadow).', ); final initials = context.knobs.string( @@ -51,7 +54,7 @@ Widget buildStreamAvatarPlayground(BuildContext context) { imageUrl: (imageUrl?.isNotEmpty ?? false) ? imageUrl : null, size: size, showBorder: showBorder, - showShadow: showShadow, + elevation: elevation, placeholder: (context) => Text( initials.substring(0, initials.length.clamp(0, 2)).toUpperCase(), ), diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart index 50db67ee..ebfc2c70 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart @@ -43,9 +43,12 @@ Widget buildStreamAvatarGroupPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); - final showShadow = context.knobs.boolean( - label: 'Show Shadow', - description: 'Whether to show a drop shadow around each individual avatar.', + final elevation = context.knobs.double.slider( + label: 'Elevation', + initialValue: 0, + min: 0, + max: 12, + description: 'Material elevation applied to each individual avatar.', ); final palette = context.streamColorScheme.avatarPalette; @@ -53,7 +56,7 @@ Widget buildStreamAvatarGroupPlayground(BuildContext context) { return Center( child: StreamAvatarGroup( size: size, - showShadow: showShadow, + elevation: elevation, children: List.generate( avatarCount, (index) => StreamAvatar( diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart index c8714431..177b667c 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart @@ -58,9 +58,12 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); - final showShadow = context.knobs.boolean( - label: 'Show Shadow', - description: 'Whether to show a drop shadow around each individual avatar.', + final elevation = context.knobs.double.slider( + label: 'Elevation', + initialValue: 0, + min: 0, + max: 12, + description: 'Material elevation applied to each individual avatar.', ); final colorScheme = context.streamColorScheme; @@ -71,7 +74,7 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { size: size, overlap: overlap, max: maxAvatars, - showShadow: showShadow, + elevation: elevation, children: [ for (var i = 0; i < avatarCount; i++) StreamAvatar( diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index e6961973..312f41d3 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -85,7 +85,7 @@ class StreamAvatar extends StatelessWidget { Color? backgroundColor, Color? foregroundColor, bool showBorder = true, - bool? showShadow, + double? elevation, }) : props = .new( size: size, imageUrl: imageUrl, @@ -93,7 +93,7 @@ class StreamAvatar extends StatelessWidget { backgroundColor: backgroundColor, foregroundColor: foregroundColor, showBorder: showBorder, - showShadow: showShadow, + elevation: elevation, ); /// The properties that configure this avatar. @@ -125,7 +125,7 @@ class StreamAvatarProps { this.backgroundColor, this.foregroundColor, this.showBorder = true, - this.showShadow, + this.elevation, }); /// The URL of the avatar image. @@ -168,12 +168,12 @@ class StreamAvatarProps { /// [StreamAvatarThemeData.border]. final bool showBorder; - /// Whether to show a drop shadow around the avatar. + /// The Material elevation applied to this avatar. /// - /// When null, falls back to [StreamAvatarThemeData.showShadow], then false. - /// The shadow style is determined by [StreamAvatarThemeData.boxShadow], - /// falling back to [StreamBoxShadow.elevation3]. - final bool? showShadow; + /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when + /// neither is set. Translates to a Material shadow using the ambient + /// [ThemeData.shadowColor]. + final double? elevation; } /// The default implementation of [StreamAvatar]. @@ -201,45 +201,44 @@ class DefaultStreamAvatar extends StatelessWidget { final effectiveSize = props.size ?? avatarTheme.size ?? defaults.size; final effectiveBackgroundColor = props.backgroundColor ?? avatarTheme.backgroundColor ?? defaults.backgroundColor; final effectiveForegroundColor = props.foregroundColor ?? avatarTheme.foregroundColor ?? defaults.foregroundColor; + final effectiveElevation = props.elevation ?? avatarTheme.elevation ?? defaults.elevation; final effectiveBorder = avatarTheme.border ?? defaults.border; - final effectiveBoxShadow = (props.showShadow ?? avatarTheme.showShadow ?? false) - ? (avatarTheme.boxShadow ?? defaults.boxShadow) - : null; - final border = props.showBorder ? effectiveBorder : null; + // Avatars are circular, so the border is always uniform — use any side. + final borderSide = props.showBorder ? effectiveBorder.top : BorderSide.none; final textStyle = _textStyleForSize(effectiveSize, textTheme).copyWith(color: effectiveForegroundColor); final iconTheme = IconTheme.of(context).copyWith( color: effectiveForegroundColor, size: _iconSizeForSize(effectiveSize), ); - return AnimatedContainer( - alignment: .center, + return Material( + shape: CircleBorder(side: borderSide), + color: effectiveBackgroundColor, + elevation: effectiveElevation, clipBehavior: .antiAlias, - width: effectiveSize.value, - height: effectiveSize.value, - duration: kThemeChangeDuration, - foregroundDecoration: BoxDecoration(shape: .circle, border: border), - decoration: BoxDecoration(shape: .circle, color: effectiveBackgroundColor, boxShadow: effectiveBoxShadow), - child: Center( - // Need to disable text scaling here so that the text doesn't - // escape the avatar when the textScaleFactor is large. - child: MediaQuery.withNoTextScaling( - child: IconTheme( - data: iconTheme, - child: DefaultTextStyle( - style: textStyle, - child: switch (props.imageUrl) { - final imageUrl? => StreamNetworkImage( - imageUrl, - fit: .cover, - width: effectiveSize.value, - height: effectiveSize.value, - placeholderBuilder: (context) => Center(child: props.placeholder.call(context)), - errorBuilder: (context, _, _) => Center(child: props.placeholder.call(context)), - ), - _ => props.placeholder.call(context), - }, + child: SizedBox.square( + dimension: effectiveSize.value, + child: Center( + // Need to disable text scaling here so that the text doesn't + // escape the avatar when the textScaleFactor is large. + child: MediaQuery.withNoTextScaling( + child: IconTheme( + data: iconTheme, + child: DefaultTextStyle( + style: textStyle, + child: switch (props.imageUrl) { + final imageUrl? => StreamNetworkImage( + imageUrl, + fit: .cover, + width: effectiveSize.value, + height: effectiveSize.value, + placeholderBuilder: (context) => Center(child: props.placeholder.call(context)), + errorBuilder: (context, _, _) => Center(child: props.placeholder.call(context)), + ), + _ => props.placeholder.call(context), + }, + ), ), ), ), @@ -288,13 +287,13 @@ class _StreamAvatarThemeDefaults extends StreamAvatarThemeData { final StreamColorScheme _colorScheme; @override - StreamAvatarSize get size => StreamAvatarSize.lg; + double get elevation => 0; @override - BoxBorder get border => Border.all(color: StreamColors.black10); + StreamAvatarSize get size => StreamAvatarSize.lg; @override - List get boxShadow => context.streamBoxShadow.elevation3; + BoxBorder get border => Border.all(color: StreamColors.black10); @override Color get backgroundColor => _colorScheme.avatarPalette.first.backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart index f599b2cc..9230eebf 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart @@ -91,8 +91,8 @@ class StreamAvatarGroup extends StatelessWidget { super.key, StreamAvatarGroupSize? size, required Iterable children, - bool showShadow = false, - }) : props = .new(size: size, children: children, showShadow: showShadow); + double? elevation, + }) : props = .new(size: size, children: children, elevation: elevation); /// The properties that configure this avatar group. final StreamAvatarGroupProps props; @@ -119,7 +119,7 @@ class StreamAvatarGroupProps { const StreamAvatarGroupProps({ this.size, required this.children, - this.showShadow = false, + this.elevation, }); /// The list of avatars to display in the group. @@ -132,11 +132,11 @@ class StreamAvatarGroupProps { /// If null, defaults to [StreamAvatarGroupSize.lg]. final StreamAvatarGroupSize? size; - /// Whether to show a drop shadow around each individual avatar. + /// The Material elevation applied to each individual avatar. /// - /// Defaults to false. The shadow style is determined by - /// [StreamBoxShadow.elevation3]. - final bool showShadow; + /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when + /// neither is set. + final double? elevation; } /// The default implementation of [StreamAvatarGroup]. @@ -182,7 +182,7 @@ class DefaultStreamAvatarGroup extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - showShadow: props.showShadow, + elevation: props.elevation, ), child: StreamBadgeCountTheme( data: StreamBadgeCountThemeData(size: badgeCountSize), diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart index 5597b157..026ef038 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart @@ -102,9 +102,15 @@ class StreamAvatarStack extends StatelessWidget { required Iterable children, double overlap = 0.33, int max = 5, - bool showShadow = false, + double? elevation, }) : assert(max >= 2, 'max must be at least 2'), - props = .new(size: size, children: children, overlap: overlap, max: max, showShadow: showShadow); + props = .new( + size: size, + children: children, + overlap: overlap, + max: max, + elevation: elevation, + ); /// The properties that configure this avatar stack. final StreamAvatarStackProps props; @@ -133,7 +139,7 @@ class StreamAvatarStackProps { required this.children, this.overlap = 0.33, this.max = 5, - this.showShadow = false, + this.elevation, }); /// The list of widgets to display in the stack. @@ -161,11 +167,11 @@ class StreamAvatarStackProps { /// Must be at least 2. Defaults to 5. final int max; - /// Whether to show a drop shadow around each individual avatar. + /// The Material elevation applied to each individual avatar. /// - /// Defaults to false. The shadow style is determined by - /// [StreamBoxShadow.elevation3]. - final bool showShadow; + /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when + /// neither is set. + final double? elevation; } /// The default implementation of [StreamAvatarStack]. @@ -210,7 +216,7 @@ class DefaultStreamAvatarStack extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - showShadow: props.showShadow, + elevation: props.elevation, ), child: StreamRow( spacing: -diameter * props.overlap, diff --git a/packages/stream_core_flutter/lib/src/components/message/stream_message_text.dart b/packages/stream_core_flutter/lib/src/components/message/stream_message_text.dart index 3a6a0626..7597ea8a 100644 --- a/packages/stream_core_flutter/lib/src/components/message/stream_message_text.dart +++ b/packages/stream_core_flutter/lib/src/components/message/stream_message_text.dart @@ -10,17 +10,62 @@ import '../message_layout/stream_message_layout.dart'; /// The default protocol prefix used to identify mention links. /// /// Links with this scheme (e.g., `[text](mention:id)`) are treated as -/// mentions rather than regular links. +/// mentions rather than regular links. A mention type qualifier can follow +/// the scheme to distinguish kinds, e.g. `[text](mention-role:id)`. Bare +/// `mention:` is treated as a user mention. const kStreamMentionScheme = 'mention'; -/// Callback fired when a mention link is tapped. +/// The mention kind carried by a mention link. +/// +/// Encoded as the optional suffix on the mention URL scheme: `mention-user:`, +/// `mention-channel:`, `mention-here:`, `mention-role:`, `mention-group:`. A +/// bare `mention:` scheme resolves to [user]. +/// +/// Defined as a Dart extension type over [String] so the same value flows +/// through the markdown URL, the [md.Element] attribute, and callbacks +/// without wrapper allocations. The set is closed — only the five constants +/// declared on this type are recognised by the markdown mention parser. +extension type const MentionType(String value) { + /// A mention referencing a single user. + static const user = MentionType('user'); + + /// A channel-wide broadcast mention, e.g. `@channel`. + static const channel = MentionType('channel'); + + /// A broadcast mention targeting online channel members, e.g. `@here`. + static const here = MentionType('here'); + + /// A mention referencing a role, e.g. `@admin`. + static const role = MentionType('role'); + + /// A mention referencing a named subset of channel members. + static const group = MentionType('group'); +} + +/// Callback fired when a user-type mention link is tapped. /// /// [displayText] is the raw display text from the link /// (e.g., `'@Alice'` from `[@Alice](mention:user123)`). /// [id] is the mention identifier (the URL-decoded portion after the /// `mention:` scheme). +/// +/// Only invoked for user-type mentions. To handle the full set of mention +/// kinds (channel / here / role / group) in a single callback, use +/// [MarkdownTapAnyMentionCallback]. typedef MarkdownTapMentionCallback = void Function(String displayText, String id); +/// Callback fired when any mention link is tapped. +/// +/// [displayText] is the raw display text from the link. +/// [type] is the mention kind decoded from the URL scheme. +/// [id] is the URL-decoded payload following the scheme. +typedef MarkdownTapAnyMentionCallback = + void Function( + String displayText, + MentionType type, + String id, + ); + // Matches characters that render as emoji — either those with default emoji // presentation, or text-default characters forced to emoji via VS16 (U+FE0F). // @@ -69,6 +114,7 @@ class StreamMessageText extends StatelessWidget { bool selectable = false, MarkdownTapLinkCallback? onTapLink, MarkdownTapMentionCallback? onTapMention, + MarkdownTapAnyMentionCallback? onTapAnyMention, VoidCallback? onTapText, MarkdownImageBuilder? imageBuilder, SyntaxHighlighter? syntaxHighlighter, @@ -87,6 +133,7 @@ class StreamMessageText extends StatelessWidget { selectable: selectable, onTapLink: onTapLink, onTapMention: onTapMention, + onTapAnyMention: onTapAnyMention, onTapText: onTapText, imageBuilder: imageBuilder, syntaxHighlighter: syntaxHighlighter, @@ -157,6 +204,7 @@ class StreamMessageTextProps { this.selectable = false, this.onTapLink, this.onTapMention, + this.onTapAnyMention, this.onTapText, this.imageBuilder, this.syntaxHighlighter, @@ -190,11 +238,23 @@ class StreamMessageTextProps { /// Called when a link is tapped. final MarkdownTapLinkCallback? onTapLink; - /// Called when a mention is tapped. + /// Called when a user-type mention is tapped. /// - /// Mentions use the `[text](mention:id)` format. + /// Mentions use the `[text](mention:id)` format. Only invoked for user + /// mentions; to handle every mention kind in a single callback, prefer + /// [onTapAnyMention] instead. + /// + /// When both callbacks are provided, [onTapAnyMention] takes precedence + /// and this callback is not invoked. final MarkdownTapMentionCallback? onTapMention; + /// Called when a mention of any kind is tapped. + /// + /// Receives the [MentionType] decoded from the URL scheme along with the + /// display text and the URL-decoded id payload. Takes precedence over + /// [onTapMention] when both are set. + final MarkdownTapAnyMentionCallback? onTapAnyMention; + /// Called when non-link text is tapped. final VoidCallback? onTapText; @@ -256,8 +316,8 @@ class DefaultStreamMessageText extends StatelessWidget { var effectiveTextStyle = resolve((s) => s?.textStyle).copyWith(color: effectiveTextColor); final effectiveLinkColor = resolve((s) => s?.linkColor); final effectiveLinkStyle = resolve((s) => s?.linkStyle).copyWith(color: effectiveLinkColor); - final effectiveMentionColor = resolve((s) => s?.mentionColor); - final effectiveMentionStyle = resolve((s) => s?.mentionStyle).copyWith(color: effectiveMentionColor); + + final mentionStyles = _resolveMentionStyles(resolve); final contentType = layout.contentKind; final emojiCount = StreamMessageText.emojiCount(props.text); @@ -289,20 +349,27 @@ class DefaultStreamMessageText extends StatelessWidget { streamThemeData, // Apply stream theme data ).copyWith(p: effectiveTextStyle, a: effectiveLinkStyle).merge(props.styleSheet); - // Prepend mention syntax so `[text](mention:id)` is intercepted + // Prepend mention syntax so `[text](mention[-type]:id)` is intercepted // before the standard LinkSyntax, producing `mention` elements. // Regular `a` elements are never touched. - final mentionStyle = effectiveMentionStyle.copyWith(color: effectiveMentionColor); - final effectiveInlineSyntaxes = [ _StreamMentionSyntax(), ...?props.inlineSyntaxes, ]; + // Base mention style — used as the defensive fallback when the parser + // ever emits a type outside the closed set in [mentionStyles]. + final baseMentionStyle = resolve((s) => s?.mentionStyle).copyWith( + color: resolve((s) => s?.mentionColor), + backgroundColor: resolve((s) => s?.mentionBackgroundColor), + ); + final effectiveBuilders = { kStreamMentionScheme: _StreamMentionBuilder( - style: mentionStyle, + stylesByType: mentionStyles, + fallbackStyle: baseMentionStyle, onTap: props.onTapMention, + onTapAny: props.onTapAnyMention, ), ...?props.builders, }; @@ -328,39 +395,130 @@ class DefaultStreamMessageText extends StatelessWidget { ), ); } + + // Pre-resolves one text style per mention kind via the variant→base + // fallback chain. The returned map always contains an entry for each of + // the five built-in [MentionType] values. + Map _resolveMentionStyles( + StreamMessageLayoutResolver resolve, + ) { + TextStyle styleFor(MentionType type) { + // Per the chat design system, `@channel` and `@here` share the + // `mention-broadcast` styling. + final variantStyle = switch (type) { + MentionType.channel || MentionType.here => resolve( + (s) => s?.mentionBroadcastStyle ?? s?.mentionStyle, + ), + MentionType.role => resolve( + (s) => s?.mentionRoleStyle ?? s?.mentionStyle, + ), + MentionType.group => resolve( + (s) => s?.mentionGroupStyle ?? s?.mentionStyle, + ), + MentionType.user => resolve( + (s) => s?.mentionUserStyle ?? s?.mentionStyle, + ), + _ => resolve((s) => s?.mentionStyle), + }; + final variantColor = switch (type) { + MentionType.channel || MentionType.here => resolve( + (s) => s?.mentionBroadcastColor ?? s?.mentionColor, + ), + MentionType.role => resolve( + (s) => s?.mentionRoleColor ?? s?.mentionColor, + ), + MentionType.group => resolve( + (s) => s?.mentionGroupColor ?? s?.mentionColor, + ), + MentionType.user => resolve( + (s) => s?.mentionUserColor ?? s?.mentionColor, + ), + _ => resolve((s) => s?.mentionColor), + }; + final variantBg = switch (type) { + MentionType.channel || MentionType.here => resolve( + (s) => s?.mentionBroadcastBackgroundColor ?? s?.mentionBackgroundColor, + ), + MentionType.role => resolve( + (s) => s?.mentionRoleBackgroundColor ?? s?.mentionBackgroundColor, + ), + MentionType.group => resolve( + (s) => s?.mentionGroupBackgroundColor ?? s?.mentionBackgroundColor, + ), + MentionType.user => resolve( + (s) => s?.mentionUserBackgroundColor ?? s?.mentionBackgroundColor, + ), + _ => resolve((s) => s?.mentionBackgroundColor), + }; + return variantStyle.copyWith( + color: variantColor, + backgroundColor: variantBg, + ); + } + + return { + MentionType.channel: styleFor(MentionType.channel), + MentionType.here: styleFor(MentionType.here), + MentionType.role: styleFor(MentionType.role), + MentionType.group: styleFor(MentionType.group), + MentionType.user: styleFor(MentionType.user), + }; + } } -// Intercepts `[text](mention:id)` patterns before the standard link parser, -// emitting a `mention` element instead of a regular link. +// Intercepts `[text](mention[-type]:id)` patterns before the standard link +// parser, emitting a `mention` element instead of a regular link. // -// Given `[@Alice](mention:user123)`: +// Given `[@Alice](mention:user123)` or `[@admin](mention-role:admin)`: // -// * Emits a `mention` element with text content `@Alice`. -// * Stores the URL-decoded id (`user123`) in the `id` attribute. +// * Emits a `mention` element with text content `@Alice` / `@admin`. +// * Stores the URL-decoded id (`user123` / `admin`) in the `id` attribute. +// * Stores the captured type (`user` / `channel` / `here` / `role` / `group`) +// in the `type` attribute. Bare `mention:` (no suffix) resolves to `user`. // * Regular links are never touched. class _StreamMentionSyntax extends md.InlineSyntax { _StreamMentionSyntax({ String scheme = kStreamMentionScheme, - }) : super('\\[([^\\]\\n]+)\\]\\(${RegExp.escape(scheme)}:([^)\\s]+)\\)'); + }) : super( + '\\[([^\\]\\n]+)\\]\\(${RegExp.escape(scheme)}(?:-(user|channel|here|role|group))?:([^)\\s]+)\\)', + ); @override bool onMatch(md.InlineParser parser, Match match) { final displayText = match.group(1)!; - final rawId = match.group(2)!; + final type = match.group(2) ?? MentionType.user.value; + final rawId = match.group(3)!; final el = md.Element.text('mention', displayText); el.attributes['id'] = Uri.decodeComponent(rawId); + el.attributes['type'] = type; parser.addNode(el); return true; } } // Renders `mention` elements as tappable styled text with pointer cursor. +// +// Per-element style resolution: reads the `type` attribute set by +// [_StreamMentionSyntax] and looks it up in [stylesByType]. [fallbackStyle] +// is a defensive guard — the parser only emits the five built-in +// [MentionType] values, all of which are present in the map. +// +// Tap dispatch: [onTapAny] takes precedence and receives the [MentionType]. +// When [onTapAny] is null, the legacy [onTap] fires only for user mentions so +// existing customer code never sees a non-user payload. class _StreamMentionBuilder extends MarkdownElementBuilder { - _StreamMentionBuilder({required this.style, this.onTap}); + _StreamMentionBuilder({ + required this.stylesByType, + required this.fallbackStyle, + this.onTap, + this.onTapAny, + }); - final TextStyle style; + final Map stylesByType; + final TextStyle fallbackStyle; final MarkdownTapMentionCallback? onTap; + final MarkdownTapAnyMentionCallback? onTapAny; @override Widget? visitElementAfterWithContext( @@ -371,11 +529,24 @@ class _StreamMentionBuilder extends MarkdownElementBuilder { ) { final displayText = element.textContent; final id = element.attributes['id'] ?? ''; + final type = MentionType( + element.attributes['type'] ?? MentionType.user.value, + ); + final style = stylesByType[type] ?? fallbackStyle; + + final VoidCallback? handleTap; + if (onTapAny case final onTapAny?) { + handleTap = () => onTapAny(displayText, type, id); + } else if (onTap case final onTap? when type == MentionType.user) { + handleTap = () => onTap(displayText, id); + } else { + handleTap = null; + } return MouseRegion( - cursor: onTap != null ? SystemMouseCursors.click : MouseCursor.defer, + cursor: handleTap != null ? SystemMouseCursors.click : MouseCursor.defer, child: GestureDetector( - onTap: onTap != null ? () => onTap!(displayText, id) : null, + onTap: handleTap, child: Text(displayText, style: preferredStyle?.merge(style) ?? style), ), ); @@ -422,6 +593,9 @@ class _StreamMessageTextDefaults extends StreamMessageTextStyle { @override StreamMessageLayoutProperty get mentionColor => .all(_colorScheme.textLink); + @override + StreamMessageLayoutProperty get mentionBackgroundColor => .all(Colors.transparent); + @override StreamMessageLayoutProperty get singleEmojiStyle { return .all(.new(fontSize: StreamEmojiSize.xxl.value, height: 1)); diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart index 2157514c..a5a039c1 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart @@ -132,8 +132,7 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { this.backgroundColor, this.foregroundColor, this.border, - this.boxShadow, - this.showShadow, + this.elevation, }); /// The default size for avatars. @@ -158,18 +157,11 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { /// of both border color and width. final BoxBorder? border; - /// The box shadow for this avatar. + /// The Material elevation applied to this avatar. /// - /// Applied when [StreamAvatar.showShadow] is true. Defaults to - /// [StreamBoxShadow.elevation3]. - final List? boxShadow; - - /// Whether to show a drop shadow around the avatar. - /// - /// When set via [StreamAvatarTheme], this overrides the per-widget - /// [StreamAvatar.showShadow] default, allowing parent widgets such as - /// [StreamAvatarGroup] to enable shadows for all child avatars at once. - final bool? showShadow; + /// Used as the fallback when no elevation is set on [StreamAvatar]. A value + /// of `0` renders no shadow. + final double? elevation; /// Linearly interpolate between two [StreamAvatarThemeData] objects. static StreamAvatarThemeData? lerp( diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart index 5cdbb6cf..0dbd1200 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart @@ -34,8 +34,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), foregroundColor: Color.lerp(a.foregroundColor, b.foregroundColor, t), border: BoxBorder.lerp(a.border, b.border, t), - boxShadow: t < 0.5 ? a.boxShadow : b.boxShadow, - showShadow: t < 0.5 ? a.showShadow : b.showShadow, + elevation: lerpDouble$(a.elevation, b.elevation, t), ); } @@ -44,8 +43,7 @@ mixin _$StreamAvatarThemeData { Color? backgroundColor, Color? foregroundColor, BoxBorder? border, - List? boxShadow, - bool? showShadow, + double? elevation, }) { final _this = (this as StreamAvatarThemeData); @@ -54,8 +52,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: backgroundColor ?? _this.backgroundColor, foregroundColor: foregroundColor ?? _this.foregroundColor, border: border ?? _this.border, - boxShadow: boxShadow ?? _this.boxShadow, - showShadow: showShadow ?? _this.showShadow, + elevation: elevation ?? _this.elevation, ); } @@ -75,8 +72,7 @@ mixin _$StreamAvatarThemeData { backgroundColor: other.backgroundColor, foregroundColor: other.foregroundColor, border: other.border, - boxShadow: other.boxShadow, - showShadow: other.showShadow, + elevation: other.elevation, ); } @@ -97,8 +93,7 @@ mixin _$StreamAvatarThemeData { _other.backgroundColor == _this.backgroundColor && _other.foregroundColor == _this.foregroundColor && _other.border == _this.border && - _other.boxShadow == _this.boxShadow && - _other.showShadow == _this.showShadow; + _other.elevation == _this.elevation; } @override @@ -111,8 +106,7 @@ mixin _$StreamAvatarThemeData { _this.backgroundColor, _this.foregroundColor, _this.border, - _this.boxShadow, - _this.showShadow, + _this.elevation, ); } } diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart index 84163aea..50b5722c 100644 --- a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart @@ -21,7 +21,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - showShadow: false, + elevation: 0, placeholder: (context) => const Text('AB'), ), ), @@ -32,7 +32,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - showShadow: true, + elevation: 3, placeholder: (context) => const Text('AB'), ), ), @@ -58,7 +58,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - showShadow: false, + elevation: 0, placeholder: (context) => const Text('AB'), ), brightness: Brightness.dark, @@ -70,7 +70,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - showShadow: true, + elevation: 3, placeholder: (context) => const Text('AB'), ), brightness: Brightness.dark, @@ -97,7 +97,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarGroup( size: size, - showShadow: true, + elevation: 3, children: List.generate( count, (i) => StreamAvatar( @@ -127,7 +127,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarGroup( size: size, - showShadow: true, + elevation: 3, children: List.generate( count, (i) => StreamAvatar( @@ -157,7 +157,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarStack( size: size, - showShadow: true, + elevation: 3, children: List.generate( 4, (i) => StreamAvatar( @@ -186,7 +186,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarStack( size: size, - showShadow: true, + elevation: 3, children: List.generate( 4, (i) => StreamAvatar( From 76562ac4e9b5a3041a613a08e02874d8b30d873e Mon Sep 17 00:00:00 2001 From: xsahil03x <25670178+xsahil03x@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:29:56 +0000 Subject: [PATCH 22/35] chore: Update Goldens --- .../ci/stream_avatar_group_shadow_dark.png | Bin 19382 -> 18364 bytes .../ci/stream_avatar_group_shadow_light.png | Bin 24730 -> 28997 bytes .../goldens/ci/stream_avatar_shadow_light.png | Bin 15545 -> 19554 bytes .../ci/stream_avatar_stack_shadow_dark.png | Bin 3815 -> 4066 bytes .../ci/stream_avatar_stack_shadow_light.png | Bin 6043 -> 5595 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png index b23f698e1d0a98665689bcd2dc01f443d50ed65d..0e687ab1a538100dc7c829083c8fce9ae816ce40 100644 GIT binary patch literal 18364 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 J#V0-g{|6Lo*@OT9 literal 19382 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 z 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 z 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 literal 24730 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 S2Zk*KqOPp1RIgz3_`d<@LAVD1 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png index 246ee21d15b4e44643c1f01fa05e00c6ed9fe1f9..6230be4deab3ae4b39d2ff0e979171e357d1e85a 100644 GIT binary patch literal 4066 zcmbVPcQhOByAQRBR_$4%e61KQEo$#kZR}BMRBCT3NL5PFsMXdcR@E*_?M<45koa1) zql%a{Vpnke{=0wObMJl6dEVzd&w0-?Kj*yX6K@JKxIxcD4*&pe7#ZrCUuo2pSkuv5 z-7u{A?JGqUtZigTcXcA@Ucj$xiePgCZ9om4Zyf+&N;J~dvJ6A~nGd(M2<@WTRlHu@ zFWFxTcV_A95>D8`hYjm36YjsCt*P#e6fBpnG0qeydNr zL@*}ykro|8dh{(0NopY}OL}eF|MLUAl#5iPtnu&=x9BJgHdCcFUMT%P#7Y44$R9dk zF4LdfZASlyH)rE;RsCZnge<;P2GQ~UzbpByC|OKTMRya%?_%Jt)ZXF(HKgkSaC38u z1EsaC^tkI~@+q@=omM`yo%G?x1Xv8jPEP*zB9Yg!xwHF+hxI0KL31rZ6w*&Z-pc8h z66vz|uhG`A)oeS$;c(5@4!3KZ+T-d+UD7g%!k5q))~Yo%X?k<_P^E{hE_Rv#A2Abs zJ3F5D^dwVGnt!&1t818vz2jqcjVLHaB_Yf;ldEgB3b0!Cf`!&oeGB zOcFH(Es1(i=+M{j!K|1Uhr_60SQX*?19SXAT6mG^4_#E(j~`-gLD-%5Dk!QrwX%JT z*&#!yGVksrgCjTyXg5J90>^W5eKhfBo$ca!94 zL+9V!t4A(hubNGm#BvLRSzQTUpVhvf^?2e>5ua2NOVX3%{N0}8BL1Sx@Zl5Pp^AR) zjEqSkj`YlLp0rKPsUG*yZ=FH~7|}_*ko;{-N}UIYD-s$Y0C0XV!jEBv#iTSh&(t-) zZeVr?!OA+$(JBHiNOaOIIx3`_S0%9S_e3~$mOqkN=~RbaN?J;3K`cu1O}4!IZ?jtd z8n-V&_!}5!1ao2%Ze-3J^V|>D2j*DpS!B(ULnV)qL;WU~VpoxYmyWc69z_q)n`B{% z8W}u-bgVp67v@K0m%~E=@KZ0Ef{9Z^MNuF~OahQaRQSj8R;%lP53Q%*;VxEqa`Nvq zcLqkrnACQS`dSC{wfWcM^IubM|B-OvjOaL&Pujmd*UgK25}MY$VE3K6sVQ~bZD!VP z?^vw>=uaDmcKI{Y$dh@PX`=9UeZl?S{rkNcm*>D3uSZ|-GmV?KxQ^!F^~IFx{RfrD&Y7GNj`XZIC30I@dNn#r@LpW4iuC?6U|`=2CR1(8 z7LL47oS=5vKBo~yqY?74r-}hG>mq<2uTN@CJ2Pc_H;k-wUP~wQ5oiH-&|dvrcem_nhw?rVhuZY_ePb#pYm8J?STnm&s+_E`anG}~&R)pMzD_z0Vohf9315|sh!0g?A8*F4PX}|5@ZNV=t}`>s zryvnIR|z;nWkLJ%eq2+nFJJC09cZTy3Vbep?My4Fs`}};UWCthQ18WZKZGu104K&~ z9v@>P3S5dN1tK=q;rda(TrHB*N)|jkVp71X9n} zL5)o5^0e+RIDD1YiUdZJhWCrlpVCwt{QCR(dqa~M zXwo_}7@L)>h^$33`oxdQmIT{pq+{!qI6fpaFmS$9_-Pmt0@=ggm7L5PSRor%=fFf@ zU#uKQV3q*~cln5BCY$EtmJ7@G3t&A5QIB1jXJ%EDRwBrh>0>4T#CFI(uyRGnJzEQ^ zk~e=MDW=g{|BYuVsAdc9A69^?8-{#{w!(9h~!vb&*oXp zm4w6uUkW{m{mf~vKGp9@Ze^fJb}!36oaC5Y+XI#P!Q2;_FO2XV5iQof$eY9&Qu-v9on_C)9o7LS*YYr;{)(~js_`G4%Xy5tME+em5=UI2Ou7&3kJ*AK3-0A z0yZNKAFT8b4z8vjA2LOs#&j`AsMzIx_=M;K`nzkevv@8{yR~+(im`%7*x+pXfSC*@n(V>M7$s*qhNs&&refyRrcMa6YaUC-ara_y%0Ozs zoD>eZzQgJ)N1*ZB)+zA#-jokFN)-jlf;K(8_04}Xk1I9_DJ#=xFQ)R!7Ma4Y0Hp*C z6If;v&>oph=-7HGQud{9WcpgFukX8O8Q-gDw+X)b7fD@%>f84%mzMwYBXHai(LHw+ zefl(W?~J`xaOFVbCFF;$O=fZ?=gJ+gBT8HQK%gSP_NmE_y%VLv%kZGX9Q-Ezq{NX$ zV8DVOK+`Im!l$gQcRp!$z!GpP;Wl$~s2CePHIJ8n-_#ICWMm{_KgZ`}=g?3kRGU-B zm%p*#xIPowgPP~u&R5TR7|a2Mwg)a^_QfUp^^D9E{H)kiKi=c_rwH9~R%(a3*g4;& zyheGo^+W{1TO5ej3H0OO*WiyZG!tjjB5pH@+4zTrpMj6Irpqg9^wA~v(>ORki_5Y~ zCmotd4UVF3`Z@LnKtc=*ZK+C?m40nae;4l`)Os2ygQc(4D*E@&qK?BwM`pVd*YA|q z!<(af3(|QBY2V8LfSW9eKg2|kkWpRyX{dE|&&UPP)z=556ee{Y4?_AcPOHx~(6op8 zPy-%+%Yw@?1zgI+DVKrr&>NFZ(a&nmFLW0&gA6LzmW|pjaP8mLVo$s-wYYe=f^xb` zTAAz2BC)A~{E^S$DlhpmGUl3;j(0+Son}*%*KDZ#`n9%^(xS7_m%NmTSSG!*W#fGx zP43#Uoi(1@J&XbeK!}j(VN-Jp*pCgxjL+wOV{nXf(L%?WJ4E78Whf;tiX7p$>MvF8 zbBhyZ7jE4uc*a7+-PEJORIxmMi~+;Q5?tKJc~-UJUCFV*eStC$vn?E*V0=fIg6Q;+ zg`X9r^>oHW1EC8zvG{||bZfBK#qR8Bn-o>y;BDW}*)`qC^nhyI4a3Ju(aC2i%sl)x zN5D3Kv#al0%sgX_+hJZ_H>~!Ch6umj*gP#9o)~RfuI}%qPVtwfwB_XmBUhZ(>f4*- z021BCPJ?ie{(ap$hdbZn^wHnyv!j>4P>HkA_qQv5%sIG?1$r}cu`%lC;OslGm69EY z1+`1LwHkUR$Ka&>{rk|ftLYY>r}iexbOjt=k8W@0d;yX(6fvKgexeV7-1M`y{(M)1 ziG3xu-|z_^$+MZWy-!7u(QljZVc^AwMmS41o`XxsPX03$jDFjFNBoycTb^pNCwT#(LC78`V<}^M7H-xAIQ2p1J0Dwy=S{jdy{d3kP11ybq z8J%1B1PP{lZ1>pKuSOS0sGF;}Y9i69*^BQ)hKJwuN;q8KD~+*8^AO}!*ZQwPc{W%v9sYEF;!L^sdVY>i$y?EECffr? z#!x4(%Q(IW#?3?}l(po}Y_4l`Ogw2~#A-kwX{o8LQzL@c`@3frWP}wI$kX=TN`mF% z(U<>%;?OuIwBH!pwtlX?X}7N|PIvyBSQ@gzvcXnrps0`S+=dj4`v$8D6 zA=#|53%GN4sM>c_R1z}&{ny^X$xfD^kW2+-@|6IwEKPq$IuY%*9D`wlm(|suEDfRr z2_VoymX6zzmk8^SpMjN?PfxI&zQ-JEg8lE!Kkp##xJL4siY8RN;JU#--4&+SCZ9TJ zW=;;IDO`mxK*|`is}ipq#IW`*n;Rv(SIr*nYfIhQ3hjyAF}di71Aeadm)|=QnO`Eg znm6r+kJhswK5c40Egm*^RHI`@dk@N4C3LaD*AFIW2Q&*M2-SD-6JE#&fqtA3lF9s1 z2;cR(+My$?uTl|nEmZEQf8FPd1^L3!;8~G)hre<=k}N>P^n!AfclCGOeuEET>m&{d zU6sbLG>=KO_HBB@Wa+j?D7s^ATxD=}V18F%{dyq9%G00Q+HE4K0-+z-V}&(nk9k~~ z1F{OwhHygl4T^I4QKBbM*)37gv^8+{168RW?UbW z+0W3swzm1DHxL9j$Ak3fF?!!ClO7AW@;X)y9gtiTAe53aY3!uOOO|tcbm616)ZD^q ztCMSON^)|ZlC{^;?Kalk8SfS`Y9jyE-)Prs%D&&1gUtyFPeu0@oIhX5)$5G+kZ>f{ zES2uyk5}jv8a2{Xf%4sRBG=E>%1(;_AB5ck+{iuvoR*jw??t4Ch?=~o!6soZrLE64 zBb}PshX(Lwk{YKe8S=K*K78QO@J^f!uQc$v1<1+CF{`~DyA^g&w%nV$AT*Z2)FGF} z{^F%?VhI<-tA643tX09Yfo{Ap8{9`>_-^9dDNv<<-lwL9Y8c&uxw;0tCi*9l`OdkG zW>omv6OGxz>vy2Dkq+5|D*}Y{CZ6c@Rs!L@^g}nJpKe6d8~b1kYd8UZb+EzbepzN# z7C$tM1OmJc?AW2o4U}fNc6Dxe<HYZp>PgAVQ-<4zNel=|5+mzgh2=SSIHee zfI^{JUOU!-87jlJ#G3PS!#vq+&VSU67{`9l`A1Kc`i{?$G@y@w0t4n?8xAVr57Ow(7Oe)u%-TYk`W~ADQ7f1sb{RG!bP^2RwXEahJ56)gFDZ&Q!P5d!A~r3moG2S ze128}(AuC;Xj*?i6&V&WG*kv?ze_a*o9azkKF+r?ar(}u>WFRYs4_X-OA*RGLpj>h znDgN;-w@?&!uPyRJZ->^)qMIDMF}SLPMfZforLrZ=r0@3`CF_WBB*ToyMsnV)RHq}E40{;6*y2OqwQA~o-&A#*qiZrZuF-QKQ&7y5+@IuJ>!67yS)ITwzm z<=2vSmUqtW&#itx&e`~LKrajunVDaEGpuAbT&(Zm9e6kZ8Mk7WgtT2?0rt%cOf1Wy zP^c^~_w{wa;%*ayqce$fQn9fa=j8{r zMBQ|Dv%oQQLynQ@vs&@rU|S

q;H0tS)MF{$1l5 zpm(~B!l~t9ksD*%%pxKprLrk6D*gTC$wvfrHO8XwD15S;Uhvx2W7=k4ajzTX-CSh3 za{%0p6@ssIQ;;=l$lhH;p3h2-M$mF1|6!fRB~YO%e8{uAd-P34G5Dn)`Ry=qz^oqj zp|p4K%0Aavl>%?vz!r@fTPhpa_}K-acCLB6LbWfYaIf)NVO0AIJ5;Uf1;}r;Pwqx2 zSNjWqq9=T{Bn+Me=MZY2X#Ps68&Va&8m?j|YFa_8J@2ghig?4bnZ&pxrs<%`$C1Ea z03!rJ5@tWE9se+c1(52SJjn^Wef8Pd%F=xm82kD0nsN!+{z@tNVBAQ0@OGXE{&~gr zSh~!}2(h+_zA9G@vhbfM`d;_}dK?R<{M?9W-`8$Go$m>Px@>igP;g8_+^+#}cp2E* z_Hb`4Yp0x8BaDRuVKA6kcKR1kMaS|7B*^}Hw3SG9h^I8u;Zyk1P$H0ePx2L(U1-|z zD3~OBt}@rG&b@K8H`%tZK5U{5AQ3!|)X9{;QBD5~!~oFfhV7QrQ8XIudE|U)GQuJ` zvxITc_F;DB_9m0W$%5o)rt)lr#Id(lWRJqWYfE#!U0&#YIal(vjzs?F zngN=T^R77A^KPj=x(lMOprlTEdY#abHR>u)5z3Lz z4R3zAKt5`2-JcrG@%TM2Cu(Fex_JmGAK%-7N}*VYteS($wh!!tKE)6$`=WfTe@OcX z6eneWE5&Y|S@c%QqSxJ#E#i0*J*}^<4t|I_NfopJ+V=L(P>}989H?{P_vq{`zrYl(-=fg!?YE&Og4nVuDfAnqzEeo`nit#UGz?ewa? zhauCBp^z#2g+J}_8<$9~IPc)~oD*^y$8-xgPeh=yhUXom`gJw1>#v z>Q5q1&!Dt*>*-%+W_`V->I-+^?sAD(n4FfD*3t3XXsd|Av}r6R@_Gm*H|&vsp`4CC zI_O)!CB5Wb%T`K`s?oEefVd92s(sNA;nfr^1ZnVq7D=DF}4uH6OT2IF^JKhI^p)ruuJ=i;Zs zWege<?dT&5)pLv>luvKaz3Hg=tZss>?U6-|lppz6ecx5&Pn3H#W0031wnp;)SDej_yXA z^pRnriAw_`U0mP3*M!cMm6pb(rrtL;9?9kSRwA=Q5fkPEJ6`*WN0|?pzBKfrv-6OA z;N}uPu{5eq)TM+%G}`Q!aFiXG@yybjEq*$?7#2`&zrS>;VG_)@3iG^+b(Lu3;#`_i z%^LjS`HFU!lKJ6%m$SY8vTqe`y61gCw)GS8>fCd)k2k1ELOT14*IHYbadTvYJ=^VV zomE}k*%^j$KT_3aI9T|ulltv~n0Wm=;z}8VgAa&xuG&dm8mO*kfkY|XbW^+>GZ2g| z#{+NQs}ZPtdmOt)$o>)I8KLBR2cNF(4wYI8@`G<;=4xiU?DhMUsRFb#^)yiG HHWB{=cU-5K diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_light.png index cc8d07f6073583475bca231c6bfce817ae42985d..2a337e6ca35dff41268f2b56e15223a2839f3993 100644 GIT binary patch literal 5595 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 literal 6043 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 From 66fabb7ece8c94ce3aef2735e1d8bb0541351e17 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 14:32:14 +0200 Subject: [PATCH 23/35] improve elevation properties --- .../lib/components/avatar/stream_avatar.dart | 11 ++++------ .../avatar/stream_avatar_group.dart | 11 ++++------ .../avatar/stream_avatar_stack.dart | 11 ++++------ .../src/components/avatar/stream_avatar.dart | 22 ++++++++++--------- .../avatar/stream_avatar_group.dart | 16 +++++++------- .../avatar/stream_avatar_stack.dart | 16 +++++++------- .../theme/components/stream_avatar_theme.dart | 18 ++++++++++----- .../stream_avatar_theme.g.theme.dart | 18 ++++++++++----- .../avatar/stream_avatar_golden_test.dart | 16 +++++++------- 9 files changed, 73 insertions(+), 66 deletions(-) diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart index ead09bcd..fd5d5c03 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar.dart @@ -35,12 +35,9 @@ Widget buildStreamAvatarPlayground(BuildContext context) { description: 'Whether to show a border around the avatar.', ); - final elevation = context.knobs.double.slider( - label: 'Elevation', - initialValue: 0, - min: 0, - max: 12, - description: 'Material elevation applied to the avatar (0 = no shadow).', + final isFloating = context.knobs.boolean( + label: 'Is Floating', + description: 'Whether to show a drop shadow around the avatar.', ); final initials = context.knobs.string( @@ -54,7 +51,7 @@ Widget buildStreamAvatarPlayground(BuildContext context) { imageUrl: (imageUrl?.isNotEmpty ?? false) ? imageUrl : null, size: size, showBorder: showBorder, - elevation: elevation, + isFloating: isFloating, placeholder: (context) => Text( initials.substring(0, initials.length.clamp(0, 2)).toUpperCase(), ), diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart index ebfc2c70..4471ad48 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_group.dart @@ -43,12 +43,9 @@ Widget buildStreamAvatarGroupPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); - final elevation = context.knobs.double.slider( - label: 'Elevation', - initialValue: 0, - min: 0, - max: 12, - description: 'Material elevation applied to each individual avatar.', + final isFloating = context.knobs.boolean( + label: 'Is Floating', + description: 'Whether to show a drop shadow around each individual avatar.', ); final palette = context.streamColorScheme.avatarPalette; @@ -56,7 +53,7 @@ Widget buildStreamAvatarGroupPlayground(BuildContext context) { return Center( child: StreamAvatarGroup( size: size, - elevation: elevation, + isFloating: isFloating, children: List.generate( avatarCount, (index) => StreamAvatar( diff --git a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart index 177b667c..7dc2dd51 100644 --- a/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart +++ b/apps/design_system_gallery/lib/components/avatar/stream_avatar_stack.dart @@ -58,12 +58,9 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { description: 'Use images or show initials placeholder.', ); - final elevation = context.knobs.double.slider( - label: 'Elevation', - initialValue: 0, - min: 0, - max: 12, - description: 'Material elevation applied to each individual avatar.', + final isFloating = context.knobs.boolean( + label: 'Is Floating', + description: 'Whether to show a drop shadow around each individual avatar.', ); final colorScheme = context.streamColorScheme; @@ -74,7 +71,7 @@ Widget buildStreamAvatarStackPlayground(BuildContext context) { size: size, overlap: overlap, max: maxAvatars, - elevation: elevation, + isFloating: isFloating, children: [ for (var i = 0; i < avatarCount; i++) StreamAvatar( diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index 312f41d3..8fa694c6 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -85,7 +85,7 @@ class StreamAvatar extends StatelessWidget { Color? backgroundColor, Color? foregroundColor, bool showBorder = true, - double? elevation, + bool? isFloating, }) : props = .new( size: size, imageUrl: imageUrl, @@ -93,7 +93,7 @@ class StreamAvatar extends StatelessWidget { backgroundColor: backgroundColor, foregroundColor: foregroundColor, showBorder: showBorder, - elevation: elevation, + isFloating: isFloating, ); /// The properties that configure this avatar. @@ -125,7 +125,7 @@ class StreamAvatarProps { this.backgroundColor, this.foregroundColor, this.showBorder = true, - this.elevation, + this.isFloating, }); /// The URL of the avatar image. @@ -168,12 +168,11 @@ class StreamAvatarProps { /// [StreamAvatarThemeData.border]. final bool showBorder; - /// The Material elevation applied to this avatar. + /// Whether this avatar is in a floating state, rendering with a drop shadow. /// - /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when - /// neither is set. Translates to a Material shadow using the ambient - /// [ThemeData.shadowColor]. - final double? elevation; + /// When true, the elevation is taken from [StreamAvatarThemeData.floatingElevation], + /// falling back to `3`. When false or null (resolved to false), no shadow is shown. + final bool? isFloating; } /// The default implementation of [StreamAvatar]. @@ -201,7 +200,10 @@ class DefaultStreamAvatar extends StatelessWidget { final effectiveSize = props.size ?? avatarTheme.size ?? defaults.size; final effectiveBackgroundColor = props.backgroundColor ?? avatarTheme.backgroundColor ?? defaults.backgroundColor; final effectiveForegroundColor = props.foregroundColor ?? avatarTheme.foregroundColor ?? defaults.foregroundColor; - final effectiveElevation = props.elevation ?? avatarTheme.elevation ?? defaults.elevation; + final effectiveIsFloating = props.isFloating ?? avatarTheme.isFloating ?? false; + final effectiveElevation = effectiveIsFloating + ? (avatarTheme.floatingElevation ?? defaults.floatingElevation) + : 0.0; final effectiveBorder = avatarTheme.border ?? defaults.border; // Avatars are circular, so the border is always uniform — use any side. @@ -287,7 +289,7 @@ class _StreamAvatarThemeDefaults extends StreamAvatarThemeData { final StreamColorScheme _colorScheme; @override - double get elevation => 0; + double get floatingElevation => 3; @override StreamAvatarSize get size => StreamAvatarSize.lg; diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart index 9230eebf..298b6706 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_group.dart @@ -91,8 +91,8 @@ class StreamAvatarGroup extends StatelessWidget { super.key, StreamAvatarGroupSize? size, required Iterable children, - double? elevation, - }) : props = .new(size: size, children: children, elevation: elevation); + bool isFloating = false, + }) : props = .new(size: size, children: children, isFloating: isFloating); /// The properties that configure this avatar group. final StreamAvatarGroupProps props; @@ -119,7 +119,7 @@ class StreamAvatarGroupProps { const StreamAvatarGroupProps({ this.size, required this.children, - this.elevation, + this.isFloating = false, }); /// The list of avatars to display in the group. @@ -132,11 +132,11 @@ class StreamAvatarGroupProps { /// If null, defaults to [StreamAvatarGroupSize.lg]. final StreamAvatarGroupSize? size; - /// The Material elevation applied to each individual avatar. + /// Whether each individual avatar is in a floating state, rendering with a drop shadow. /// - /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when - /// neither is set. - final double? elevation; + /// Defaults to false. The elevation used is [StreamAvatarThemeData.floatingElevation], + /// falling back to `3`. + final bool isFloating; } /// The default implementation of [StreamAvatarGroup]. @@ -182,7 +182,7 @@ class DefaultStreamAvatarGroup extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - elevation: props.elevation, + isFloating: props.isFloating, ), child: StreamBadgeCountTheme( data: StreamBadgeCountThemeData(size: badgeCountSize), diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart index 026ef038..cae6ac09 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart @@ -102,14 +102,14 @@ class StreamAvatarStack extends StatelessWidget { required Iterable children, double overlap = 0.33, int max = 5, - double? elevation, + bool isFloating = false, }) : assert(max >= 2, 'max must be at least 2'), props = .new( size: size, children: children, overlap: overlap, max: max, - elevation: elevation, + isFloating: isFloating, ); /// The properties that configure this avatar stack. @@ -139,7 +139,7 @@ class StreamAvatarStackProps { required this.children, this.overlap = 0.33, this.max = 5, - this.elevation, + this.isFloating = false, }); /// The list of widgets to display in the stack. @@ -167,11 +167,11 @@ class StreamAvatarStackProps { /// Must be at least 2. Defaults to 5. final int max; - /// The Material elevation applied to each individual avatar. + /// Whether each individual avatar is in a floating state, rendering with a drop shadow. /// - /// Falls back to [StreamAvatarThemeData.elevation], or `0` (no shadow) when - /// neither is set. - final double? elevation; + /// Defaults to false. The elevation used is [StreamAvatarThemeData.floatingElevation], + /// falling back to `3`. + final bool isFloating; } /// The default implementation of [StreamAvatarStack]. @@ -216,7 +216,7 @@ class DefaultStreamAvatarStack extends StatelessWidget { color: colorScheme.borderOnInverse, strokeAlign: BorderSide.strokeAlignOutside, ), - elevation: props.elevation, + isFloating: props.isFloating, ), child: StreamRow( spacing: -diameter * props.overlap, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart index a5a039c1..ea8e3f9b 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.dart @@ -132,7 +132,8 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { this.backgroundColor, this.foregroundColor, this.border, - this.elevation, + this.isFloating, + this.floatingElevation, }); /// The default size for avatars. @@ -157,11 +158,18 @@ class StreamAvatarThemeData with _$StreamAvatarThemeData { /// of both border color and width. final BoxBorder? border; - /// The Material elevation applied to this avatar. + /// Whether the avatar is in a floating state, rendering with elevation. /// - /// Used as the fallback when no elevation is set on [StreamAvatar]. A value - /// of `0` renders no shadow. - final double? elevation; + /// When set via [StreamAvatarTheme], this overrides the per-widget + /// [StreamAvatar.isFloating] default, allowing parent widgets such as + /// [StreamAvatarGroup] to enable floating for all child avatars at once. + final bool? isFloating; + + /// The Material elevation applied to this avatar when it is floating. + /// + /// Used when [StreamAvatar.isFloating] (or [isFloating]) is true. + /// Falls back to the default elevation of `3`. + final double? floatingElevation; /// Linearly interpolate between two [StreamAvatarThemeData] objects. static StreamAvatarThemeData? lerp( diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart index 0dbd1200..7a5a1fef 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart @@ -34,7 +34,8 @@ mixin _$StreamAvatarThemeData { backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), foregroundColor: Color.lerp(a.foregroundColor, b.foregroundColor, t), border: BoxBorder.lerp(a.border, b.border, t), - elevation: lerpDouble$(a.elevation, b.elevation, t), + isFloating: t < 0.5 ? a.isFloating : b.isFloating, + floatingElevation: lerpDouble$(a.floatingElevation, b.floatingElevation, t), ); } @@ -43,7 +44,8 @@ mixin _$StreamAvatarThemeData { Color? backgroundColor, Color? foregroundColor, BoxBorder? border, - double? elevation, + bool? isFloating, + double? floatingElevation, }) { final _this = (this as StreamAvatarThemeData); @@ -52,7 +54,8 @@ mixin _$StreamAvatarThemeData { backgroundColor: backgroundColor ?? _this.backgroundColor, foregroundColor: foregroundColor ?? _this.foregroundColor, border: border ?? _this.border, - elevation: elevation ?? _this.elevation, + isFloating: isFloating ?? _this.isFloating, + floatingElevation: floatingElevation ?? _this.floatingElevation, ); } @@ -72,7 +75,8 @@ mixin _$StreamAvatarThemeData { backgroundColor: other.backgroundColor, foregroundColor: other.foregroundColor, border: other.border, - elevation: other.elevation, + isFloating: other.isFloating, + floatingElevation: other.floatingElevation, ); } @@ -93,7 +97,8 @@ mixin _$StreamAvatarThemeData { _other.backgroundColor == _this.backgroundColor && _other.foregroundColor == _this.foregroundColor && _other.border == _this.border && - _other.elevation == _this.elevation; + _other.isFloating == _this.isFloating && + _other.floatingElevation == _this.floatingElevation; } @override @@ -106,7 +111,8 @@ mixin _$StreamAvatarThemeData { _this.backgroundColor, _this.foregroundColor, _this.border, - _this.elevation, + _this.isFloating, + _this.floatingElevation, ); } } diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart index 50b5722c..0372b0cc 100644 --- a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart @@ -21,7 +21,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - elevation: 0, + isFloating: false, placeholder: (context) => const Text('AB'), ), ), @@ -32,7 +32,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - elevation: 3, + isFloating: true, placeholder: (context) => const Text('AB'), ), ), @@ -58,7 +58,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - elevation: 0, + isFloating: false, placeholder: (context) => const Text('AB'), ), brightness: Brightness.dark, @@ -70,7 +70,7 @@ void main() { StreamAvatar( size: size, showBorder: false, - elevation: 3, + isFloating: true, placeholder: (context) => const Text('AB'), ), brightness: Brightness.dark, @@ -97,7 +97,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarGroup( size: size, - elevation: 3, + isFloating: true, children: List.generate( count, (i) => StreamAvatar( @@ -127,7 +127,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarGroup( size: size, - elevation: 3, + isFloating: true, children: List.generate( count, (i) => StreamAvatar( @@ -157,7 +157,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarStack( size: size, - elevation: 3, + isFloating: true, children: List.generate( 4, (i) => StreamAvatar( @@ -186,7 +186,7 @@ void main() { child: _buildAvatarInTheme( StreamAvatarStack( size: size, - elevation: 3, + isFloating: true, children: List.generate( 4, (i) => StreamAvatar( From a54e4c81f365d7b477f65b6ccdb3afec9c147cea Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 17 Jun 2026 16:06:31 +0200 Subject: [PATCH 24/35] Update appstyle theming --- .../components/toolbar/stream_app_bar.dart | 5 +- .../components/scaffold/stream_scaffold.dart | 36 +++++--- .../components/toolbar/stream_app_bar.dart | 12 +-- .../toolbar/stream_bottom_nav_bar.dart | 46 ++++++---- .../components/stream_app_bar_theme.dart | 29 +++++++ .../stream_app_bar_theme.g.theme.dart | 8 +- .../stream_avatar_theme.g.theme.dart | 6 +- .../stream_bottom_app_bar_theme.dart | 30 +++++++ .../stream_bottom_app_bar_theme.g.theme.dart | 8 +- .../lib/src/theme/stream_app_style.dart | 87 ++++++++++++------- .../lib/src/theme/stream_theme.dart | 2 +- .../toolbar/stream_app_bar_golden_test.dart | 8 +- .../toolbar/stream_app_bar_test.dart | 14 +-- 13 files changed, 203 insertions(+), 88 deletions(-) diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart index 385b92b3..882e65cb 100644 --- a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart +++ b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart @@ -60,13 +60,12 @@ Widget buildStreamAppBarPlayground(BuildContext context) { 'instead of a solid background and a bottom border.', ); - final appBarBehavior = floating ? AppBarBehavior.floating : AppBarBehavior.regular; final colorScheme = context.streamColorScheme; final Widget bar = StreamAppBar( primary: false, - appBarBehavior: appBarBehavior, style: StreamAppBarStyle( + behavior: floating ? AppBarBehavior.floating : AppBarBehavior.regular, padding: EdgeInsets.all(padding), spacing: spacing, ), @@ -265,7 +264,7 @@ Widget buildStreamAppBarShowcase(BuildContext context) { bar: StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), leading: StreamButton.icon( icon: Icon(context.streamIcons.chevronLeft), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart index 6b4fb745..237afb4d 100644 --- a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; +import '../../theme/components/stream_app_bar_theme.dart'; +import '../../theme/components/stream_bottom_app_bar_theme.dart'; import '../../theme/semantics/stream_color_scheme.dart'; -import '../../theme/stream_app_style.dart'; import '../../theme/stream_theme_extensions.dart'; // --------------------------------------------------------------------------- @@ -82,20 +83,23 @@ class StreamScaffoldInsets extends InheritedWidget { /// /// ## Floating vs. regular /// -/// The behaviour of each slot is controlled by [StreamAppStyle]: +/// The behaviour of each slot is resolved via a three-step priority chain: /// -/// * `AppBarBehavior.floating` — the body extends *behind* the app bar; +/// 1. Per-instance [appBarBehavior] / [bottomBarBehavior] on this widget. +/// 2. [StreamAppBarStyle.behavior] / [StreamBottomAppBarStyle.behavior] +/// from the ambient component theme. +/// 3. The ambient [StreamAppStyle] enum value ([StreamAppStyle.floating] or +/// [StreamAppStyle.regular]). +/// +/// * [AppBarBehavior.floating] — the body extends *behind* the app bar; /// [StreamScaffoldInsets.topPadding] is set to the bar height plus the /// system status-bar inset so the body can add its own inset. -/// * `BottomBarBehavior.floating` — the body extends *behind* the bottom +/// * [BottomBarBehavior.floating] — the body extends *behind* the bottom /// widget; [StreamScaffoldInsets.bottomPadding] equals the measured height of /// that widget. /// * `regular` for either slot — no overlap; the slot occupies its own space /// and the corresponding inset is `0.0`. /// -/// Per-instance [appBarBehavior] / [bottomBarBehavior] override the ambient -/// [StreamAppStyle] for this scaffold only. -/// /// ## Drawer support /// /// [drawer] is forwarded to the underlying [Scaffold] so that widgets in @@ -167,12 +171,16 @@ class StreamScaffold extends StatelessWidget { /// Per-instance override for the app-bar floating behaviour. /// - /// When null the value is read from the ambient [StreamAppStyle]. + /// When null the value is resolved from [StreamAppBarStyle.behavior] + /// in the ambient [StreamAppBarTheme], falling back to the ambient + /// [StreamAppStyle]. final AppBarBehavior? appBarBehavior; /// Per-instance override for the bottom-bar floating behaviour. /// - /// When null the value is read from the ambient [StreamAppStyle]. + /// When null the value is resolved from + /// [StreamBottomAppBarStyle.behavior] in the ambient + /// [StreamBottomAppBarTheme], falling back to the ambient [StreamAppStyle]. final BottomBarBehavior? bottomBarBehavior; /// Background color of the scaffold. @@ -188,8 +196,14 @@ class StreamScaffold extends StatelessWidget { @override Widget build(BuildContext context) { final appStyle = context.streamTheme.appStyle; - final effectiveAppBarBehavior = appBarBehavior ?? appStyle.appBarBehavior; - final effectiveBottomBarBehavior = bottomBarBehavior ?? appStyle.bottomBarBehavior; + final effectiveAppBarBehavior = + appBarBehavior ?? + context.streamAppBarTheme.style?.behavior ?? + (appStyle.isFloating ? AppBarBehavior.floating : AppBarBehavior.regular); + final effectiveBottomBarBehavior = + bottomBarBehavior ?? + context.streamBottomAppBarTheme.style?.behavior ?? + (appStyle.isFloating ? BottomBarBehavior.floating : BottomBarBehavior.regular); final effectiveBackgroundColor = backgroundColor ?? context.streamColorScheme.backgroundApp; final appBarFloating = effectiveAppBarBehavior == AppBarBehavior.floating; diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 3f57f9f7..96a088b8 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -6,7 +6,6 @@ import '../../theme/components/stream_button_theme.dart'; import '../../theme/primitives/stream_spacing.dart'; import '../../theme/semantics/stream_color_scheme.dart'; import '../../theme/semantics/stream_text_theme.dart'; -import '../../theme/stream_app_style.dart'; import '../../theme/stream_floating_fade.dart'; import '../../theme/stream_theme_extensions.dart'; import '../buttons/stream_button.dart'; @@ -74,7 +73,6 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { Widget? trailing, bool primary = true, StreamAppBarStyle? style, - AppBarBehavior? appBarBehavior, }) : props = .new( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, @@ -83,7 +81,6 @@ class StreamAppBar extends StatelessWidget implements PreferredSizeWidget { trailing: trailing, primary: primary, style: style, - appBarBehavior: appBarBehavior, ); /// The properties that configure this app bar. @@ -119,7 +116,6 @@ class StreamAppBarProps { this.trailing, this.primary = true, this.style, - this.appBarBehavior, }); /// A widget to display before the [title]. @@ -177,11 +173,6 @@ class StreamAppBarProps { /// Resolution order per field: this [style] → ambient [StreamAppBarTheme] /// → token-backed defaults. final StreamAppBarStyle? style; - - /// Whether this app bar is floating. - /// - /// When true, the app bar is floating and will be displayed above the content. - final AppBarBehavior? appBarBehavior; } /// The default implementation of [StreamAppBar]. @@ -215,7 +206,8 @@ class DefaultStreamAppBar extends StatelessWidget { final style = context.streamAppBarTheme.style?.merge(props.style) ?? props.style; final defaults = _StreamAppBarStyleDefaults(context); - final effectiveAppBarBehavior = props.appBarBehavior ?? context.streamTheme.appStyle.appBarBehavior; + final effectiveAppBarBehavior = + style?.behavior ?? (context.streamTheme.appStyle.isFloating ? AppBarBehavior.floating : AppBarBehavior.regular); final effectiveBackgroundColor = switch (effectiveAppBarBehavior) { .floating => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index c3c2b752..9fa78b37 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../theme/components/stream_badge_notification_theme.dart'; -import '../../theme/stream_app_style.dart'; +import '../../theme/components/stream_bottom_app_bar_theme.dart'; import '../../theme/stream_floating_fade.dart'; import '../../theme/stream_theme_extensions.dart'; @@ -32,26 +32,30 @@ class StreamBottomNavBarItem { /// A bottom navigation bar for Stream surfaces that automatically adapts /// between a floating pill style and a regular docked style based on the -/// ambient [BottomBarBehavior] from [StreamAppStyle]. +/// ambient [BottomBarBehavior] from [StreamBottomAppBarTheme] or +/// [StreamAppStyle]. /// /// ## Floating style /// -/// When [StreamAppStyle.bottomBarBehavior] is [BottomBarBehavior.floating], -/// the bar renders as a horizontally padded pill with a rounded background, -/// a subtle box shadow, and a hairline border. It sits above the body content -/// and is typically used with [StreamScaffold]'s floating bottom slot. +/// When [BottomBarBehavior.floating] is in effect, the bar renders as a +/// horizontally padded pill with a rounded background, a subtle box shadow, +/// and a hairline border. It sits above the body content and is typically +/// used with [StreamScaffold]'s floating bottom slot. /// /// ## Regular style /// -/// When [BottomBarBehavior.regular], the bar renders as a standard docked -/// bottom navigation bar using Flutter's [BottomNavigationBar] with Stream -/// colour and typography tokens. A hairline `borderSubtle` top border -/// separates it from the body. +/// When [BottomBarBehavior.regular] is in effect, the bar renders as a +/// standard docked bottom navigation bar using Flutter's [BottomNavigationBar] +/// with Stream colour and typography tokens. A hairline `borderSubtle` top +/// border separates it from the body. /// -/// ## Behaviour override +/// ## Behaviour resolution /// -/// Pass an explicit [behavior] to override the ambient style for this -/// instance only. +/// The effective behaviour is resolved in this priority order: +/// 1. The per-instance [behavior] parameter on this widget. +/// 2. [StreamBottomAppBarStyle.behavior] from the ambient +/// [StreamBottomAppBarTheme]. +/// 3. The ambient [StreamAppStyle] enum value. /// /// {@tool snippet} /// @@ -81,7 +85,8 @@ class StreamBottomNavBarItem { /// /// * [StreamBottomNavBarItem], which configures each tab. /// * [StreamScaffold], which accepts this widget in its `bottom` slot. -/// * [StreamAppStyle], which controls the floating/regular behaviour. +/// * [StreamAppStyle], the global app-wide style that acts as fallback. +/// * [StreamBottomAppBarStyle.behavior], the per-theme component override. class StreamBottomNavBar extends StatelessWidget { /// Creates a Stream bottom navigation bar. const StreamBottomNavBar({ @@ -103,15 +108,20 @@ class StreamBottomNavBar extends StatelessWidget { /// Called when the user taps a navigation item. final ValueChanged onTap; - /// Overrides the ambient [BottomBarBehavior] for this instance only. + /// Overrides the resolved [BottomBarBehavior] for this instance only. /// - /// When null, the value is read from [StreamAppStyle] in the current - /// [StreamTheme]. + /// When null the effective behaviour is resolved from + /// [StreamBottomAppBarStyle.behavior] in the ambient + /// [StreamBottomAppBarTheme], falling back to the ambient [StreamAppStyle]. final BottomBarBehavior? behavior; @override Widget build(BuildContext context) { - final effectiveBehavior = behavior ?? context.streamTheme.appStyle.bottomBarBehavior; + final appStyle = context.streamTheme.appStyle; + final effectiveBehavior = + behavior ?? + context.streamBottomAppBarTheme.style?.behavior ?? + (appStyle.isFloating ? BottomBarBehavior.floating : BottomBarBehavior.regular); if (effectiveBehavior == BottomBarBehavior.floating) { return _FloatingNavBar( diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart index a389c307..b4349dea 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart @@ -6,6 +6,24 @@ import 'stream_button_theme.dart'; part 'stream_app_bar_theme.g.theme.dart'; +/// The floating or regular layout behaviour for a [StreamAppBar]. +/// +/// When null on [StreamAppBarStyle], the ambient [StreamAppStyle] is used +/// as a fallback — [StreamAppStyle.floating] maps to [floating] and +/// [StreamAppStyle.regular] maps to [regular]. +/// +/// See also: +/// +/// * [StreamAppBarStyle.behavior], which carries this value. +/// * [StreamAppStyle], the global app-wide style that acts as fallback. +enum AppBarBehavior { + /// The app bar sits within the layout flow with a solid background. + regular, + + /// The app bar floats above the body with a translucent background. + floating, +} + /// Applies an app bar theme to descendant [StreamAppBar] widgets. /// /// Wrap a subtree with [StreamAppBarTheme] to override app bar styling. @@ -136,6 +154,7 @@ class StreamAppBarThemeData with _$StreamAppBarThemeData { class StreamAppBarStyle with _$StreamAppBarStyle { /// Creates an app bar style with optional property overrides. const StreamAppBarStyle({ + this.behavior, this.backgroundColor, this.floatingBackgroundColor, this.padding, @@ -146,6 +165,16 @@ class StreamAppBarStyle with _$StreamAppBarStyle { this.trailingStyle, }); + /// The floating or regular layout behaviour for this app bar. + /// + /// When null the value falls back to the ambient [StreamAppStyle]: + /// [StreamAppStyle.floating] → [AppBarBehavior.floating], + /// [StreamAppStyle.regular] → [AppBarBehavior.regular]. + /// + /// Set this to override the global style for this component only, without + /// affecting other components. + final AppBarBehavior? behavior; + /// The background colour of the app bar. final Color? backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart index 0dc90277..1394200c 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart @@ -99,6 +99,7 @@ mixin _$StreamAppBarStyle { } return StreamAppBarStyle( + behavior: t < 0.5 ? a.behavior : b.behavior, backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), floatingBackgroundColor: Color.lerp( a.floatingBackgroundColor, @@ -127,6 +128,7 @@ mixin _$StreamAppBarStyle { } StreamAppBarStyle copyWith({ + AppBarBehavior? behavior, Color? backgroundColor, Color? floatingBackgroundColor, EdgeInsetsGeometry? padding, @@ -139,6 +141,7 @@ mixin _$StreamAppBarStyle { final _this = (this as StreamAppBarStyle); return StreamAppBarStyle( + behavior: behavior ?? _this.behavior, backgroundColor: backgroundColor ?? _this.backgroundColor, floatingBackgroundColor: floatingBackgroundColor ?? _this.floatingBackgroundColor, @@ -163,6 +166,7 @@ mixin _$StreamAppBarStyle { } return copyWith( + behavior: other.behavior, backgroundColor: other.backgroundColor, floatingBackgroundColor: other.floatingBackgroundColor, padding: other.padding, @@ -194,7 +198,8 @@ mixin _$StreamAppBarStyle { final _this = (this as StreamAppBarStyle); final _other = (other as StreamAppBarStyle); - return _other.backgroundColor == _this.backgroundColor && + return _other.behavior == _this.behavior && + _other.backgroundColor == _this.backgroundColor && _other.floatingBackgroundColor == _this.floatingBackgroundColor && _other.padding == _this.padding && _other.spacing == _this.spacing && @@ -210,6 +215,7 @@ mixin _$StreamAppBarStyle { return Object.hash( runtimeType, + _this.behavior, _this.backgroundColor, _this.floatingBackgroundColor, _this.padding, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart index 7a5a1fef..1c1f7e4a 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_avatar_theme.g.theme.dart @@ -35,7 +35,11 @@ mixin _$StreamAvatarThemeData { foregroundColor: Color.lerp(a.foregroundColor, b.foregroundColor, t), border: BoxBorder.lerp(a.border, b.border, t), isFloating: t < 0.5 ? a.isFloating : b.isFloating, - floatingElevation: lerpDouble$(a.floatingElevation, b.floatingElevation, t), + floatingElevation: lerpDouble$( + a.floatingElevation, + b.floatingElevation, + t, + ), ); } diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart index ce125fe6..7beeaa08 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart @@ -6,6 +6,25 @@ import 'stream_button_theme.dart'; part 'stream_bottom_app_bar_theme.g.theme.dart'; +/// The floating or regular layout behaviour for a [StreamBottomAppBar] or +/// [StreamBottomNavBar]. +/// +/// When null on [StreamBottomAppBarStyle], the ambient [StreamAppStyle] is +/// used as a fallback — [StreamAppStyle.floating] maps to [floating] and +/// [StreamAppStyle.regular] maps to [regular]. +/// +/// See also: +/// +/// * [StreamBottomAppBarStyle.behavior], which carries this value. +/// * [StreamAppStyle], the global app-wide style that acts as fallback. +enum BottomBarBehavior { + /// The bottom bar sits within the layout flow with a solid background. + regular, + + /// The bottom bar floats above the body with a translucent background. + floating, +} + /// Applies a bottom app bar theme to descendant [StreamBottomAppBar] widgets. /// /// Wrap a subtree with [StreamBottomAppBarTheme] to override bottom app bar @@ -139,6 +158,7 @@ class StreamBottomAppBarThemeData with _$StreamBottomAppBarThemeData { class StreamBottomAppBarStyle with _$StreamBottomAppBarStyle { /// Creates a bottom app bar style with optional property overrides. const StreamBottomAppBarStyle({ + this.behavior, this.backgroundColor, this.padding, this.spacing, @@ -148,6 +168,16 @@ class StreamBottomAppBarStyle with _$StreamBottomAppBarStyle { this.trailingStyle, }); + /// The floating or regular layout behaviour for this bottom bar. + /// + /// When null the value falls back to the ambient [StreamAppStyle]: + /// [StreamAppStyle.floating] → [BottomBarBehavior.floating], + /// [StreamAppStyle.regular] → [BottomBarBehavior.regular]. + /// + /// Set this to override the global style for this component only, without + /// affecting other components. + final BottomBarBehavior? behavior; + /// The background colour of the bottom app bar. final Color? backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart index cd9f90ba..51d9efe0 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart @@ -99,6 +99,7 @@ mixin _$StreamBottomAppBarStyle { } return StreamBottomAppBarStyle( + behavior: t < 0.5 ? a.behavior : b.behavior, backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), spacing: lerpDouble$(a.spacing, b.spacing, t), @@ -122,6 +123,7 @@ mixin _$StreamBottomAppBarStyle { } StreamBottomAppBarStyle copyWith({ + BottomBarBehavior? behavior, Color? backgroundColor, EdgeInsetsGeometry? padding, double? spacing, @@ -133,6 +135,7 @@ mixin _$StreamBottomAppBarStyle { final _this = (this as StreamBottomAppBarStyle); return StreamBottomAppBarStyle( + behavior: behavior ?? _this.behavior, backgroundColor: backgroundColor ?? _this.backgroundColor, padding: padding ?? _this.padding, spacing: spacing ?? _this.spacing, @@ -155,6 +158,7 @@ mixin _$StreamBottomAppBarStyle { } return copyWith( + behavior: other.behavior, backgroundColor: other.backgroundColor, padding: other.padding, spacing: other.spacing, @@ -185,7 +189,8 @@ mixin _$StreamBottomAppBarStyle { final _this = (this as StreamBottomAppBarStyle); final _other = (other as StreamBottomAppBarStyle); - return _other.backgroundColor == _this.backgroundColor && + return _other.behavior == _this.behavior && + _other.backgroundColor == _this.backgroundColor && _other.padding == _this.padding && _other.spacing == _this.spacing && _other.titleTextStyle == _this.titleTextStyle && @@ -200,6 +205,7 @@ mixin _$StreamBottomAppBarStyle { return Object.hash( runtimeType, + _this.behavior, _this.backgroundColor, _this.padding, _this.spacing, diff --git a/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart index 7fb64b6f..29eb3aa5 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_app_style.dart @@ -1,36 +1,57 @@ -class StreamAppStyle { - const StreamAppStyle({ - this.composerLocation = ComposerLocation.docked, - this.appBarBehavior = AppBarBehavior.regular, - this.bottomBarBehavior = BottomBarBehavior.regular, - }); - - const StreamAppStyle.regular() - : composerLocation = ComposerLocation.docked, - appBarBehavior = AppBarBehavior.regular, - bottomBarBehavior = BottomBarBehavior.regular; - - const StreamAppStyle.floating() - : composerLocation = ComposerLocation.floating, - appBarBehavior = AppBarBehavior.floating, - bottomBarBehavior = BottomBarBehavior.floating; - - final AppBarBehavior appBarBehavior; - final BottomBarBehavior bottomBarBehavior; - final ComposerLocation composerLocation; -} - -enum ComposerLocation { - floating, - docked, -} - -enum AppBarBehavior { +/// The overall visual style of a Stream-powered app. +/// +/// [StreamAppStyle] is a coarse, app-wide switch. Set it once on [StreamTheme] +/// to make every Stream component default to either a grounded *regular* look +/// or an airy *floating* look: +/// +/// * [regular] — app bar and bottom bar sit within the layout flow; the +/// message composer is docked at the bottom edge. +/// * [floating] — app bar and bottom bar float above the body with translucent +/// backgrounds; the message composer floats above the keyboard. +/// +/// Individual components can override this default by setting their own +/// behaviour on their component-specific theme style (e.g. +/// [StreamAppBarStyle.behavior] for [StreamAppBar], or +/// [StreamBottomAppBarStyle.behavior] for [StreamBottomAppBar]). +/// +/// ## Resolution order (high → low priority) +/// +/// 1. Component theme style field (e.g. `StreamAppBarStyle.behavior`) +/// 2. This [StreamAppStyle] enum value (the global fallback) +/// +/// {@tool snippet} +/// +/// Apply a floating style to the whole app: +/// +/// ```dart +/// StreamTheme( +/// data: StreamTheme(appStyle: StreamAppStyle.floating), +/// child: MyApp(), +/// ) +/// ``` +/// {@end-tool} +/// +/// See also: +/// +/// * [StreamTheme], which holds this value. +/// * [StreamAppBarStyle.behavior], the per-component override for the app bar. +/// * [StreamBottomAppBarStyle.behavior], the per-component override for the bottom bar. +enum StreamAppStyle { + /// All components default to a grounded, regularly-positioned layout. + /// + /// App bar and bottom bar sit within the layout flow. The message composer + /// is docked at the bottom edge. regular, - floating, -} -enum BottomBarBehavior { - regular, - floating, + /// All components default to an airy, floating layout. + /// + /// App bar and bottom bar float above the body with translucent backgrounds. + /// The message composer floats above the keyboard. + floating; + + /// Whether this style is the floating variant. + /// + /// Convenience getter used by components when mapping to their own + /// component-specific behavior enums without hard-coding enum names. + bool get isFloating => this == StreamAppStyle.floating; } diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart index cfc173b5..cf44a0f3 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart @@ -168,7 +168,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { boxShadow ??= isDark ? StreamBoxShadow.dark() : StreamBoxShadow.light(); // Components - appStyle ??= const StreamAppStyle.regular(); + appStyle ??= StreamAppStyle.regular; appBarTheme ??= const StreamAppBarThemeData(); audioWaveformTheme ??= const StreamAudioWaveformThemeData(); avatarTheme ??= const StreamAvatarThemeData(); diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart index e847e686..ea79ce32 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart @@ -112,7 +112,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), title: const Text('Details'), ), ), @@ -123,7 +123,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, @@ -156,7 +156,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), title: const Text('Details'), ), brightness: Brightness.dark, @@ -168,7 +168,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart index 113e9363..5dfb0a19 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart @@ -116,7 +116,7 @@ void main() { body: StreamAppBar( automaticallyImplyLeading: false, primary: false, - appBarBehavior: AppBarBehavior.floating, + style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), title: const Text('Title'), ), ), @@ -138,7 +138,11 @@ void main() { }); testWidgets('floating: true uses outline button type for auto-implied leading', (tester) async { - await tester.pumpWidget(_withStreamTheme(const _LauncherScreen(appBarBehavior: AppBarBehavior.floating))); + await tester.pumpWidget( + _withStreamTheme( + const _LauncherScreen(appBarStyle: StreamAppBarStyle(behavior: AppBarBehavior.floating)), + ), + ); await tester.tap(find.text('Open')); await tester.pumpAndSettle(); @@ -229,13 +233,13 @@ class _LauncherScreen extends StatelessWidget { this.customLeading = false, this.implyLeading = true, this.fullscreenDialog = false, - this.appBarBehavior, + this.appBarStyle, }); final bool customLeading; final bool implyLeading; final bool fullscreenDialog; - final AppBarBehavior? appBarBehavior; + final StreamAppBarStyle? appBarStyle; @override Widget build(BuildContext context) { @@ -250,7 +254,7 @@ class _LauncherScreen extends StatelessWidget { builder: (_) => Scaffold( appBar: StreamAppBar( automaticallyImplyLeading: implyLeading, - appBarBehavior: appBarBehavior, + style: appBarStyle, leading: customLeading ? const SizedBox(key: ValueKey('custom-leading'), width: 40, height: 40) : null, From f3bed7defcedf01517a1cf0f12d66da5cf611d07 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 19 Jun 2026 11:02:50 +0200 Subject: [PATCH 25/35] Rename StreamAppBarBehavior --- .../components/toolbar/stream_app_bar.dart | 4 ++-- packages/stream_core_flutter/CHANGELOG.md | 4 ++-- .../components/scaffold/stream_scaffold.dart | 22 +++++++++---------- .../components/toolbar/stream_app_bar.dart | 16 +++++++------- .../toolbar/stream_bottom_nav_bar.dart | 14 ++++++------ .../components/stream_app_bar_theme.dart | 8 +++---- .../stream_app_bar_theme.g.theme.dart | 2 +- .../stream_bottom_app_bar_theme.dart | 8 +++---- .../stream_bottom_app_bar_theme.g.theme.dart | 2 +- .../toolbar/stream_app_bar_golden_test.dart | 8 +++---- .../toolbar/stream_app_bar_test.dart | 4 ++-- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart index 882e65cb..299bfc83 100644 --- a/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart +++ b/apps/design_system_gallery/lib/components/toolbar/stream_app_bar.dart @@ -65,7 +65,7 @@ Widget buildStreamAppBarPlayground(BuildContext context) { final Widget bar = StreamAppBar( primary: false, style: StreamAppBarStyle( - behavior: floating ? AppBarBehavior.floating : AppBarBehavior.regular, + behavior: floating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular, padding: EdgeInsets.all(padding), spacing: spacing, ), @@ -264,7 +264,7 @@ Widget buildStreamAppBarShowcase(BuildContext context) { bar: StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), leading: StreamButton.icon( icon: Icon(context.streamIcons.chevronLeft), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/CHANGELOG.md b/packages/stream_core_flutter/CHANGELOG.md index 1f6e33c6..6b03dccc 100644 --- a/packages/stream_core_flutter/CHANGELOG.md +++ b/packages/stream_core_flutter/CHANGELOG.md @@ -3,8 +3,8 @@ ### ✨ Features - Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details. -- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Supports the ambient `BottomBarBehavior` from `StreamAppStyle`, rendering either a regular bar or a floating pill with a gradient fade-out beneath it. Items announce themselves as accessible buttons via `Semantics`. -- Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `AppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. +- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Supports the ambient `StreamBottomAppBarBehavior` from `StreamAppStyle`, rendering either a regular bar or a floating pill with a gradient fade-out beneath it. Items announce themselves as accessible buttons via `Semantics`. +- Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `StreamAppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. - Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. Fixed: a themed `boxShadow` in `StreamAvatarThemeData` no longer bleeds onto avatars where `showShadow` is `false`. - Added `streamFloatingFade` helper — a shared `LinearGradient` factory (alpha stops `0xE8/0xA8/0x40/0x00` with solid-fraction support for safe-area zones) used internally by `StreamAppBar`, `StreamBottomNavBar`, and `StreamMessageComposer` floating fade effects. - Floating buttons (`isFloating: true`) now retain their pill surface (`backgroundElevation1`) when disabled, across all style/type combinations. Previously, outline and ghost variants fell back to transparent when disabled, losing the floating visual. diff --git a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart index 237afb4d..61eac1c9 100644 --- a/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart +++ b/packages/stream_core_flutter/lib/src/components/scaffold/stream_scaffold.dart @@ -91,10 +91,10 @@ class StreamScaffoldInsets extends InheritedWidget { /// 3. The ambient [StreamAppStyle] enum value ([StreamAppStyle.floating] or /// [StreamAppStyle.regular]). /// -/// * [AppBarBehavior.floating] — the body extends *behind* the app bar; +/// * [StreamAppBarBehavior.floating] — the body extends *behind* the app bar; /// [StreamScaffoldInsets.topPadding] is set to the bar height plus the /// system status-bar inset so the body can add its own inset. -/// * [BottomBarBehavior.floating] — the body extends *behind* the bottom +/// * [StreamBottomAppBarBehavior.floating] — the body extends *behind* the bottom /// widget; [StreamScaffoldInsets.bottomPadding] equals the measured height of /// that widget. /// * `regular` for either slot — no overlap; the slot occupies its own space @@ -152,7 +152,7 @@ class StreamScaffold extends StatelessWidget { /// An optional widget displayed at the bottom of the scaffold. /// - /// When [bottomBarBehavior] is [BottomBarBehavior.floating] this widget + /// When [bottomBarBehavior] is [StreamBottomAppBarBehavior.floating] this widget /// overlaps the body; otherwise it sits below it (equivalent to /// [Scaffold.bottomNavigationBar]). final Widget? bottom; @@ -174,14 +174,14 @@ class StreamScaffold extends StatelessWidget { /// When null the value is resolved from [StreamAppBarStyle.behavior] /// in the ambient [StreamAppBarTheme], falling back to the ambient /// [StreamAppStyle]. - final AppBarBehavior? appBarBehavior; + final StreamAppBarBehavior? appBarBehavior; /// Per-instance override for the bottom-bar floating behaviour. /// /// When null the value is resolved from /// [StreamBottomAppBarStyle.behavior] in the ambient /// [StreamBottomAppBarTheme], falling back to the ambient [StreamAppStyle]. - final BottomBarBehavior? bottomBarBehavior; + final StreamBottomAppBarBehavior? bottomBarBehavior; /// Background color of the scaffold. /// @@ -196,18 +196,18 @@ class StreamScaffold extends StatelessWidget { @override Widget build(BuildContext context) { final appStyle = context.streamTheme.appStyle; - final effectiveAppBarBehavior = + final effectiveStreamAppBarBehavior = appBarBehavior ?? context.streamAppBarTheme.style?.behavior ?? - (appStyle.isFloating ? AppBarBehavior.floating : AppBarBehavior.regular); - final effectiveBottomBarBehavior = + (appStyle.isFloating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular); + final effectiveStreamBottomAppBarBehavior = bottomBarBehavior ?? context.streamBottomAppBarTheme.style?.behavior ?? - (appStyle.isFloating ? BottomBarBehavior.floating : BottomBarBehavior.regular); + (appStyle.isFloating ? StreamBottomAppBarBehavior.floating : StreamBottomAppBarBehavior.regular); final effectiveBackgroundColor = backgroundColor ?? context.streamColorScheme.backgroundApp; - final appBarFloating = effectiveAppBarBehavior == AppBarBehavior.floating; - final bottomFloating = effectiveBottomBarBehavior == BottomBarBehavior.floating && bottom != null; + final appBarFloating = effectiveStreamAppBarBehavior == StreamAppBarBehavior.floating; + final bottomFloating = effectiveStreamBottomAppBarBehavior == StreamBottomAppBarBehavior.floating && bottom != null; final topInset = appBarFloating ? (appBar?.preferredSize.height ?? 0) + MediaQuery.paddingOf(context).top : 0.0; diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 96a088b8..d9d8d960 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -206,10 +206,10 @@ class DefaultStreamAppBar extends StatelessWidget { final style = context.streamAppBarTheme.style?.merge(props.style) ?? props.style; final defaults = _StreamAppBarStyleDefaults(context); - final effectiveAppBarBehavior = - style?.behavior ?? (context.streamTheme.appStyle.isFloating ? AppBarBehavior.floating : AppBarBehavior.regular); + final effectiveStreamAppBarBehavior = + style?.behavior ?? (context.streamTheme.appStyle.isFloating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular); - final effectiveBackgroundColor = switch (effectiveAppBarBehavior) { + final effectiveBackgroundColor = switch (effectiveStreamAppBarBehavior) { .floating => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, .regular => style?.backgroundColor ?? defaults.backgroundColor, }; @@ -236,11 +236,11 @@ class DefaultStreamAppBar extends StatelessWidget { }; final useCloseIcon = parentRoute is PageRoute && parentRoute.fullscreenDialog; leading = StreamButton.icon( - type: switch (effectiveAppBarBehavior) { + type: switch (effectiveStreamAppBarBehavior) { .floating => .outline, .regular => .ghost, }, - isFloating: effectiveAppBarBehavior == .floating, + isFloating: effectiveStreamAppBarBehavior == .floating, style: .secondary, icon: Icon(useCloseIcon ? icons.xmark : backIcon), onPressed: Navigator.of(context).maybePop, @@ -320,15 +320,15 @@ class DefaultStreamAppBar extends StatelessWidget { // not a configurable divider. return DecoratedBox( decoration: BoxDecoration( - color: switch (effectiveAppBarBehavior) { + color: switch (effectiveStreamAppBarBehavior) { .floating => null, .regular => effectiveBackgroundColor, }, - gradient: switch (effectiveAppBarBehavior) { + gradient: switch (effectiveStreamAppBarBehavior) { .floating => _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor), .regular => null, }, - border: switch (effectiveAppBarBehavior) { + border: switch (effectiveStreamAppBarBehavior) { .floating => null, .regular => Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), }, diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index 9fa78b37..c800adaf 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -32,19 +32,19 @@ class StreamBottomNavBarItem { /// A bottom navigation bar for Stream surfaces that automatically adapts /// between a floating pill style and a regular docked style based on the -/// ambient [BottomBarBehavior] from [StreamBottomAppBarTheme] or +/// ambient [StreamBottomAppBarBehavior] from [StreamBottomAppBarTheme] or /// [StreamAppStyle]. /// /// ## Floating style /// -/// When [BottomBarBehavior.floating] is in effect, the bar renders as a +/// When [StreamBottomAppBarBehavior.floating] is in effect, the bar renders as a /// horizontally padded pill with a rounded background, a subtle box shadow, /// and a hairline border. It sits above the body content and is typically /// used with [StreamScaffold]'s floating bottom slot. /// /// ## Regular style /// -/// When [BottomBarBehavior.regular] is in effect, the bar renders as a +/// When [StreamBottomAppBarBehavior.regular] is in effect, the bar renders as a /// standard docked bottom navigation bar using Flutter's [BottomNavigationBar] /// with Stream colour and typography tokens. A hairline `borderSubtle` top /// border separates it from the body. @@ -108,12 +108,12 @@ class StreamBottomNavBar extends StatelessWidget { /// Called when the user taps a navigation item. final ValueChanged onTap; - /// Overrides the resolved [BottomBarBehavior] for this instance only. + /// Overrides the resolved [StreamBottomAppBarBehavior] for this instance only. /// /// When null the effective behaviour is resolved from /// [StreamBottomAppBarStyle.behavior] in the ambient /// [StreamBottomAppBarTheme], falling back to the ambient [StreamAppStyle]. - final BottomBarBehavior? behavior; + final StreamBottomAppBarBehavior? behavior; @override Widget build(BuildContext context) { @@ -121,9 +121,9 @@ class StreamBottomNavBar extends StatelessWidget { final effectiveBehavior = behavior ?? context.streamBottomAppBarTheme.style?.behavior ?? - (appStyle.isFloating ? BottomBarBehavior.floating : BottomBarBehavior.regular); + (appStyle.isFloating ? StreamBottomAppBarBehavior.floating : StreamBottomAppBarBehavior.regular); - if (effectiveBehavior == BottomBarBehavior.floating) { + if (effectiveBehavior == StreamBottomAppBarBehavior.floating) { return _FloatingNavBar( items: items, currentIndex: currentIndex, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart index b4349dea..6e504cee 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.dart @@ -16,7 +16,7 @@ part 'stream_app_bar_theme.g.theme.dart'; /// /// * [StreamAppBarStyle.behavior], which carries this value. /// * [StreamAppStyle], the global app-wide style that acts as fallback. -enum AppBarBehavior { +enum StreamAppBarBehavior { /// The app bar sits within the layout flow with a solid background. regular, @@ -168,12 +168,12 @@ class StreamAppBarStyle with _$StreamAppBarStyle { /// The floating or regular layout behaviour for this app bar. /// /// When null the value falls back to the ambient [StreamAppStyle]: - /// [StreamAppStyle.floating] → [AppBarBehavior.floating], - /// [StreamAppStyle.regular] → [AppBarBehavior.regular]. + /// [StreamAppStyle.floating] → [StreamAppBarBehavior.floating], + /// [StreamAppStyle.regular] → [StreamAppBarBehavior.regular]. /// /// Set this to override the global style for this component only, without /// affecting other components. - final AppBarBehavior? behavior; + final StreamAppBarBehavior? behavior; /// The background colour of the app bar. final Color? backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart index 1394200c..afac78d2 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_app_bar_theme.g.theme.dart @@ -128,7 +128,7 @@ mixin _$StreamAppBarStyle { } StreamAppBarStyle copyWith({ - AppBarBehavior? behavior, + StreamAppBarBehavior? behavior, Color? backgroundColor, Color? floatingBackgroundColor, EdgeInsetsGeometry? padding, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart index 7beeaa08..c123c369 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.dart @@ -17,7 +17,7 @@ part 'stream_bottom_app_bar_theme.g.theme.dart'; /// /// * [StreamBottomAppBarStyle.behavior], which carries this value. /// * [StreamAppStyle], the global app-wide style that acts as fallback. -enum BottomBarBehavior { +enum StreamBottomAppBarBehavior { /// The bottom bar sits within the layout flow with a solid background. regular, @@ -171,12 +171,12 @@ class StreamBottomAppBarStyle with _$StreamBottomAppBarStyle { /// The floating or regular layout behaviour for this bottom bar. /// /// When null the value falls back to the ambient [StreamAppStyle]: - /// [StreamAppStyle.floating] → [BottomBarBehavior.floating], - /// [StreamAppStyle.regular] → [BottomBarBehavior.regular]. + /// [StreamAppStyle.floating] → [StreamBottomAppBarBehavior.floating], + /// [StreamAppStyle.regular] → [StreamBottomAppBarBehavior.regular]. /// /// Set this to override the global style for this component only, without /// affecting other components. - final BottomBarBehavior? behavior; + final StreamBottomAppBarBehavior? behavior; /// The background colour of the bottom app bar. final Color? backgroundColor; diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart index 51d9efe0..508ff261 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_app_bar_theme.g.theme.dart @@ -123,7 +123,7 @@ mixin _$StreamBottomAppBarStyle { } StreamBottomAppBarStyle copyWith({ - BottomBarBehavior? behavior, + StreamBottomAppBarBehavior? behavior, Color? backgroundColor, EdgeInsetsGeometry? padding, double? spacing, diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart index ea79ce32..36297997 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart @@ -112,7 +112,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), title: const Text('Details'), ), ), @@ -123,7 +123,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, @@ -156,7 +156,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), title: const Text('Details'), ), brightness: Brightness.dark, @@ -168,7 +168,7 @@ void main() { StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), leading: StreamButton.icon( icon: const Icon(Icons.chevron_left), style: StreamButtonStyle.secondary, diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart index 5dfb0a19..e07ebd4d 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_test.dart @@ -116,7 +116,7 @@ void main() { body: StreamAppBar( automaticallyImplyLeading: false, primary: false, - style: const StreamAppBarStyle(behavior: AppBarBehavior.floating), + style: const StreamAppBarStyle(behavior: StreamAppBarBehavior.floating), title: const Text('Title'), ), ), @@ -140,7 +140,7 @@ void main() { testWidgets('floating: true uses outline button type for auto-implied leading', (tester) async { await tester.pumpWidget( _withStreamTheme( - const _LauncherScreen(appBarStyle: StreamAppBarStyle(behavior: AppBarBehavior.floating)), + const _LauncherScreen(appBarStyle: StreamAppBarStyle(behavior: StreamAppBarBehavior.floating)), ), ); await tester.tap(find.text('Open')); From f94d9ccf3f6cec2c098ec214b1c39095ddec907c Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 19 Jun 2026 11:05:08 +0200 Subject: [PATCH 26/35] update test imports --- .../lib/src/components/toolbar/stream_app_bar.dart | 3 ++- .../test/components/avatar/stream_avatar_golden_test.dart | 2 +- .../test/components/toolbar/stream_app_bar_golden_test.dart | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index d9d8d960..2bace6c0 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -207,7 +207,8 @@ class DefaultStreamAppBar extends StatelessWidget { final defaults = _StreamAppBarStyleDefaults(context); final effectiveStreamAppBarBehavior = - style?.behavior ?? (context.streamTheme.appStyle.isFloating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular); + style?.behavior ?? + (context.streamTheme.appStyle.isFloating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular); final effectiveBackgroundColor = switch (effectiveStreamAppBarBehavior) { .floating => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart index 0372b0cc..5c92c8b9 100644 --- a/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_golden_test.dart @@ -1,7 +1,7 @@ import 'package:alchemist/alchemist.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; +import 'package:stream_core_flutter/core.dart'; void main() { group('StreamAvatar Golden Tests', () { diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart index 36297997..52dde5d0 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_app_bar_golden_test.dart @@ -1,7 +1,7 @@ import 'package:alchemist/alchemist.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; +import 'package:stream_core_flutter/core.dart'; const _kBarWidth = 390.0; From 7c55b7353fa31bd4e4842a13ddad125f85b2563f Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 19 Jun 2026 11:13:28 +0200 Subject: [PATCH 27/35] export scaffold and appstyle --- packages/stream_core_flutter/lib/core.dart | 4 ++++ .../lib/src/components/toolbar/stream_app_bar.dart | 2 +- .../lib/src/components/toolbar/stream_bottom_nav_bar.dart | 2 +- .../lib/src/theme/stream_floating_fade.dart | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/stream_core_flutter/lib/core.dart b/packages/stream_core_flutter/lib/core.dart index 03371bb1..129c4884 100644 --- a/packages/stream_core_flutter/lib/core.dart +++ b/packages/stream_core_flutter/lib/core.dart @@ -49,10 +49,12 @@ export 'src/components/emoji/data/stream_supported_emojis.dart'; export 'src/components/emoji/stream_emoji_picker_sheet.dart'; export 'src/components/list/stream_list_tile.dart'; export 'src/components/media_viewer/stream_media_viewer.dart'; +export 'src/components/scaffold/stream_scaffold.dart'; export 'src/components/sheet/stream_sheet.dart'; export 'src/components/snackbar/stream_snackbar.dart'; export 'src/components/toolbar/stream_app_bar.dart'; export 'src/components/toolbar/stream_bottom_app_bar.dart'; +export 'src/components/toolbar/stream_bottom_nav_bar.dart'; export 'src/components/toolbar/stream_sheet_header.dart'; export 'src/components/toolbar/stream_toolbar.dart'; export 'src/factory/stream_component_factory.dart'; @@ -92,6 +94,8 @@ export 'src/theme/semantics/stream_box_shadow.dart'; export 'src/theme/semantics/stream_color_scheme.dart'; export 'src/theme/semantics/stream_text_theme.dart'; +export 'src/theme/stream_app_style.dart'; +export 'src/theme/stream_floating_fade.dart'; export 'src/theme/stream_theme.dart'; export 'src/theme/stream_theme_extensions.dart'; export 'src/theme/widget_state_utils.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 2bace6c0..92c64bae 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -349,7 +349,7 @@ class DefaultStreamAppBar extends StatelessWidget { final totalHeight = safeAreaTop + kStreamToolbarHeight; final solidFraction = totalHeight > 0 ? safeAreaTop / totalHeight : 0.0; - return streamFloatingFade(color: effectiveBackgroundColor, solidFraction: solidFraction); + return streamFloatingFadeLinearGradient(color: effectiveBackgroundColor, solidFraction: solidFraction); } } diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index c800adaf..aae9f6d4 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -161,7 +161,7 @@ class _FloatingNavBar extends StatelessWidget { final totalHeight = safeAreaBottom + itemHeight; final solidFraction = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; - return streamFloatingFade( + return streamFloatingFadeLinearGradient( color: backgroundColor, solidFraction: solidFraction, begin: Alignment.bottomCenter, diff --git a/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart b/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart index 6787ba62..07b4ff31 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_floating_fade.dart @@ -12,7 +12,7 @@ import 'package:flutter/material.dart'; /// floating app bars, where the bar fades into the scrollable content below. /// * bottom-to-top (`Alignment.bottomCenter` → `Alignment.topCenter`) for /// floating nav bars and composers, where they fade into content above. -LinearGradient streamFloatingFade({ +LinearGradient streamFloatingFadeLinearGradient({ required Color color, double solidFraction = 0.0, AlignmentGeometry begin = Alignment.topCenter, From ee041cd2cd63868ea3f02f8e902a631cf748d02a Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 19 Jun 2026 13:29:37 +0200 Subject: [PATCH 28/35] fix border on streamavatar --- .../src/components/avatar/stream_avatar.dart | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart index 8fa694c6..76aa3c4d 100644 --- a/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart +++ b/packages/stream_core_flutter/lib/src/components/avatar/stream_avatar.dart @@ -214,32 +214,38 @@ class DefaultStreamAvatar extends StatelessWidget { size: _iconSizeForSize(effectiveSize), ); - return Material( - shape: CircleBorder(side: borderSide), - color: effectiveBackgroundColor, - elevation: effectiveElevation, - clipBehavior: .antiAlias, - child: SizedBox.square( - dimension: effectiveSize.value, - child: Center( - // Need to disable text scaling here so that the text doesn't - // escape the avatar when the textScaleFactor is large. - child: MediaQuery.withNoTextScaling( - child: IconTheme( - data: iconTheme, - child: DefaultTextStyle( - style: textStyle, - child: switch (props.imageUrl) { - final imageUrl? => StreamNetworkImage( - imageUrl, - fit: .cover, - width: effectiveSize.value, - height: effectiveSize.value, - placeholderBuilder: (context) => Center(child: props.placeholder.call(context)), - errorBuilder: (context, _, _) => Center(child: props.placeholder.call(context)), - ), - _ => props.placeholder.call(context), - }, + // Material clips children via PhysicalShape, so a border with strokeAlignOutside + // on the Material's shape gets clipped. Draw the border outside Material instead. + return SizedBox.square( + dimension: effectiveSize.value, + child: DecoratedBox( + decoration: ShapeDecoration(shape: CircleBorder(side: borderSide)), + position: DecorationPosition.foreground, + child: Material( + shape: const CircleBorder(), + color: effectiveBackgroundColor, + elevation: effectiveElevation, + clipBehavior: .antiAlias, + child: Center( + // Need to disable text scaling here so that the text doesn't + // escape the avatar when the textScaleFactor is large. + child: MediaQuery.withNoTextScaling( + child: IconTheme( + data: iconTheme, + child: DefaultTextStyle( + style: textStyle, + child: switch (props.imageUrl) { + final imageUrl? => StreamNetworkImage( + imageUrl, + fit: .cover, + width: effectiveSize.value, + height: effectiveSize.value, + placeholderBuilder: (context) => Center(child: props.placeholder.call(context)), + errorBuilder: (context, _, _) => Center(child: props.placeholder.call(context)), + ), + _ => props.placeholder.call(context), + }, + ), ), ), ), From 66ee511050b8ef4f8a39edf0c2c62568b521d34d Mon Sep 17 00:00:00 2001 From: renefloor <15101411+renefloor@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:20:45 +0000 Subject: [PATCH 29/35] chore: Update Goldens --- .../ci/stream_avatar_group_shadow_dark.png | Bin 18364 -> 17853 bytes .../ci/stream_avatar_group_shadow_light.png | Bin 28997 -> 33001 bytes .../ci/stream_avatar_stack_shadow_dark.png | Bin 4066 -> 3774 bytes .../ci/stream_avatar_stack_shadow_light.png | Bin 5595 -> 7130 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_dark.png index 0e687ab1a538100dc7c829083c8fce9ae816ce40..4c8ab5927d93462812034441f3c6ca00a88b2310 100644 GIT binary patch literal 17853 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 literal 18364 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 J#V0-g{|6Lo*@OT9 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_group_shadow_light.png index f150b2de7dce2aa42ed6d7bbaecd6e19a015748d..6130be6f869283168410a0e4046048342b617444 100644 GIT binary patch literal 33001 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%0A?Ia`x60y%gbbvEaejPGTp7H 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%0D2e;>s2e{o46Z^0=G z!WPr<@qP-fL`F|4H}~>!%Q=>px1$mdZZDcRb&<2~CKaOJxEJ8C4Vg);fJS78Pj+~u zbXrq*(!WmI`LBG@f8kmF=a;lfuiQkDmzN)bzI`bEf%1SRlfms9GaDQ34KmOLMgTf6 zn4Kgt7`>$66rNq6<88r7Ks440-B)01I1?d)HXU**s@pO$-H))eeW!I0?~oA)X!}4?{As zXaq+#iWfo89!P>#*$UWm!AgpX+f%Mv1yHHLDL0+KeOMmXcXoEpANz$XDi7;sl!#ev z`4(kk$yj+x_@h4qDLALtH|_^|$D*lQjXL%aL-DL1!At{&p#JXPHX!l};3y+#HHmxU zM(!a4{wCYSj#*^81b73N!es=04-S^hZgnFN)|V}k11a^=W+A_S6BwyDsyRE!g+@z> z%Ly!ee`uObCzrjtJd#3k?HY;GYE}mF7a=J-(#H-mTr4!3!?{&bRJF!aIa5VS%F4~~ z03F_U@l=bAvEU#N6sQtIZD?_Wy8IkIYWA*eSgn$Crpq2d0Ri(+ z_aFdSyImX%Kj-05Td0mhUl}cARNps8KoMxzfsZ^|2;6Q!`rMikmOx)2sCZsk^4+~< zJULlaF-GQ8CZpG+bD}?6tYIP)Ht-(I7qTPs@^rY4mUKEU-RRGld4Ev}>MkIznipR^$3qPw_$GK%-!zBI!s*>%QLuH@bC>&VRiFSzYB zx05UGQkuhrTo=j=r62+WBv}Mb*boE|NV{;%$7>#!Pyem8?~dmB|NGXry=aI^(T=QS z=3`Yx2wB;yAzMadS5^pR7D;yY-m5|?eFz~VLRK<9k&F-S$GhM4yRPd#*E!cY_c`|; z-*YvXg_NniFEu^=8sHOGI4PiD?JSUQ zZ%_P^$7Rl_gDz_zHRbsLUX0P_m&!DW&q?)l56=tx&J}4sqxNvva>t%9GxR9X=0q() z7>%KEAY_f2u7T1uxU|!Iw=o3V7G*2SATQRngVSAr-vRcvqks+XuH8syRAiT=P~Oeb zTlJJhRrOQqrPj=ukY)N#YcCFVb$;C^PC?S{OEPsZ?+lLqU@cn7hicy zeB^|}6#HNP>W+!~&YudGBm&;HjBoeqgV%ePN8W~(K2Eyuwh$<(g(Dr%bemKD`)z83BIo=f)je2~cv zfti%d?#MrCBPg~;^wurgB3bH5<{;x=HFRtYEQbnQ#Dfxb53!S?K_59x^^)beD{FBs zT1I%9L~$8ZeI%TAz_RX4mX6ST$z}KZr0;3Hl==JZyN@Lw2ScUNgLBvM{7=;-PDk0l3NJSgb*S7@A*CR!2L^MFJVITQ^3?qr z2_)$$Lx;((t*_wy`~t-sVNxO6?Hq`LRWRz^yNmjF`q!J8nSH5n6Fm2IvHPbyb%-(6 z_>;uYfI+riy@eH9fI1mDyow!{H3fk2ZK-}a%Qp@&R@L3s0os2k3ZFQN8P zFCOU&_!%fGH>w6dL@%CjiMmSPb&aNPN=y!J5GdKNAubK)4Qoh12`>YC5ukk{mjmdT zNul=KB+?r@EzOW=ra3rYKPt0mz!E3r!x$ zSy@4DzKR2_$(7`R>Pi!Vm8uVQtDF<04f#`_WYLS{wU#*-bNNB% zt>8y@(bLx^$ww-my_3*v#%W^`@X4gmMhtsiI|V9L_`J?6cCNEtB>M;m9*He2Q`P%K8m5IX2^pG`-H_oH&;b*Z4X5;oaxpFBRxQXhqbUuw}p)>#0$WtLdvSIw)Gs&baE}RJb((SP3F4P_ZHz@-i-G z>!gWtD|a_OA3(jd^a;H;?$6h@xV__zc-M3_$YOQf-B(#|C{N>{F7`sEBI*Sm zIP#KOcXNJ5j>1#8Gt3I3rgnQAD(P;jaV#=9niT2qYvGq5eSilkt58|>_HyGcgl`;& zvyaih^)aO9tj}U{d|)Hfcl)hgWZg&ms&}o-SZB8T8nbBKSYzHB;#niq&cP40)!RF| zeDed?Nq;N`Rz`Ocv15c5)Aswj6P-Go?(L&}iU4?s;{%Kf%>g+vztH^gDR)KFMy{-% zN@*-3AW;Qi#!D_M(;h33+-m>pyDWif;B!MgaN*i?fho1ipS{33^9qOiwe^nU@BjFb zl+)V?8-|8~oBCLoS2&^2!m-*vF`k8z&5r5y0d40$85mf zKLRg;y6|xdX}_LD9qgeD4DC7AVJ+E@`hv1VC$XD)0&)Rp%m~Fxn4)Zf1R+Lf5}DbC z$2URRWhqvx|J*SIfG-=vs-np@=Fe?yJP2DM$RuUu$1QA|*)^+N&k`FX&Bowo64}MY zrqo{*q5f~JIc_ov(jE|7^9nHv?A)PzYXiB81gv`AJ>j`VBlO5Vu~Rou_p7|k>gyUB zqH|G*zMi0MuAA$w;n2?;DiV6`x zEu+1aq!XcjMQe&;*wr;u?={ONXi`Z--CR#Te2{~rND55a*|TS{Zrv{=1Z09WdmD6c z>s?QIbNS)xyEmjP3ZAGBWU2>g5T+@fYNJyw!q;+1PW#Z59asOtx>$$#|Kp?JE8CRNC7)dAVOPipQx>wY>py2U|Eakc@ zAOx71nF0QX#KtP!dO74MQC!rh=kf?*PmpN9o=|s6kA+EY%|n=lkMH9enGhS>q6wzE z>c=DZ1X^#VZTw9qiOTuR=e~a|zvRTljr^9gDJ2hTFdC@vRUQBSU2o04I8%oG>K1z9 zUQb*_)@Lf-9IMDsOmDUMKFU+#9B0*2qD=h#wr)&3>Rs-evdiZ4;whYmbL{pyIXS^L z+5%_|&0n&;+?(@e=H>)IRpZ-Hy)ZJwV$!|tqw&j+%3M|6B}Kp1o9s0cj3(o0TE*ke z;Mv-_^LIDp$%p8vXxE`|ej0p<4UDBZFUPwdga(w82Rqd0S@-wtDiA&h-K}T3CEwYz zT3Ei`)Y(=gJduHK-z1Fs_fWeXh$a7Hm+*!H4UVd$b?dw@>*_vCPiMzIi1rolyTng= zj}Bhsojac$Dd~KU1!|G;1ki;-}0P7rF$)ztFyWiOH1cpoRu6M&)OL_OD+*Mg-)TOuO*VhK7d)bYBJqDR@|BMwdpELr7Fw zN-lowmz?zSZXd^WXI`K5?ud80@8u+pTOT`nwiGhoqCdr1$>*ErBh+qY zt@?)ubmi%K(6Mo67dTPNqHLuGbyQ4E_g!Q%{e`PTG^wEO%d9N2o!F+k={jzcza$TF zj4fVGfAQkgFooQ)M@O!<_!y~tG159Qu!y6h_;K2g{n7Q+Re`KK`$A5g8Xr-R|JQwv z*_SaC)&)W?S1jaJhsyvEwz@t`e{z#E zmHTSZ&;c%4d)fYYQ_I=TOU>bne%>eu?zjl{IdR6DmR7m#{n}%}Y+!lwG8SZ;S_d8F zB9o<7mi1BL%n9GpHf>KVH`(lt`}iWJaQx-9442=0nwlu)SbEX>xRZ+ukeKy%eSJy% z0+Z{nm>;AMwALy-WLZ#$r+YQKcv(2`6v+k8B_zRfE%96?OTMIW2x8bzuj1elB=R_TM@d$rlEt{3~o7du&=o--N6NA_B#>{+2G2QV2 zoe*D{8K*xY8O4oz5K1U$ z7XT$G&u^1dy`32d0{!Xzo^4(0?Mo8|)gz6S^&({T)Y-rhd~SR4GMy_Wt881iv~O4A zn!@(GU5$6O%_WkWQEQ8{G8iNX#@kuqkE)t^$i}<}*9z0*I8Nz7}fz-j*>ZlaZQg3<`i(3su|6qY2uvW1 z`GBo}VWGc>;Ly5{7;E4}*I?@Caha+lJBuDQ(t@lDK-)ct8~T5~sGMkuHcwAIRVt}Y zkxKLDZsiwx&`cKu2M~?5^^}kKXSAY_pfP1NqY0xuAoL1B9P`*cHgBKsdEFVxb@;2r zevcX-ezpDwjY*us9dMfV^~%kSs4DGfD`p~cbilnB81!|otg=RBAyIWFBV#?9YFVqY ziGYKd`LV=K$UP&oiS7_A+F+&GV}jqfvj*#hdNh)7w?O?E4x1kq1uJ{Utj-XP&;yx9y+z+oz z1;S`WR^|sy`1UhB3pDuv0-7lBjq{(nIRE*6)oQ0=aSlyRY0)m#MxIj$PVFqF9?XW@lzorc0k_2$x62CS zg7VlqB?KYy0HObx(@mO>g@|rNSkn-6Z;6HF6O8rkrSmXvyug+=J(uBe*DpAD1U>&{ z;e!;W{a^RkO}rNcY4*cEc~$xbwQRS zC>T6=Qc*=qFCeC!8F+nTmb6IaG8@~e#FwWd^IDFWrJXt*olf~}rJz}S8AM7wAXJ)p zWQ93V=t9Tn54=scV_@Iqf&7Q>BPO?|$Gl_ui+x49iY?blfHp$MsdCg~cYNx8*oZ;i zCji?7wrV57zcskMDB3R3Zthx*&lIZ3lr6swluAqgTMLlq_h3^>TAKe<_3Cq2KDEcf zYOPJ|bMXRL5$s*do?UUix~h_mH~L=mA6m9LU5yLxy$^C2INbfyyG;5Y02yW6p3YtH ztk3Ji-xxh2Y?AJ8m6iRh9@)%avYYThq8b5iL;>~p3jhlR)jI$XlObMug*G(Vh~j(! z19gEz^#YSpp?V#CY~RPx{eXm}hZx}?<9=+}3OcNKh5HnmraI=F{;aCTfT#=ifh z{E+w8|6|vVcvG|4UoAwJ4_F#N)HS~SXP+0;b9}Lt_nI zC0mMLPNEztaiNbXo0H70UY4zJt`xv zC>W8N;WcUWo4b-wol+^m9%}zl!khB#CyeYwRNQD^F{Af_!p+?u(?S|v+IbjW_-RJC z=D?@wIQ~q0p{vv}xi+^|d$K_%TX2Va(~e)4w2LOb$U>b-0CTHTtIOgDul!QslwWt% zZ}=!omxM+X2*E#w_Ek1qv207M69;&OoQ3?bZ$k0=I%4Y23&*W5>`bf!hJn*5L{54N zIsZ6Aa-4V#%OXIP`y^+Z*#~DRaL_)T`H)YaQm3M!-ZgFAlziZbNCp$&2n6#yfjp-* zzVt!zU~WD0;5=mzG)HrqI(uWRm`UsWT;@LuR?7@^1A^^JH|hEZ2Hv1u5^`JQgU1}L zDutvrOzOGBCM5I(#P<`ZsB>&)9L~FJ&((DZoL%W-%(-3T2q3>DS%C?1gVJXjvP`Q6 zv>UZ+hPIAO&lJ=*H3b9O1U^xN26q1zRrxJ$Cf;?yZ0^H4MWNM|{GK_}S%HhLC@7Jw znwXqC@Z-ma;e#%wEc9=;Hi_N$ZGMbiXIrIy(>+h$TQfhrJVW#An)=0`Ub-Q|V@iLp zYl(dq%eUIcqT3#3uq9BoAZgQzHKmYD}!eFswBFEEqdxN(E}#Pm&Oc#2d$m6I}F-M=cP&b2a8rt(C_ zkm)2+Q-~1=&`DT6VeH(?k|j4>)ApW$tlaaLt8lE4pFn%ZbRwJfpeuK3N|5%EV(F!B z9lH{HF>fHI*xQ(b4k)};8@ZZ)e(S4jy+cyr8}J*+Xsi#2xjsS0^%;mIqK6JeZ2&7x z#6v=hMl;%#dQkP`!$Z!WFB3k;S!YqwF2}*$pK6S~8+X&m@FG&2K7ejVS0#fChT z74ZGL{P}6z|15I;SLhAc9BZF-K=miXbYzi$x+uL@F0l+pf_%^*{slh{HKhSL)neI za)n&;E4GGzu3X7@IW@6h)S<6kxVi3|NqO`;{w!(7hrO?V_7pPSMVKBD%2c&HrxQJL zB?fF^DF}IfvIe^?NhEMEx@}_jTRv@zrSgV9k~WZZYzUdyoC=s`bl* zUSHQs9h@EGMc8aE__&pYU^*d}ISvAp20~~(m+lgvlMfc>x!au9mMvRG?UbxlXgeKf zr_Jrc13l6ePp(P?Pws^NVH(>}zWta=lIpJF(Vzg%yWCat_lXF3K%Z-1`Txll*ZwxT zkC_xzOOhYi!NLMX$&INh&vjmsr^<%IV-#h4A6=aLDSG!xIvBR%Rs!1_yrhJrr^Or;m0gKuwpfb@nG0G?#Uv0rZc=`7$HwNp-Bi zYrE5(J3Dslcm;j~`X`ItMbX3kj|Bp%tsRe;UvbaUr1r(PGO?!SorDwvhc%IS3K0B; zj8FMT(2NiDv#s|EPj>TqJ!}}s+$Dc=W8;R?!uL~n=SyCH;1)m1!?UxnY^6xZ-q4z= zO^Fs4v-%w?D11M^@^?}8659m5^0Lc6(;wKgUv!K+A+kGT_a#klDF}6daz}9LyhSiF z&JyEqcP}=^_Q)%Q{}xPhzwwq&Y-KbS8ZZ#3H`Hi*O$v&urThy`3bgrx#6X4Z*tP2o zgf6dUn#8jSJQ2{W$6{+Nu)-R{(>acP?q!lauJ=^s*|`OI#<@L?2nbwx{6FwWRDC`g zzv{l8OKAQ}hGyw?pY}NQs>8d0x1Ph+)swa-=2ge0OubiaG(pav%+IyHBgIMUtvbnw zmI!}l>FCg8sW*&c>}^VUekd`4af9bQ%wh>b!yxdnV;9+1%0mZRuMt#<+q*YxJFr96 zsGZF}n_lzG$L(_yipO5WaARNq3qY9IGxE21oi#c2ua)i-6^hlDgir-8dctIih(6Ys zh@5*cIrG99joMnsV?{=LVMF(9fbBwgz*9jDV27uGKnLnL{xjXKV@>F5`~#xv%VgdV z?~oX_&?Nfjz(zXeT8NKczB{cF^wVmVXS?vU?Q$uNijI?Wy!LN9qmiL4bB@zJ9wKay z@41~fZA;s;^k-@W1|~v)nWyQ%d!1t412&S#w0UvPla+%b(M3{-OL({VbJC5m%QPQX z#~sBBA`8@xM6~WAYiq0jqDAE zwVzfFkaE1cx(vAPy6|=|YH52XPnz+6>vvs}(!du~PitZHd3w?95)$UfC{(`ujbk9+ z40oaMrawGgy|Ort0OZzc4-bO*hJ$o+a>%vXjx<5~{i?H$e8i?bV9|^+_vFkTSJ|S2RnP!A^?1_j|Udz~KcA_D{Q6iOjWyWoQZk^+j(|jXC zhsjt{jB6Ejd)+`^khx{8nx6Q|8N?o-F}p*lV+1%D_@;BS&K6h!M;c>9=D&F&MdL5y z>ipden$@V;XDVf0bBpAr@t?2Aag-X*h~&1E=;yS8A4) zu2pvHN)3~|Z-~;s_nuitD@O;L8y+gl-4B4Z5@f7e_dHp_h>6g{L54-p8D(Y23Ge0# z)6}u?p37|Wud~khW+l1+d>r5>w$ER9FsEWdF5e9Z*h&mODJgjZf$p_4Pd81rcpI&C zu^Id6&b1o0m>z5Q>0XL_D_cQU^ULuW+miRXSzuKWX>)b7Qgri{El{O}p)mi@(0~Rj z68^{hA47Zh@BaX!3o#4{br2M9+mQi@oAOGpdMKYNOT9D9+NQpz*zIQ^rLS4^$Tm1h zx%4Yu&a?k4PB0I4dH?PmF>1$tti>Cw433N|L}1-Cw2d#Wq<2;wZ63bRGvss4bi$Tt)!=8zSDtb!B1Xb9+0{cDj{qR0*;3v140$ zPcB>cnXawS_Mh(T{f_2pcbmsX4%by=$UhTzx|`RNzpdn?7rNK@~)v6nq}E*56;morefaCwnKP{($9{h{QVE(IzSH7xrio=>y2=s=z=pePWo7mkJ}pq0 zbzZwf*KRE*;yi02U>PzYsU1&Xv$_e#hl&gym!-|$kEcvY;#&?0p^a-cfk4*lC%1DX z6NXkngr5Kj3EsgB(h*_k#9MuO?$2DD%LDPQr~^IQs(Gb5*1e<=ys&+-OXSFT>OP@w z%)*Y7UI=r5CmvbV!BF%N{!PfrTE@0)&Fwrd0D>7ES*~Tb0K`9vkhDL+nFlJENRm;S z>f7sS-MVJ`jx*8GCS_i6k$fegjRAGu$y<#27J zPgO@tk|fSuH=uLgSW)b64i0pMBD0?^0Fb3mY&Id{nuw}{FlK~n=o=9NKxBhJ%KNRY zY@uf(OeE8@8Pyw!!~{eb=x;2UKd!D0>mSj9Cf8a4~GJIr_d{b(FrnfWf3M; zOCXN01%yCS>n?`B2>tdhh43PlH|bne=)SF48TxkpL-Ktb8R-iLIn1Pkr~@FjVT*|{ zIRdn>4p`HB{FiEfDsT=awqN+~RE$r~y%V`C(m>E&zb+PY`a^60N8;T{%&JZ^ZlT!~ zdG7A#?%WX~Iq;DKm81r-n+obCC~{4L6H!%u0c`uz5Bq1LZnP*0v45kvjer2NnS;MU z;{e3{)6*|mu3k2clC1o~s$IDzYce`AG&I3p_|1LXK30H%+3WXpCcv!QP5@PvbCNoK zk!k07K09)r%6l@|lC|i-!RVDPZ9#yc_y=GH49AkZ2yoTP$_napu;#b^6ioOx4R@V- zD4lSX!kOBxyJ}#1bU?9?GJd`F&RAqq7vFP}t|+&rhzq=$?`Dm+X%s6wPMM1sTJ*j5 z?3pg6$Shq_)liMYouu)0cu2`I?W}%lA;2DUU#cK%W`|%0M?fZ4t539Fy7|nr;D5gT zxDs0~QdrEZckqjD+s-HkC~ z{=k!=hp6lB*0DOqNyt$kcz$IeV5cDT!5!)^|X781A zimgby2x#$aULA49HZQ0h=FU~4N@S)S=e#9gj;IPc!)%ErL zFr~0@#s6*f?z2xBH*Mbh_WBuOavf+!kZkdOAalbaBCrieg@uK^dy~wmo6lK>VxFYBq~PuC)YCo1OtUgxy%GQw>Wc_Yb?rph#&NJULcrNz zu=0!XVdMVjw;iL;-t(SiWvI?=Og?b+U8N`+7nd<)3&&0hRv*4>E#&n&PD(S}0ym^IE)k=|}X5%TwY94BZE{$fz z9Uc@tuNxZVL4od0yprBLW{*}IehYTuyMt;DPiWiGqFdxD`5Tb?R?N1@(`@?}QgSM$ zMInY1^YPK^KmSa_Tt%41h<|)|VuB2zlLj!$Tp}xDv zKC?Z*G$*me(WAuR4E&Hn7;F=Ur@{JmTb%sR(bh(s7_SWRfez{uuToBU}K4 zKV`S);BeL(D{wz7Nb$cRvjV0Ej5+99u|BXSki!!_^`>WXBP^quv?q1b0#wUkiYEb!ujKH^1!a(U>#x33% z&nyPw$U=7yDZNLM8PH6b~9%x<*h9$fX>Q5+adE@G!k=YDxh! zJ7#Z1V3q(I@cRwl=gTDmSc@<@L$ln06FUGg^6uL=q?s$I2xo5CHxj(7Cuu7YkOfsM zk#|i`pNP)chuL-d9HHqVE(av`K7nKYp)!^l(+`=K4h4%R=u-Psu4q3@3D|;cWrSfZ z^sO!%AdT~`ezt}%e{-#Ap*GYqVB>Ww?&Nl6oH9^VtwEm%3g~=7^NTitCOzibO!J*} z3=#mcFglc=v|#q(y(MvML}@Zf`gNwOSz6jfQf{=%l8lO$mMr!r!ixWs;t=T!5i5po znmoBCbp4y?F&1jCF~xv7)j^q4U3W6@i&56@O=W*51p zkohnoh-e69=Pl`K=(q@HO9_|tSf|;7_NCnQry<24%+|Y=MAp1|wdOIsaZLQY+&!`# z+q;Hj)+IjWwM%QKzg!C@IF{r~Pp{7CO14sufc15Wd78w~D6O(DLUCjo@ z&))&^&(kAJBJ^KO3tbl`jKx+vwnz;a z*!>!1UX)zdKQvT_lj7fM>Qkpa7@vI*@w&H{Ib6;=Cgvb6^!w0|4T2<22qtRcwPLS< zG9EC(+P@yVH@&_3W1qdY7nEELNU!1Nu9*IZkj=nphpM$XUB@Npq-9Ftynow31ieB3 z=f{%H_Ljbg>4I+47+INwgzEA8s`z`Mp}T=r$)vOr@;T_Z#@g~XPSUC$Ak9~*TkqNz z*%<0Lwhj=e3df3f>(XAaL>7E~gzFMSXf967<O!4~4ylY2Xxt^Z|eh`f#Xc^o>1US91aK6U2p@Jr4m}Zy1q>5~LxK-oT%jFjeP~tjsBYGW z54It67B$^%AKfk_V7|&tG|t3aN!0!*im&Br#t&)cUEfS-cc4%lgfQ|ATv^RWHz@1P z9!&|FC^pHc=((hLu=iYWmgQJqHa88_?f|V=89X3Dte9ye{p>0XfIB_l?QTcLO8vf^ zf68${135x17a9@q78=Raj10A7*%0FZjF**{Pk^8gQqaNgYSl_(g*Vu1zsA)u=+Gc9 z@n>IkEUI;8m!CY)P$N?P=I7~iB|jQU!lG(}Zw9I8-Cj}>M?*{vi~2ZZ=X*;~?TqpF z%OFL8I1J*jy8)j00J7ddH>E#|HrYp<6a=cP@4j#Yv(^-BYZtnRqD2-0h;KFu~+ z(5ABQfTD#%r|2P!Z7b9f@zyFg7c^Sl!NGKo-JJQUFu2`2 z9Mi-&t~y7WQtI0I|Mx~(UvTwSG_8cM0o4Y53D)&Bdt_r$!vG|}M0FESLn zNEZ8q)h0?QLy|*igvUn6jFH z8KBD3g!q;)0#8-PLT%q1SHsP+H%i;}@MM^NHX^u#^777nG`6dWB?$?k4wnEtggpnl zIQqMn>FM}VCw)9z&{6M!yR%UH>*dj}867{g`#YX6^EFey-mYWN;9dmhht2>K2{yyp zc?2~iq^;CM$VPjTl+q!=IHY#C^f#O~my$ jy1$d_|36vX7FRQ$^;Ne@Yhxq<4UMdnqGZ;2!~6dSmFTkO literal 28997 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 diff --git a/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png b/packages/stream_core_flutter/test/components/avatar/goldens/ci/stream_avatar_stack_shadow_dark.png index 6230be4deab3ae4b39d2ff0e979171e357d1e85a..5ff0e365cc19bb1ff1293bba7cdee23cacf241d2 100644 GIT binary patch literal 3774 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 literal 5595 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 From a58a7b1e57ab36150caeaa7bf986127bb1d542a7 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 17 Jul 2026 11:28:51 +0200 Subject: [PATCH 30/35] Add unit tests --- .../components/avatar/stream_avatar_test.dart | 22 ++ .../scaffold/stream_scaffold_test.dart | 218 ++++++++++++++++++ .../toolbar/stream_bottom_nav_bar_test.dart | 163 +++++++++++++ .../test/theme/stream_theme_test.dart | 26 +++ 4 files changed, 429 insertions(+) create mode 100644 packages/stream_core_flutter/test/components/avatar/stream_avatar_test.dart create mode 100644 packages/stream_core_flutter/test/components/scaffold/stream_scaffold_test.dart create mode 100644 packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart create mode 100644 packages/stream_core_flutter/test/theme/stream_theme_test.dart diff --git a/packages/stream_core_flutter/test/components/avatar/stream_avatar_test.dart b/packages/stream_core_flutter/test/components/avatar/stream_avatar_test.dart new file mode 100644 index 00000000..7e9087ba --- /dev/null +++ b/packages/stream_core_flutter/test/components/avatar/stream_avatar_test.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/core.dart'; + +void main() { + testWidgets('StreamAvatar renders a StreamNetworkImage when imageUrl is set', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(extensions: [StreamTheme()]), + home: Scaffold( + body: StreamAvatar( + imageUrl: 'https://example.com/avatar.png', + placeholder: (context) => const Text('A'), + ), + ), + ), + ); + + final networkImage = tester.widget(find.byType(StreamNetworkImage)); + expect(networkImage.props.url, equals('https://example.com/avatar.png')); + }); +} diff --git a/packages/stream_core_flutter/test/components/scaffold/stream_scaffold_test.dart b/packages/stream_core_flutter/test/components/scaffold/stream_scaffold_test.dart new file mode 100644 index 00000000..b569089d --- /dev/null +++ b/packages/stream_core_flutter/test/components/scaffold/stream_scaffold_test.dart @@ -0,0 +1,218 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/core.dart'; + +Widget _withStreamTheme(Widget child, {StreamAppStyle appStyle = StreamAppStyle.regular}) { + return MaterialApp( + theme: ThemeData(extensions: [StreamTheme(appStyle: appStyle)]), + home: child, + ); +} + +class _InsetsProbe extends StatelessWidget { + const _InsetsProbe(); + + @override + Widget build(BuildContext context) { + final insets = StreamScaffoldInsets.of(context); + return Text('top:${insets.topPadding} bottom:${insets.bottomPadding}'); + } +} + +void main() { + group('StreamScaffoldInsets', () { + testWidgets('of() asserts when no ancestor is present', (tester) async { + await tester.pumpWidget( + _withStreamTheme(const Scaffold(body: _InsetsProbe())), + ); + + expect(tester.takeException(), isA()); + }); + + testWidgets('maybeOf() returns null when no ancestor is present', (tester) async { + StreamScaffoldInsets? result; + await tester.pumpWidget( + _withStreamTheme( + Scaffold( + body: Builder( + builder: (context) { + result = StreamScaffoldInsets.maybeOf(context); + return const SizedBox(); + }, + ), + ), + ), + ); + + expect(result, isNull); + }); + }); + + group('when neither slot is floating', () { + testWidgets('injects zero insets and forwards drawer/endDrawer', (tester) async { + const drawer = Drawer(key: ValueKey('drawer')); + const endDrawer = Drawer(key: ValueKey('end-drawer')); + + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + drawer: drawer, + endDrawer: endDrawer, + body: _InsetsProbe(), + ), + ), + ); + + expect(find.text('top:0.0 bottom:0.0'), findsOneWidget); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.drawer, same(drawer)); + expect(scaffold.endDrawer, same(endDrawer)); + }); + + testWidgets('places a regular bottom widget below the body instead of in bottomNavigationBar', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + body: SizedBox(), + bottom: Text('Bottom bar'), + ), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.bottomNavigationBar, isNull); + expect(find.text('Bottom bar'), findsOneWidget); + }); + }); + + group('when the app bar is floating', () { + testWidgets('extends the body behind the app bar and reports its height as topPadding', (tester) async { + const appBarHeight = kToolbarHeight; + + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + appBarBehavior: StreamAppBarBehavior.floating, + appBar: PreferredSize( + preferredSize: Size.fromHeight(appBarHeight), + child: SizedBox(), + ), + body: _InsetsProbe(), + ), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.extendBodyBehindAppBar, isTrue); + + final topPadding = MediaQuery.paddingOf(tester.element(find.byType(_InsetsProbe))).top; + expect(find.text('top:${appBarHeight + topPadding} bottom:0.0'), findsOneWidget); + }); + }); + + group('when the bottom widget is floating', () { + testWidgets('extends the body, drops bottomNavigationBar, and reports the bottom height as bottomPadding', ( + tester, + ) async { + const bottomHeight = 64.0; + + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + bottomBarBehavior: StreamBottomAppBarBehavior.floating, + bottom: SizedBox(height: bottomHeight), + body: _InsetsProbe(), + ), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.extendBody, isTrue); + expect(scaffold.bottomNavigationBar, isNull); + expect(find.text('top:0.0 bottom:$bottomHeight'), findsOneWidget); + }); + + testWidgets('reports the updated bottomPadding after the bottom widget resizes', (tester) async { + Widget buildWithHeight(double height) { + return _withStreamTheme( + StreamScaffold( + bottomBarBehavior: StreamBottomAppBarBehavior.floating, + bottom: SizedBox(height: height), + body: const _InsetsProbe(), + ), + ); + } + + await tester.pumpWidget(buildWithHeight(64)); + expect(find.text('top:0.0 bottom:64.0'), findsOneWidget); + + await tester.pumpWidget(buildWithHeight(80)); + expect(find.text('top:0.0 bottom:80.0'), findsOneWidget); + }); + + testWidgets('is not floating when no bottom widget is provided', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + bottomBarBehavior: StreamBottomAppBarBehavior.floating, + body: _InsetsProbe(), + ), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.extendBody, isFalse); + expect(find.text('top:0.0 bottom:0.0'), findsOneWidget); + }); + }); + + group('behavior resolution', () { + testWidgets('falls back to the component theme when no instance behavior is set', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + const StreamAppBarTheme( + data: StreamAppBarThemeData(style: StreamAppBarStyle(behavior: StreamAppBarBehavior.floating)), + child: StreamScaffold( + appBar: PreferredSize(preferredSize: Size.fromHeight(kToolbarHeight), child: SizedBox()), + body: SizedBox(), + ), + ), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.extendBodyBehindAppBar, isTrue); + }); + + testWidgets('falls back to the ambient StreamAppStyle when neither instance nor theme set a behavior', ( + tester, + ) async { + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold( + appBar: PreferredSize(preferredSize: Size.fromHeight(kToolbarHeight), child: SizedBox()), + body: SizedBox(), + ), + appStyle: StreamAppStyle.floating, + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.extendBodyBehindAppBar, isTrue); + }); + }); + + testWidgets('applies the given background color', (tester) async { + const backgroundColor = Color(0xFF123456); + + await tester.pumpWidget( + _withStreamTheme( + const StreamScaffold(backgroundColor: backgroundColor, body: SizedBox()), + ), + ); + + final scaffold = tester.widget(find.byType(Scaffold)); + expect(scaffold.backgroundColor, equals(backgroundColor)); + }); +} diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart new file mode 100644 index 00000000..91a987be --- /dev/null +++ b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/core.dart'; + +const _items = [ + StreamBottomNavBarItem( + icon: Icon(Icons.chat_bubble_outline), + selectedIcon: Icon(Icons.chat_bubble), + label: 'Chats', + ), + StreamBottomNavBarItem( + icon: Icon(Icons.bookmark_outline), + selectedIcon: Icon(Icons.bookmark), + label: 'Saved', + ), +]; + +Widget _withStreamTheme(Widget child, {StreamAppStyle appStyle = StreamAppStyle.regular}) { + return MaterialApp( + theme: ThemeData(extensions: [StreamTheme(appStyle: appStyle)]), + home: Scaffold(body: child), + ); +} + +void main() { + testWidgets('renders a label for every item', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + ), + ); + + expect(find.text('Chats'), findsOneWidget); + expect(find.text('Saved'), findsOneWidget); + }); + + testWidgets('invokes onTap with the tapped index', (tester) async { + int? tappedIndex; + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (index) => tappedIndex = index), + ), + ); + + await tester.tap(find.text('Saved')); + + expect(tappedIndex, equals(1)); + }); + + testWidgets('throws when fewer than 2 items are provided', (tester) async { + expect( + () => StreamBottomNavBar(items: [_items.first], currentIndex: 0, onTap: (_) {}), + throwsA(isA()), + ); + }); + + group('regular behavior', () { + testWidgets('renders a docked BottomNavigationBar', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar( + items: _items, + currentIndex: 0, + onTap: (_) {}, + behavior: StreamBottomAppBarBehavior.regular, + ), + ), + ); + + expect(find.byType(BottomNavigationBar), findsOneWidget); + }); + }); + + group('floating behavior', () { + testWidgets('renders a pill container instead of a BottomNavigationBar', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar( + items: _items, + currentIndex: 0, + onTap: (_) {}, + behavior: StreamBottomAppBarBehavior.floating, + ), + ), + ); + + expect(find.byType(BottomNavigationBar), findsNothing); + expect(find.text('Chats'), findsOneWidget); + }); + + testWidgets('invokes onTap with the tapped index', (tester) async { + int? tappedIndex; + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar( + items: _items, + currentIndex: 0, + onTap: (index) => tappedIndex = index, + behavior: StreamBottomAppBarBehavior.floating, + ), + ), + ); + + await tester.tap(find.text('Saved')); + + expect(tappedIndex, equals(1)); + }); + + testWidgets('renders a gradient background', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar( + items: _items, + currentIndex: 0, + onTap: (_) {}, + behavior: StreamBottomAppBarBehavior.floating, + ), + ), + ); + + final decoratedBox = tester.widget( + find + .descendant( + of: find.byType(StreamBottomNavBar), + matching: find.byType(DecoratedBox), + ) + .first, + ); + final decoration = decoratedBox.decoration as BoxDecoration; + expect(decoration.gradient, isA()); + }); + }); + + group('behavior resolution', () { + testWidgets('falls back to StreamBottomAppBarTheme when the instance behavior is unset', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomAppBarTheme( + data: const StreamBottomAppBarThemeData( + style: StreamBottomAppBarStyle(behavior: StreamBottomAppBarBehavior.floating), + ), + child: StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + ), + ), + ); + + expect(find.byType(BottomNavigationBar), findsNothing); + }); + + testWidgets('falls back to the ambient StreamAppStyle when neither instance nor theme set a behavior', ( + tester, + ) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + appStyle: StreamAppStyle.floating, + ), + ); + + expect(find.byType(BottomNavigationBar), findsNothing); + }); + }); +} diff --git a/packages/stream_core_flutter/test/theme/stream_theme_test.dart b/packages/stream_core_flutter/test/theme/stream_theme_test.dart new file mode 100644 index 00000000..fd479e24 --- /dev/null +++ b/packages/stream_core_flutter/test/theme/stream_theme_test.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/core.dart'; + +void main() { + group('StreamTheme.applyPlatform', () { + test('carries non-typography fields through unchanged', () { + final theme = StreamTheme(platform: TargetPlatform.android, appStyle: StreamAppStyle.floating); + + final iosTheme = theme.applyPlatform(TargetPlatform.iOS); + + expect(iosTheme.appStyle, equals(StreamAppStyle.floating)); + expect(iosTheme.brightness, equals(theme.brightness)); + expect(iosTheme.colorScheme, equals(theme.colorScheme)); + }); + + test('regenerates typography and text theme for the given platform', () { + final theme = StreamTheme(platform: TargetPlatform.android); + + final iosTheme = theme.applyPlatform(TargetPlatform.iOS); + + expect(iosTheme.typography.fontSize, equals(StreamFontSize.ios)); + expect(theme.typography.fontSize, equals(StreamFontSize.android)); + }); + }); +} From 9564b9eef698f1a985c5e8026c2ac61d539ef153 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 20 Jul 2026 14:19:42 +0200 Subject: [PATCH 31/35] refactor(ui): rework StreamBottomNavBar with a dedicated theme + factory Restructure StreamBottomNavBar onto the standard design-system shape: Props + StreamBottomNavBar (factory lookup) + DefaultStreamBottomNavBar, with styling resolved via effective-value locals off a token-backed _StreamBottomNavBarStyleDefaults. - Add StreamBottomNavBarTheme / ThemeData / Style (@themeGen), registered on StreamTheme, exposed via context.streamBottomNavBarTheme and core.dart. - Add a dedicated StreamBottomNavBarBehavior enum; resolution order is per-instance behavior -> nav-bar theme -> StreamAppStyle. - Own the docked + floating rendering (animated tiles, tap ripple, tab semantics) instead of delegating the regular case to a Material widget. - Register a bottomNavBar hook on StreamComponentFactory. - Add unit + semantics tests and a golden test (regular/floating x light/dark); update the gallery use-cases to sit in a StreamScaffold-style preview. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../lib/app/gallery_app.directories.g.dart | 19 + .../toolbar/stream_bottom_nav_bar.dart | 226 +++++++ packages/stream_core_flutter/CHANGELOG.md | 2 +- packages/stream_core_flutter/lib/core.dart | 1 + .../toolbar/stream_bottom_nav_bar.dart | 563 +++++++++++++----- .../src/factory/stream_component_factory.dart | 9 + .../stream_component_factory.g.theme.dart | 6 + .../stream_bottom_nav_bar_theme.dart | 207 +++++++ .../stream_bottom_nav_bar_theme.g.theme.dart | 240 ++++++++ .../lib/src/theme/stream_theme.dart | 9 + .../lib/src/theme/stream_theme.g.theme.dart | 9 + .../src/theme/stream_theme_extensions.dart | 4 + .../stream_bottom_nav_bar_golden_test.dart | 144 +++++ .../toolbar/stream_bottom_nav_bar_test.dart | 99 ++- 14 files changed, 1363 insertions(+), 175 deletions(-) create mode 100644 apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart create mode 100644 packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.dart create mode 100644 packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.g.theme.dart create mode 100644 packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_golden_test.dart diff --git a/apps/design_system_gallery/lib/app/gallery_app.directories.g.dart b/apps/design_system_gallery/lib/app/gallery_app.directories.g.dart index b89aa862..8c61b245 100644 --- a/apps/design_system_gallery/lib/app/gallery_app.directories.g.dart +++ b/apps/design_system_gallery/lib/app/gallery_app.directories.g.dart @@ -120,6 +120,8 @@ import 'package:design_system_gallery/components/toolbar/stream_app_bar.dart' as _design_system_gallery_components_toolbar_stream_app_bar; import 'package:design_system_gallery/components/toolbar/stream_bottom_app_bar.dart' as _design_system_gallery_components_toolbar_stream_bottom_app_bar; +import 'package:design_system_gallery/components/toolbar/stream_bottom_nav_bar.dart' + as _design_system_gallery_components_toolbar_stream_bottom_nav_bar; import 'package:design_system_gallery/components/toolbar/stream_sheet_header.dart' as _design_system_gallery_components_toolbar_stream_sheet_header; import 'package:design_system_gallery/primitives/colors.dart' @@ -1232,6 +1234,23 @@ final directories = <_widgetbook.WidgetbookNode>[ ), ], ), + _widgetbook.WidgetbookComponent( + name: 'StreamBottomNavBar', + useCases: [ + _widgetbook.WidgetbookUseCase( + name: 'Playground', + builder: + _design_system_gallery_components_toolbar_stream_bottom_nav_bar + .buildStreamBottomNavBarPlayground, + ), + _widgetbook.WidgetbookUseCase( + name: 'Showcase', + builder: + _design_system_gallery_components_toolbar_stream_bottom_nav_bar + .buildStreamBottomNavBarShowcase, + ), + ], + ), _widgetbook.WidgetbookComponent( name: 'StreamSheetHeader', useCases: [ diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart new file mode 100644 index 00000000..089e7f86 --- /dev/null +++ b/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart @@ -0,0 +1,226 @@ +import 'package:flutter/material.dart'; +import 'package:stream_core_flutter/core.dart'; +import 'package:widgetbook/widgetbook.dart'; +import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; + +// The tabs used across the playground and showcase. Icons switch to their +// filled variant when the item is selected. +List _navItems(BuildContext context) { + final icons = context.streamIcons; + return [ + StreamBottomNavBarItem( + icon: Icon(icons.messageBubble), + selectedIcon: Icon(icons.messageBubbleFill), + label: 'Chats', + ), + StreamBottomNavBarItem( + icon: Icon(icons.thread), + selectedIcon: Icon(icons.threadFill), + label: 'Threads', + ), + StreamBottomNavBarItem( + icon: Icon(icons.mention), + selectedIcon: Icon(icons.mention), + label: 'Mentions', + ), + StreamBottomNavBarItem( + icon: Icon(icons.user), + selectedIcon: Icon(icons.account), + label: 'Profile', + ), + ]; +} + +// ============================================================================= +// Playground +// ============================================================================= + +@widgetbook.UseCase( + name: 'Playground', + type: StreamBottomNavBar, + path: '[Components]/Toolbar', +) +Widget buildStreamBottomNavBarPlayground(BuildContext context) { + return const _PlaygroundDemo(); +} + +class _PlaygroundDemo extends StatefulWidget { + const _PlaygroundDemo(); + + @override + State<_PlaygroundDemo> createState() => _PlaygroundDemoState(); +} + +class _PlaygroundDemoState extends State<_PlaygroundDemo> { + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + final floating = context.knobs.boolean( + label: 'Floating', + description: + 'When true, the bar renders as a rounded pill with a gradient fade ' + 'instead of a docked bar with a top border.', + ); + + final itemCount = context.knobs.int.slider( + label: 'Item count', + initialValue: 4, + min: 2, + max: 4, + description: 'Number of navigation tabs to display (2–4).', + ); + + final items = _navItems(context).take(itemCount).toList(); + // Keep the selected index in range as the item count changes. + final currentIndex = _currentIndex.clamp(0, items.length - 1); + + return Align( + alignment: Alignment.bottomCenter, + child: StreamBottomNavBar( + items: items, + currentIndex: currentIndex, + onTap: (index) => setState(() => _currentIndex = index), + behavior: floating ? StreamBottomNavBarBehavior.floating : StreamBottomNavBarBehavior.regular, + ), + ); + } +} + +// ============================================================================= +// Showcase +// ============================================================================= + +@widgetbook.UseCase( + name: 'Showcase', + type: StreamBottomNavBar, + path: '[Components]/Toolbar', +) +Widget buildStreamBottomNavBarShowcase(BuildContext context) { + return const _ShowcaseDemo(); +} + +class _ShowcaseDemo extends StatefulWidget { + const _ShowcaseDemo(); + + @override + State<_ShowcaseDemo> createState() => _ShowcaseDemoState(); +} + +class _ShowcaseDemoState extends State<_ShowcaseDemo> { + var _regularIndex = 0; + var _floatingIndex = 1; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + final textTheme = context.streamTextTheme; + final spacing = context.streamSpacing; + final items = _navItems(context); + + return DefaultTextStyle( + style: textTheme.bodyDefault.copyWith(color: colorScheme.textPrimary), + child: SingleChildScrollView( + padding: EdgeInsets.all(spacing.lg), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _BarExample( + label: 'Regular — docked with a top border', + bar: StreamBottomNavBar( + items: items, + currentIndex: _regularIndex, + onTap: (index) => setState(() => _regularIndex = index), + behavior: StreamBottomNavBarBehavior.regular, + ), + ), + SizedBox(height: spacing.md), + _BarExample( + label: 'Floating — pill with a gradient fade over content', + bar: _FloatingNavBarPreview( + bar: StreamBottomNavBar( + items: items, + currentIndex: _floatingIndex, + onTap: (index) => setState(() => _floatingIndex = index), + behavior: StreamBottomNavBarBehavior.floating, + ), + ), + ), + ], + ), + ), + ); + } +} + +/// Renders a floating [StreamBottomNavBar] over a simulated content gradient so +/// the fade effect is clearly visible in the Showcase. +class _FloatingNavBarPreview extends StatelessWidget { + const _FloatingNavBarPreview({required this.bar}); + + final Widget bar; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + return SizedBox( + height: kStreamToolbarHeight * 3, + child: Stack( + children: [ + Positioned.fill( + child: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + colorScheme.backgroundApp, + colorScheme.accentPrimary.withAlpha(0x40), + ], + ), + ), + ), + ), + Positioned(bottom: 0, left: 0, right: 0, child: bar), + ], + ), + ); + } +} + +class _BarExample extends StatelessWidget { + const _BarExample({required this.label, required this.bar}); + + final String label; + final Widget bar; + + @override + Widget build(BuildContext context) { + final colorScheme = context.streamColorScheme; + final textTheme = context.streamTextTheme; + final radius = context.streamRadius; + final spacing = context.streamSpacing; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: textTheme.captionEmphasis.copyWith( + color: colorScheme.textSecondary, + ), + ), + SizedBox(height: spacing.xs), + Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: colorScheme.backgroundSurface, + borderRadius: BorderRadius.all(radius.lg), + border: Border.all(color: colorScheme.borderSubtle), + ), + child: bar, + ), + ], + ); + } +} diff --git a/packages/stream_core_flutter/CHANGELOG.md b/packages/stream_core_flutter/CHANGELOG.md index 94fca2ba..5440fe2f 100644 --- a/packages/stream_core_flutter/CHANGELOG.md +++ b/packages/stream_core_flutter/CHANGELOG.md @@ -21,7 +21,7 @@ - Split the public API into `package:stream_core_flutter/core.dart` (shared primitives for any Stream SDK) and `package:stream_core_flutter/chat.dart` (chat-only widgets; re-exports `core.dart`); the convenience barrel `package:stream_core_flutter/stream_core_flutter.dart` is now deprecated. - Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details. -- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Supports the ambient `StreamBottomAppBarBehavior` from `StreamAppStyle`, rendering either a regular bar or a floating pill with a gradient fade-out beneath it. Items announce themselves as accessible buttons via `Semantics`. +- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Renders either a regular docked bar or a floating pill with a gradient fade-out beneath it, resolved from the per-instance `behavior`, the `StreamBottomNavBarTheme`, the `StreamBottomAppBarTheme` (kept in sync with `StreamScaffold`), then `StreamAppStyle`. Follows the standard `Props`/`Default`/`StreamComponentFactory` pattern (`bottomNavBar` builder) and is themeable via `StreamBottomNavBarTheme` / `StreamBottomNavBarStyle` (selected/unselected item colours, icon size, label styles, border, pill radius). Items announce themselves as accessible buttons via `Semantics`. - Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `StreamAppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. - Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. Fixed: a themed `boxShadow` in `StreamAvatarThemeData` no longer bleeds onto avatars where `showShadow` is `false`. - Added `streamFloatingFade` helper — a shared `LinearGradient` factory (alpha stops `0xE8/0xA8/0x40/0x00` with solid-fraction support for safe-area zones) used internally by `StreamAppBar`, `StreamBottomNavBar`, and `StreamMessageComposer` floating fade effects. diff --git a/packages/stream_core_flutter/lib/core.dart b/packages/stream_core_flutter/lib/core.dart index 9ac89779..d9e5e9b1 100644 --- a/packages/stream_core_flutter/lib/core.dart +++ b/packages/stream_core_flutter/lib/core.dart @@ -68,6 +68,7 @@ export 'src/theme/components/stream_avatar_theme.dart'; export 'src/theme/components/stream_badge_count_theme.dart'; export 'src/theme/components/stream_badge_notification_theme.dart'; export 'src/theme/components/stream_bottom_app_bar_theme.dart'; +export 'src/theme/components/stream_bottom_nav_bar_theme.dart'; export 'src/theme/components/stream_button_theme.dart'; export 'src/theme/components/stream_checkbox_theme.dart'; export 'src/theme/components/stream_context_menu_action_theme.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index aae9f6d4..dbaf3b11 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; +import '../../factory/stream_component_factory.dart'; import '../../theme/components/stream_badge_notification_theme.dart'; -import '../../theme/components/stream_bottom_app_bar_theme.dart'; +import '../../theme/components/stream_bottom_nav_bar_theme.dart'; import '../../theme/stream_floating_fade.dart'; import '../../theme/stream_theme_extensions.dart'; @@ -32,31 +33,35 @@ class StreamBottomNavBarItem { /// A bottom navigation bar for Stream surfaces that automatically adapts /// between a floating pill style and a regular docked style based on the -/// ambient [StreamBottomAppBarBehavior] from [StreamBottomAppBarTheme] or -/// [StreamAppStyle]. +/// ambient [StreamBottomNavBarBehavior]. /// /// ## Floating style /// -/// When [StreamBottomAppBarBehavior.floating] is in effect, the bar renders as a +/// When [StreamBottomNavBarBehavior.floating] is in effect, the bar renders as a /// horizontally padded pill with a rounded background, a subtle box shadow, /// and a hairline border. It sits above the body content and is typically /// used with [StreamScaffold]'s floating bottom slot. /// /// ## Regular style /// -/// When [StreamBottomAppBarBehavior.regular] is in effect, the bar renders as a -/// standard docked bottom navigation bar using Flutter's [BottomNavigationBar] -/// with Stream colour and typography tokens. A hairline `borderSubtle` top -/// border separates it from the body. +/// When [StreamBottomNavBarBehavior.regular] is in effect, the bar renders as a +/// standard docked bar with Stream colour and typography tokens. A hairline +/// `borderSubtle` top border separates it from the body. /// /// ## Behaviour resolution /// /// The effective behaviour is resolved in this priority order: /// 1. The per-instance [behavior] parameter on this widget. -/// 2. [StreamBottomAppBarStyle.behavior] from the ambient -/// [StreamBottomAppBarTheme]. +/// 2. [StreamBottomNavBarStyle.behavior] from the ambient +/// [StreamBottomNavBarTheme]. /// 3. The ambient [StreamAppStyle] enum value. /// +/// ## Theming +/// +/// Item colours, icon size, label styles, border, and pill radius are resolved +/// from [StreamBottomNavBarStyle] — set per-instance via `style` or globally +/// via [StreamBottomNavBarTheme], falling back to token-backed defaults. +/// /// {@tool snippet} /// /// Basic usage: @@ -84,18 +89,56 @@ class StreamBottomNavBarItem { /// See also: /// /// * [StreamBottomNavBarItem], which configures each tab. +/// * [StreamBottomNavBarTheme], which styles this widget. /// * [StreamScaffold], which accepts this widget in its `bottom` slot. -/// * [StreamAppStyle], the global app-wide style that acts as fallback. -/// * [StreamBottomAppBarStyle.behavior], the per-theme component override. +/// * [DefaultStreamBottomNavBar], the default visual implementation. class StreamBottomNavBar extends StatelessWidget { /// Creates a Stream bottom navigation bar. - const StreamBottomNavBar({ + StreamBottomNavBar({ super.key, + required List items, + required int currentIndex, + required ValueChanged onTap, + StreamBottomNavBarBehavior? behavior, + StreamBottomNavBarStyle? style, + }) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'), + props = .new( + items: items, + currentIndex: currentIndex, + onTap: onTap, + behavior: behavior, + style: style, + ); + + /// The properties that configure this navigation bar. + final StreamBottomNavBarProps props; + + @override + Widget build(BuildContext context) { + final builder = StreamComponentFactory.of(context).bottomNavBar; + if (builder != null) return builder(context, props); + return DefaultStreamBottomNavBar(props: props); + } +} + +/// Properties for configuring a [StreamBottomNavBar]. +/// +/// This class holds all configuration options for a navigation bar, allowing +/// them to be passed through the [StreamComponentFactory]. +/// +/// See also: +/// +/// * [StreamBottomNavBar], which uses these properties. +/// * [DefaultStreamBottomNavBar], the default implementation. +class StreamBottomNavBarProps { + /// Creates properties for a bottom navigation bar. + const StreamBottomNavBarProps({ required this.items, required this.currentIndex, required this.onTap, this.behavior, - }) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'); + this.style, + }); /// The list of items to display in the navigation bar. /// @@ -108,213 +151,403 @@ class StreamBottomNavBar extends StatelessWidget { /// Called when the user taps a navigation item. final ValueChanged onTap; - /// Overrides the resolved [StreamBottomAppBarBehavior] for this instance only. + /// Overrides the resolved [StreamBottomNavBarBehavior] for this instance only. /// - /// When null the effective behaviour is resolved from - /// [StreamBottomAppBarStyle.behavior] in the ambient - /// [StreamBottomAppBarTheme], falling back to the ambient [StreamAppStyle]. - final StreamBottomAppBarBehavior? behavior; + /// When null the effective behaviour is resolved from the ambient themes; + /// see [StreamBottomNavBar] for the full resolution order. + final StreamBottomNavBarBehavior? behavior; + + /// The visual style applied to this navigation bar. + /// + /// Resolution order per field: this [style] → ambient + /// [StreamBottomNavBarTheme] → token-backed defaults. + final StreamBottomNavBarStyle? style; +} + +/// The default implementation of [StreamBottomNavBar]. +/// +/// Renders the navigation bar with theming from [StreamBottomNavBarTheme] and +/// serves as the default factory implementation in [StreamComponentFactory]. +/// +/// Depending on the resolved [StreamBottomNavBarBehavior], the bar is either a +/// docked bar (a solid surface with a hairline top border) or a floating pill +/// (a rounded surface over a gradient fade). Both share the same tiles, each of +/// which animates its icon and label colour between the unselected and selected +/// states on tap. +/// +/// See also: +/// +/// * [StreamBottomNavBar], the public API widget. +/// * [StreamBottomNavBarProps], which configures this widget. +class DefaultStreamBottomNavBar extends StatefulWidget { + /// Creates a default bottom navigation bar with the given [props]. + const DefaultStreamBottomNavBar({super.key, required this.props}); + + /// The properties that configure this navigation bar. + final StreamBottomNavBarProps props; @override - Widget build(BuildContext context) { - final appStyle = context.streamTheme.appStyle; - final effectiveBehavior = - behavior ?? - context.streamBottomAppBarTheme.style?.behavior ?? - (appStyle.isFloating ? StreamBottomAppBarBehavior.floating : StreamBottomAppBarBehavior.regular); - - if (effectiveBehavior == StreamBottomAppBarBehavior.floating) { - return _FloatingNavBar( - items: items, - currentIndex: currentIndex, - onTap: onTap, - ); + State createState() => _DefaultStreamBottomNavBarState(); +} + +class _DefaultStreamBottomNavBarState extends State with TickerProviderStateMixin { + var _controllers = []; + var _animations = []; + + List get _items => widget.props.items; + + void _resetState() { + for (final controller in _controllers) { + controller.dispose(); + } + for (final animation in _animations) { + animation.dispose(); } - return _RegularNavBar( - items: items, - currentIndex: currentIndex, - onTap: onTap, - ); + _controllers = List.generate(_items.length, (index) { + return AnimationController(duration: kThemeAnimationDuration, vsync: this)..addListener(_rebuild); + }); + _animations = List.generate(_items.length, (index) { + return CurvedAnimation( + parent: _controllers[index], + curve: Curves.fastOutSlowIn, + reverseCurve: Curves.fastOutSlowIn.flipped, + ); + }); + _controllers[widget.props.currentIndex].value = 1; } -} -// --------------------------------------------------------------------------- -// Floating pill nav bar -// --------------------------------------------------------------------------- + @override + void initState() { + super.initState(); + _resetState(); + } -class _FloatingNavBar extends StatelessWidget { - const _FloatingNavBar({ - required this.items, - required this.currentIndex, - required this.onTap, - }); + void _rebuild() { + setState(() { + // Rebuild when any controller ticks so the tiles animate. + }); + } - final List items; - final int currentIndex; - final ValueChanged onTap; + @override + void dispose() { + for (final controller in _controllers) { + controller.dispose(); + } + for (final animation in _animations) { + animation.dispose(); + } + super.dispose(); + } - LinearGradient _buildGradient(BuildContext context, Color backgroundColor) { - final safeAreaBottom = MediaQuery.paddingOf(context).bottom; - // Approximate rendered height: safe area + vertical padding + item height. - const itemHeight = 56.0; - final totalHeight = safeAreaBottom + itemHeight; - final solidFraction = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; + @override + void didUpdateWidget(DefaultStreamBottomNavBar oldWidget) { + super.didUpdateWidget(oldWidget); - return streamFloatingFadeLinearGradient( - color: backgroundColor, - solidFraction: solidFraction, - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - ); + // No animated segue if the number of items changes. + if (_items.length != oldWidget.props.items.length) { + _resetState(); + return; + } + + if (widget.props.currentIndex != oldWidget.props.currentIndex) { + _controllers[oldWidget.props.currentIndex].reverse(); + _controllers[widget.props.currentIndex].forward(); + } + } + + List _createTiles({ + required double iconSize, + required Color selectedItemColor, + required Color unselectedItemColor, + required TextStyle selectedLabelStyle, + required TextStyle unselectedLabelStyle, + }) { + final localizations = MaterialLocalizations.of(context); + + // Selected and unselected tiles share the animated colour tween; only the + // label style is chosen per selection state. + final colorTween = ColorTween(begin: unselectedItemColor, end: selectedItemColor); + + return [ + for (var i = 0; i < _items.length; i++) + _StreamNavTile( + item: _items[i], + animation: _animations[i], + iconSize: iconSize, + selected: i == widget.props.currentIndex, + onTap: () => widget.props.onTap(i), + colorTween: colorTween, + labelStyle: i == widget.props.currentIndex ? selectedLabelStyle : unselectedLabelStyle, + indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: _items.length), + ), + ]; } @override Widget build(BuildContext context) { - final colorScheme = context.streamColorScheme; - final spacing = context.streamSpacing; - final radius = context.streamRadius; - final backgroundColor = colorScheme.backgroundElevation0; + assert(debugCheckHasDirectionality(context), 'A Directionality ancestor is required.'); + assert(debugCheckHasMaterialLocalizations(context), 'MaterialLocalizations are required.'); + assert(debugCheckHasMediaQuery(context), 'A MediaQuery ancestor is required.'); - return DecoratedBox( - decoration: BoxDecoration( - gradient: _buildGradient(context, backgroundColor), - ), - child: SafeArea( - top: false, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: spacing.xl), - child: Container( - decoration: BoxDecoration( - color: colorScheme.backgroundElevation1, - borderRadius: BorderRadius.all(radius.max), - boxShadow: context.streamBoxShadow.elevation1, - ), - foregroundDecoration: BoxDecoration( - borderRadius: BorderRadius.all(radius.max), - border: Border.all(color: colorScheme.borderSubtle), - ), - child: Padding( - padding: EdgeInsets.symmetric(vertical: spacing.xs), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - for (var i = 0; i < items.length; i++) - _FloatingNavBarItem( - item: items[i], - selected: i == currentIndex, - onTap: () => onTap(i), - ), - ], + final appStyle = context.streamTheme.appStyle; + + final style = context.streamBottomNavBarTheme.style?.merge(widget.props.style) ?? widget.props.style; + final defaults = _StreamBottomNavBarStyleDefaults(context); + + var effectiveBehavior = widget.props.behavior ?? style?.behavior; + effectiveBehavior ??= appStyle.isFloating ? .floating : .regular; + + final effectiveBackgroundColor = style?.backgroundColor ?? defaults.backgroundColor; + final effectiveFloatingBackgroundColor = style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor; + final effectiveSelectedItemColor = style?.selectedItemColor ?? defaults.selectedItemColor; + final effectiveUnselectedItemColor = style?.unselectedItemColor ?? defaults.unselectedItemColor; + final effectiveIconSize = style?.iconSize ?? defaults.iconSize; + final effectiveSelectedLabelStyle = style?.selectedLabelStyle ?? defaults.selectedLabelStyle; + final effectiveUnselectedLabelStyle = style?.unselectedLabelStyle ?? defaults.unselectedLabelStyle; + final effectiveBorderColor = style?.borderColor ?? defaults.borderColor; + final effectiveBorderRadius = style?.borderRadius ?? defaults.borderRadius; + + final tiles = StreamBadgeNotificationTheme( + data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), + child: ConstrainedBox( + constraints: const BoxConstraints(minHeight: kBottomNavigationBarHeight), + // A transparent surface above the bar background so each tile can paint + // its tap ripple. + child: Material( + type: MaterialType.transparency, + child: DefaultTextStyle.merge( + overflow: TextOverflow.ellipsis, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _createTiles( + iconSize: effectiveIconSize, + selectedItemColor: effectiveSelectedItemColor, + unselectedItemColor: effectiveUnselectedItemColor, + selectedLabelStyle: effectiveSelectedLabelStyle, + unselectedLabelStyle: effectiveUnselectedLabelStyle, ), ), ), ), ), ); + + return Semantics( + explicitChildNodes: true, + child: switch (effectiveBehavior) { + StreamBottomNavBarBehavior.regular => _RegularChrome( + backgroundColor: effectiveBackgroundColor, + borderColor: effectiveBorderColor, + child: tiles, + ), + StreamBottomNavBarBehavior.floating => _FloatingChrome( + pillColor: effectiveBackgroundColor, + gradientColor: effectiveFloatingBackgroundColor, + borderColor: effectiveBorderColor, + borderRadius: effectiveBorderRadius, + child: tiles, + ), + }, + ); } } -class _FloatingNavBarItem extends StatelessWidget { - const _FloatingNavBarItem({ +// A single navigation tile: an icon above a label, both sharing a colour that +// animates between the unselected and selected states. +class _StreamNavTile extends StatelessWidget { + const _StreamNavTile({ required this.item, + required this.animation, + required this.iconSize, required this.selected, required this.onTap, + required this.colorTween, + required this.labelStyle, + required this.indexLabel, }); final StreamBottomNavBarItem item; + final Animation animation; + final double iconSize; final bool selected; final VoidCallback onTap; + final ColorTween colorTween; + final TextStyle labelStyle; + final String indexLabel; @override Widget build(BuildContext context) { - final textTheme = context.streamTextTheme; - final colorScheme = context.streamColorScheme; final spacing = context.streamSpacing; - final color = selected ? colorScheme.textPrimary : colorScheme.textTertiary; + final color = colorTween.evaluate(animation); - return Semantics( - button: true, + final Widget result = Semantics( selected: selected, - label: item.label, - onTap: onTap, - onTapHint: 'select', - excludeSemantics: true, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: onTap, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: spacing.md, vertical: spacing.xxs), - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: spacing.xxxs, - children: [ - StreamBadgeNotificationTheme( - data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), - child: IconTheme( - data: IconThemeData(color: color, size: 20), - child: selected ? item.selectedIcon : item.icon, - ), - ), - Text( - item.label, - style: textTheme.metadataEmphasis.copyWith(color: color), + button: true, + container: true, + child: Stack( + children: [ + InkResponse( + onTap: onTap, + child: Padding( + padding: EdgeInsets.symmetric(vertical: spacing.xs), + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: spacing.xxxs, + children: [ + Align( + alignment: Alignment.topCenter, + heightFactor: 1, + child: IconTheme( + data: IconThemeData(color: color, size: iconSize), + child: selected ? item.selectedIcon : item.icon, + ), + ), + Align( + alignment: Alignment.bottomCenter, + heightFactor: 1, + child: MediaQuery.withClampedTextScaling( + maxScaleFactor: 1, + child: Text(item.label, style: labelStyle.copyWith(color: color)), + ), + ), + ], ), - ], + ), ), - ), + Semantics(label: indexLabel), + ], ), ); + + return Expanded(child: result); } } -// --------------------------------------------------------------------------- -// Regular docked nav bar -// --------------------------------------------------------------------------- - -class _RegularNavBar extends StatelessWidget { - const _RegularNavBar({ - required this.items, - required this.currentIndex, - required this.onTap, +// Docked chrome: a solid surface with a hairline top border, inset above the +// system bottom inset. +class _RegularChrome extends StatelessWidget { + const _RegularChrome({ + required this.backgroundColor, + required this.borderColor, + required this.child, }); - final List items; - final int currentIndex; - final ValueChanged onTap; + final Color backgroundColor; + final Color borderColor; + final Widget child; @override Widget build(BuildContext context) { - final colorScheme = context.streamColorScheme; - final textTheme = context.streamTextTheme; - return DecoratedBox( decoration: BoxDecoration( - color: colorScheme.backgroundElevation1, - border: Border(top: BorderSide(color: colorScheme.borderSubtle)), + color: backgroundColor, + border: Border(top: BorderSide(color: borderColor)), ), - child: StreamBadgeNotificationTheme( - data: const StreamBadgeNotificationThemeData(size: StreamBadgeNotificationSize.xs), - child: BottomNavigationBar( - elevation: 0, - iconSize: 20, - currentIndex: currentIndex, - type: BottomNavigationBarType.fixed, - selectedItemColor: colorScheme.textPrimary, - unselectedItemColor: colorScheme.textTertiary, - backgroundColor: Colors.transparent, - selectedLabelStyle: textTheme.metadataEmphasis, - unselectedLabelStyle: textTheme.metadataEmphasis, - onTap: onTap, - items: items.map((item) { - return BottomNavigationBarItem( - icon: item.icon, - activeIcon: item.selectedIcon, - label: item.label, - ); - }).toList(), + child: SafeArea(top: false, child: child), + ); + } +} + +// Floating chrome: a rounded pill with a shadow and hairline border, sitting +// above a gradient that fades the bar into the content behind it. +class _FloatingChrome extends StatelessWidget { + const _FloatingChrome({ + required this.pillColor, + required this.gradientColor, + required this.borderColor, + required this.borderRadius, + required this.child, + }); + + final Color pillColor; + final Color gradientColor; + final Color borderColor; + final BorderRadiusGeometry borderRadius; + final Widget child; + + LinearGradient _buildGradient(BuildContext context) { + final safeAreaBottom = MediaQuery.paddingOf(context).bottom; + // Approximate rendered height: safe area + item height. + const itemHeight = kBottomNavigationBarHeight; + final totalHeight = safeAreaBottom + itemHeight; + final solidFraction = totalHeight > 0 ? safeAreaBottom / totalHeight : 0.0; + + return streamFloatingFadeLinearGradient( + color: gradientColor, + solidFraction: solidFraction, + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ); + } + + @override + Widget build(BuildContext context) { + final spacing = context.streamSpacing; + + return DecoratedBox( + decoration: BoxDecoration(gradient: _buildGradient(context)), + child: SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.xl), + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: pillColor, + borderRadius: borderRadius, + boxShadow: context.streamBoxShadow.elevation1, + ), + foregroundDecoration: BoxDecoration( + borderRadius: borderRadius, + border: Border.all(color: borderColor), + ), + child: child, + ), ), ), ); } } + +// Default style values for [StreamBottomNavBar]. +// +// These defaults are used when no explicit value is provided via +// [StreamBottomNavBarStyle]. They are context-aware and use values from +// [StreamColorScheme], [StreamTextTheme], and [StreamRadius]. +class _StreamBottomNavBarStyleDefaults extends StreamBottomNavBarStyle { + _StreamBottomNavBarStyleDefaults(this._context); + + final BuildContext _context; + + late final _colorScheme = _context.streamColorScheme; + late final _textTheme = _context.streamTextTheme; + late final _radius = _context.streamRadius; + + @override + Color get backgroundColor => _colorScheme.backgroundElevation1; + + @override + Color get floatingBackgroundColor => _colorScheme.backgroundElevation0; + + @override + Color get selectedItemColor => _colorScheme.textPrimary; + + @override + Color get unselectedItemColor => _colorScheme.textTertiary; + + @override + double get iconSize => 20; + + @override + TextStyle get selectedLabelStyle => _textTheme.metadataEmphasis; + + @override + TextStyle get unselectedLabelStyle => _textTheme.metadataEmphasis; + + @override + Color get borderColor => _colorScheme.borderSubtle; + + @override + BorderRadiusGeometry get borderRadius => BorderRadius.all(_radius.max); +} diff --git a/packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart b/packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart index 7e10b59c..b332a687 100644 --- a/packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart +++ b/packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart @@ -48,6 +48,7 @@ import '../components/reaction/stream_reactions.dart'; import '../components/snackbar/stream_snackbar.dart'; import '../components/toolbar/stream_app_bar.dart'; import '../components/toolbar/stream_bottom_app_bar.dart'; +import '../components/toolbar/stream_bottom_nav_bar.dart'; import '../components/toolbar/stream_sheet_header.dart'; part 'stream_component_factory.g.theme.dart'; @@ -181,6 +182,7 @@ class StreamComponentBuilders with _$StreamComponentBuilders { StreamComponentBuilder? appBar, StreamComponentBuilder? avatar, StreamComponentBuilder? bottomAppBar, + StreamComponentBuilder? bottomNavBar, StreamComponentBuilder? avatarGroup, StreamComponentBuilder? avatarStack, StreamComponentBuilder? badgeCount, @@ -234,6 +236,7 @@ class StreamComponentBuilders with _$StreamComponentBuilders { appBar: appBar, avatar: avatar, bottomAppBar: bottomAppBar, + bottomNavBar: bottomNavBar, avatarGroup: avatarGroup, avatarStack: avatarStack, badgeCount: badgeCount, @@ -288,6 +291,7 @@ class StreamComponentBuilders with _$StreamComponentBuilders { required this.appBar, required this.avatar, required this.bottomAppBar, + required this.bottomNavBar, required this.avatarGroup, required this.avatarStack, required this.badgeCount, @@ -370,6 +374,11 @@ class StreamComponentBuilders with _$StreamComponentBuilders { /// When null, [StreamBottomAppBar] uses [DefaultStreamBottomAppBar]. final StreamComponentBuilder? bottomAppBar; + /// Custom builder for bottom navigation bar widgets. + /// + /// When null, [StreamBottomNavBar] uses [DefaultStreamBottomNavBar]. + final StreamComponentBuilder? bottomNavBar; + /// Custom builder for avatar group widgets. /// /// When null, [StreamAvatarGroup] uses [DefaultStreamAvatarGroup]. diff --git a/packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart b/packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart index 7c0bfb6f..1f39ed62 100644 --- a/packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart @@ -34,6 +34,7 @@ mixin _$StreamComponentBuilders { appBar: t < 0.5 ? a.appBar : b.appBar, avatar: t < 0.5 ? a.avatar : b.avatar, bottomAppBar: t < 0.5 ? a.bottomAppBar : b.bottomAppBar, + bottomNavBar: t < 0.5 ? a.bottomNavBar : b.bottomNavBar, avatarGroup: t < 0.5 ? a.avatarGroup : b.avatarGroup, avatarStack: t < 0.5 ? a.avatarStack : b.avatarStack, badgeCount: t < 0.5 ? a.badgeCount : b.badgeCount, @@ -103,6 +104,7 @@ mixin _$StreamComponentBuilders { Widget Function(BuildContext, StreamAppBarProps)? appBar, Widget Function(BuildContext, StreamAvatarProps)? avatar, Widget Function(BuildContext, StreamBottomAppBarProps)? bottomAppBar, + Widget Function(BuildContext, StreamBottomNavBarProps)? bottomNavBar, Widget Function(BuildContext, StreamAvatarGroupProps)? avatarGroup, Widget Function(BuildContext, StreamAvatarStackProps)? avatarStack, Widget Function(BuildContext, StreamBadgeCountProps)? badgeCount, @@ -179,6 +181,7 @@ mixin _$StreamComponentBuilders { appBar: appBar ?? _this.appBar, avatar: avatar ?? _this.avatar, bottomAppBar: bottomAppBar ?? _this.bottomAppBar, + bottomNavBar: bottomNavBar ?? _this.bottomNavBar, avatarGroup: avatarGroup ?? _this.avatarGroup, avatarStack: avatarStack ?? _this.avatarStack, badgeCount: badgeCount ?? _this.badgeCount, @@ -255,6 +258,7 @@ mixin _$StreamComponentBuilders { appBar: other.appBar, avatar: other.avatar, bottomAppBar: other.bottomAppBar, + bottomNavBar: other.bottomNavBar, avatarGroup: other.avatarGroup, avatarStack: other.avatarStack, badgeCount: other.badgeCount, @@ -323,6 +327,7 @@ mixin _$StreamComponentBuilders { _other.appBar == _this.appBar && _other.avatar == _this.avatar && _other.bottomAppBar == _this.bottomAppBar && + _other.bottomNavBar == _this.bottomNavBar && _other.avatarGroup == _this.avatarGroup && _other.avatarStack == _this.avatarStack && _other.badgeCount == _this.badgeCount && @@ -386,6 +391,7 @@ mixin _$StreamComponentBuilders { _this.appBar, _this.avatar, _this.bottomAppBar, + _this.bottomNavBar, _this.avatarGroup, _this.avatarStack, _this.badgeCount, diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.dart new file mode 100644 index 00000000..2d0f11a9 --- /dev/null +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.dart @@ -0,0 +1,207 @@ +import 'package:flutter/widgets.dart'; +import 'package:theme_extensions_builder_annotation/theme_extensions_builder_annotation.dart'; + +import '../stream_theme.dart'; + +part 'stream_bottom_nav_bar_theme.g.theme.dart'; + +/// The floating or regular layout behaviour for a [StreamBottomNavBar]. +/// +/// When null on [StreamBottomNavBarStyle], the ambient [StreamAppStyle] is used +/// as a fallback — [StreamAppStyle.floating] maps to [floating] and +/// [StreamAppStyle.regular] maps to [regular]. +/// +/// See also: +/// +/// * [StreamBottomNavBarStyle.behavior], which carries this value. +/// * [StreamAppStyle], the global app-wide style that acts as fallback. +enum StreamBottomNavBarBehavior { + /// The navigation bar sits within the layout flow with a solid background. + regular, + + /// The navigation bar floats above the body as a pill over a gradient fade. + floating, +} + +/// Applies a bottom navigation bar theme to descendant [StreamBottomNavBar] +/// widgets. +/// +/// Wrap a subtree with [StreamBottomNavBarTheme] to override navigation bar +/// styling. Access the merged theme using +/// [BuildContext.streamBottomNavBarTheme]. +/// +/// {@tool snippet} +/// +/// Override the selected item colour for a specific subtree: +/// +/// ```dart +/// StreamBottomNavBarTheme( +/// data: StreamBottomNavBarThemeData( +/// style: StreamBottomNavBarStyle(selectedItemColor: Color(0xFF005FFF)), +/// ), +/// child: StreamBottomNavBar(...), +/// ) +/// ``` +/// {@end-tool} +/// +/// See also: +/// +/// * [StreamBottomNavBarThemeData], which describes the navigation bar theme. +/// * [StreamBottomNavBarStyle], the reusable visual style embedded by the theme. +/// * [StreamBottomNavBar], the widget affected by this theme. +class StreamBottomNavBarTheme extends InheritedTheme { + /// Creates a bottom navigation bar theme that controls descendant bars. + const StreamBottomNavBarTheme({ + super.key, + required this.data, + required super.child, + }); + + /// The bottom navigation bar theme data for descendant widgets. + final StreamBottomNavBarThemeData data; + + /// Returns the [StreamBottomNavBarThemeData] merged from local and global + /// themes. + /// + /// Local values from the nearest [StreamBottomNavBarTheme] ancestor take + /// precedence over global values from [StreamTheme.of]. + static StreamBottomNavBarThemeData of(BuildContext context) { + final localTheme = context.dependOnInheritedWidgetOfExactType(); + return StreamTheme.of(context).bottomNavBarTheme.merge(localTheme?.data); + } + + @override + Widget wrap(BuildContext context, Widget child) { + return StreamBottomNavBarTheme(data: data, child: child); + } + + @override + bool updateShouldNotify(StreamBottomNavBarTheme oldWidget) => data != oldWidget.data; +} + +/// Theme data for customizing [StreamBottomNavBar] widgets. +/// +/// Wraps a [StreamBottomNavBarStyle] so it can be served by +/// [StreamBottomNavBarTheme] and slotted into [StreamTheme] alongside other +/// component theme data classes. +/// +/// {@tool snippet} +/// +/// Customize navigation bar appearance globally via [StreamTheme]: +/// +/// ```dart +/// StreamTheme( +/// bottomNavBarTheme: StreamBottomNavBarThemeData( +/// style: StreamBottomNavBarStyle(iconSize: 24), +/// ), +/// ) +/// ``` +/// {@end-tool} +/// +/// See also: +/// +/// * [StreamBottomNavBarStyle], the reusable visual style embedded here. +/// * [StreamBottomNavBarTheme], for overriding the theme in a widget subtree. +/// * [StreamBottomNavBar], the widget that uses this theme data. +@themeGen +@immutable +class StreamBottomNavBarThemeData with _$StreamBottomNavBarThemeData { + /// Creates bottom navigation bar theme data. + const StreamBottomNavBarThemeData({this.style}); + + /// Visual styling for the bottom navigation bar. + final StreamBottomNavBarStyle? style; + + /// Linearly interpolate between two [StreamBottomNavBarThemeData] objects. + static StreamBottomNavBarThemeData? lerp( + StreamBottomNavBarThemeData? a, + StreamBottomNavBarThemeData? b, + double t, + ) => _$StreamBottomNavBarThemeData.lerp(a, b, t); +} + +/// Visual styling properties for a [StreamBottomNavBar]. +/// +/// Defines the appearance of the navigation bar — the docked/floating +/// behaviour, background colours, per-item selected and unselected colours, +/// icon size, item label styles, and the border and corner radius used by the +/// floating pill. +/// +/// Exposed separately from [StreamBottomNavBarThemeData] so other theme data +/// classes can embed a navigation bar style via a typed field. +/// +/// {@tool snippet} +/// +/// Compose a style and hand it to a navigation bar theme: +/// +/// ```dart +/// StreamBottomNavBarStyle( +/// selectedItemColor: Color(0xFF080707), +/// unselectedItemColor: Color(0xFF7A7A7A), +/// iconSize: 20, +/// ) +/// ``` +/// {@end-tool} +/// +/// See also: +/// +/// * [StreamBottomNavBarThemeData], which wraps this style for theming. +/// * [StreamBottomNavBar], which uses this styling. +@themeGen +@immutable +class StreamBottomNavBarStyle with _$StreamBottomNavBarStyle { + /// Creates a bottom navigation bar style with optional property overrides. + const StreamBottomNavBarStyle({ + this.behavior, + this.backgroundColor, + this.floatingBackgroundColor, + this.selectedItemColor, + this.unselectedItemColor, + this.iconSize, + this.selectedLabelStyle, + this.unselectedLabelStyle, + this.borderColor, + this.borderRadius, + }); + + /// The floating or regular layout behaviour for this navigation bar. + /// + /// When null the value falls back to the ambient [StreamAppStyle]: + /// [StreamAppStyle.floating] → [StreamBottomNavBarBehavior.floating], + /// [StreamAppStyle.regular] → [StreamBottomNavBarBehavior.regular]. + final StreamBottomNavBarBehavior? behavior; + + /// The background colour of the docked bar and of the floating pill. + final Color? backgroundColor; + + /// The base colour of the floating gradient fade behind the pill. + final Color? floatingBackgroundColor; + + /// The colour of the icon and label of the selected item. + final Color? selectedItemColor; + + /// The colour of the icon and label of unselected items. + final Color? unselectedItemColor; + + /// The size of each item's icon. + final double? iconSize; + + /// The text style for the label of the selected item. + final TextStyle? selectedLabelStyle; + + /// The text style for the label of unselected items. + final TextStyle? unselectedLabelStyle; + + /// The colour of the docked bar's top border and the floating pill's border. + final Color? borderColor; + + /// The corner radius of the floating pill. + final BorderRadiusGeometry? borderRadius; + + /// Linearly interpolate between two [StreamBottomNavBarStyle] objects. + static StreamBottomNavBarStyle? lerp( + StreamBottomNavBarStyle? a, + StreamBottomNavBarStyle? b, + double t, + ) => _$StreamBottomNavBarStyle.lerp(a, b, t); +} diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.g.theme.dart new file mode 100644 index 00000000..15c863b8 --- /dev/null +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_bottom_nav_bar_theme.g.theme.dart @@ -0,0 +1,240 @@ +// dart format width=80 +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint, unused_element + +part of 'stream_bottom_nav_bar_theme.dart'; + +// ************************************************************************** +// ThemeGenGenerator +// ************************************************************************** + +mixin _$StreamBottomNavBarThemeData { + bool get canMerge => true; + + static StreamBottomNavBarThemeData? lerp( + StreamBottomNavBarThemeData? a, + StreamBottomNavBarThemeData? b, + double t, + ) { + if (identical(a, b)) { + return a; + } + + if (a == null) { + return t == 1.0 ? b : null; + } + + if (b == null) { + return t == 0.0 ? a : null; + } + + return StreamBottomNavBarThemeData( + style: StreamBottomNavBarStyle.lerp(a.style, b.style, t), + ); + } + + StreamBottomNavBarThemeData copyWith({StreamBottomNavBarStyle? style}) { + final _this = (this as StreamBottomNavBarThemeData); + + return StreamBottomNavBarThemeData(style: style ?? _this.style); + } + + StreamBottomNavBarThemeData merge(StreamBottomNavBarThemeData? other) { + final _this = (this as StreamBottomNavBarThemeData); + + if (other == null || identical(_this, other)) { + return _this; + } + + if (!other.canMerge) { + return other; + } + + return copyWith(style: _this.style?.merge(other.style) ?? other.style); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + if (other.runtimeType != runtimeType) { + return false; + } + + final _this = (this as StreamBottomNavBarThemeData); + final _other = (other as StreamBottomNavBarThemeData); + + return _other.style == _this.style; + } + + @override + int get hashCode { + final _this = (this as StreamBottomNavBarThemeData); + + return Object.hash(runtimeType, _this.style); + } +} + +mixin _$StreamBottomNavBarStyle { + bool get canMerge => true; + + static StreamBottomNavBarStyle? lerp( + StreamBottomNavBarStyle? a, + StreamBottomNavBarStyle? b, + double t, + ) { + if (identical(a, b)) { + return a; + } + + if (a == null) { + return t == 1.0 ? b : null; + } + + if (b == null) { + return t == 0.0 ? a : null; + } + + return StreamBottomNavBarStyle( + behavior: t < 0.5 ? a.behavior : b.behavior, + backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), + floatingBackgroundColor: Color.lerp( + a.floatingBackgroundColor, + b.floatingBackgroundColor, + t, + ), + selectedItemColor: Color.lerp( + a.selectedItemColor, + b.selectedItemColor, + t, + ), + unselectedItemColor: Color.lerp( + a.unselectedItemColor, + b.unselectedItemColor, + t, + ), + iconSize: lerpDouble$(a.iconSize, b.iconSize, t), + selectedLabelStyle: TextStyle.lerp( + a.selectedLabelStyle, + b.selectedLabelStyle, + t, + ), + unselectedLabelStyle: TextStyle.lerp( + a.unselectedLabelStyle, + b.unselectedLabelStyle, + t, + ), + borderColor: Color.lerp(a.borderColor, b.borderColor, t), + borderRadius: BorderRadiusGeometry.lerp( + a.borderRadius, + b.borderRadius, + t, + ), + ); + } + + StreamBottomNavBarStyle copyWith({ + StreamBottomNavBarBehavior? behavior, + Color? backgroundColor, + Color? floatingBackgroundColor, + Color? selectedItemColor, + Color? unselectedItemColor, + double? iconSize, + TextStyle? selectedLabelStyle, + TextStyle? unselectedLabelStyle, + Color? borderColor, + BorderRadiusGeometry? borderRadius, + }) { + final _this = (this as StreamBottomNavBarStyle); + + return StreamBottomNavBarStyle( + behavior: behavior ?? _this.behavior, + backgroundColor: backgroundColor ?? _this.backgroundColor, + floatingBackgroundColor: + floatingBackgroundColor ?? _this.floatingBackgroundColor, + selectedItemColor: selectedItemColor ?? _this.selectedItemColor, + unselectedItemColor: unselectedItemColor ?? _this.unselectedItemColor, + iconSize: iconSize ?? _this.iconSize, + selectedLabelStyle: selectedLabelStyle ?? _this.selectedLabelStyle, + unselectedLabelStyle: unselectedLabelStyle ?? _this.unselectedLabelStyle, + borderColor: borderColor ?? _this.borderColor, + borderRadius: borderRadius ?? _this.borderRadius, + ); + } + + StreamBottomNavBarStyle merge(StreamBottomNavBarStyle? other) { + final _this = (this as StreamBottomNavBarStyle); + + if (other == null || identical(_this, other)) { + return _this; + } + + if (!other.canMerge) { + return other; + } + + return copyWith( + behavior: other.behavior, + backgroundColor: other.backgroundColor, + floatingBackgroundColor: other.floatingBackgroundColor, + selectedItemColor: other.selectedItemColor, + unselectedItemColor: other.unselectedItemColor, + iconSize: other.iconSize, + selectedLabelStyle: + _this.selectedLabelStyle?.merge(other.selectedLabelStyle) ?? + other.selectedLabelStyle, + unselectedLabelStyle: + _this.unselectedLabelStyle?.merge(other.unselectedLabelStyle) ?? + other.unselectedLabelStyle, + borderColor: other.borderColor, + borderRadius: other.borderRadius, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + if (other.runtimeType != runtimeType) { + return false; + } + + final _this = (this as StreamBottomNavBarStyle); + final _other = (other as StreamBottomNavBarStyle); + + return _other.behavior == _this.behavior && + _other.backgroundColor == _this.backgroundColor && + _other.floatingBackgroundColor == _this.floatingBackgroundColor && + _other.selectedItemColor == _this.selectedItemColor && + _other.unselectedItemColor == _this.unselectedItemColor && + _other.iconSize == _this.iconSize && + _other.selectedLabelStyle == _this.selectedLabelStyle && + _other.unselectedLabelStyle == _this.unselectedLabelStyle && + _other.borderColor == _this.borderColor && + _other.borderRadius == _this.borderRadius; + } + + @override + int get hashCode { + final _this = (this as StreamBottomNavBarStyle); + + return Object.hash( + runtimeType, + _this.behavior, + _this.backgroundColor, + _this.floatingBackgroundColor, + _this.selectedItemColor, + _this.unselectedItemColor, + _this.iconSize, + _this.selectedLabelStyle, + _this.unselectedLabelStyle, + _this.borderColor, + _this.borderRadius, + ); + } +} diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart index cf44a0f3..e6518dc9 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart @@ -10,6 +10,7 @@ import 'components/stream_avatar_theme.dart'; import 'components/stream_badge_count_theme.dart'; import 'components/stream_badge_notification_theme.dart'; import 'components/stream_bottom_app_bar_theme.dart'; +import 'components/stream_bottom_nav_bar_theme.dart'; import 'components/stream_button_theme.dart'; import 'components/stream_checkbox_theme.dart'; import 'components/stream_command_chip_theme.dart'; @@ -122,6 +123,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { StreamBadgeCountThemeData? badgeCountTheme, StreamBadgeNotificationThemeData? badgeNotificationTheme, StreamBottomAppBarThemeData? bottomAppBarTheme, + StreamBottomNavBarThemeData? bottomNavBarTheme, StreamButtonThemeData? buttonTheme, StreamCheckboxThemeData? checkboxTheme, StreamCommandChipThemeData? commandChipTheme, @@ -175,6 +177,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { badgeCountTheme ??= const StreamBadgeCountThemeData(); badgeNotificationTheme ??= const StreamBadgeNotificationThemeData(); bottomAppBarTheme ??= const StreamBottomAppBarThemeData(); + bottomNavBarTheme ??= const StreamBottomNavBarThemeData(); buttonTheme ??= const StreamButtonThemeData(); checkboxTheme ??= const StreamCheckboxThemeData(); commandChipTheme ??= const StreamCommandChipThemeData(); @@ -222,6 +225,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { badgeCountTheme: badgeCountTheme, badgeNotificationTheme: badgeNotificationTheme, bottomAppBarTheme: bottomAppBarTheme, + bottomNavBarTheme: bottomNavBarTheme, buttonTheme: buttonTheme, checkboxTheme: checkboxTheme, commandChipTheme: commandChipTheme, @@ -283,6 +287,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { required this.badgeCountTheme, required this.badgeNotificationTheme, required this.bottomAppBarTheme, + required this.bottomNavBarTheme, required this.buttonTheme, required this.checkboxTheme, required this.commandChipTheme, @@ -394,6 +399,9 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { /// The bottom app bar theme for this theme. final StreamBottomAppBarThemeData bottomAppBarTheme; + /// The bottom navigation bar theme for this theme. + final StreamBottomNavBarThemeData bottomNavBarTheme; + /// The button theme for this theme. final StreamButtonThemeData buttonTheme; @@ -521,6 +529,7 @@ class StreamTheme extends ThemeExtension with _$StreamTheme { badgeCountTheme: badgeCountTheme, badgeNotificationTheme: badgeNotificationTheme, bottomAppBarTheme: bottomAppBarTheme, + bottomNavBarTheme: bottomNavBarTheme, buttonTheme: buttonTheme, checkboxTheme: checkboxTheme, commandChipTheme: commandChipTheme, diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart index f906ee3e..0f341c3f 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart @@ -27,6 +27,7 @@ mixin _$StreamTheme on ThemeExtension { StreamBadgeCountThemeData? badgeCountTheme, StreamBadgeNotificationThemeData? badgeNotificationTheme, StreamBottomAppBarThemeData? bottomAppBarTheme, + StreamBottomNavBarThemeData? bottomNavBarTheme, StreamButtonThemeData? buttonTheme, StreamCheckboxThemeData? checkboxTheme, StreamCommandChipThemeData? commandChipTheme, @@ -83,6 +84,7 @@ mixin _$StreamTheme on ThemeExtension { badgeNotificationTheme: badgeNotificationTheme ?? _this.badgeNotificationTheme, bottomAppBarTheme: bottomAppBarTheme ?? _this.bottomAppBarTheme, + bottomNavBarTheme: bottomNavBarTheme ?? _this.bottomNavBarTheme, buttonTheme: buttonTheme ?? _this.buttonTheme, checkboxTheme: checkboxTheme ?? _this.checkboxTheme, commandChipTheme: commandChipTheme ?? _this.commandChipTheme, @@ -185,6 +187,11 @@ mixin _$StreamTheme on ThemeExtension { other.bottomAppBarTheme, t, )!, + bottomNavBarTheme: StreamBottomNavBarThemeData.lerp( + _this.bottomNavBarTheme, + other.bottomNavBarTheme, + t, + )!, buttonTheme: StreamButtonThemeData.lerp( _this.buttonTheme, other.buttonTheme, @@ -373,6 +380,7 @@ mixin _$StreamTheme on ThemeExtension { _other.badgeCountTheme == _this.badgeCountTheme && _other.badgeNotificationTheme == _this.badgeNotificationTheme && _other.bottomAppBarTheme == _this.bottomAppBarTheme && + _other.bottomNavBarTheme == _this.bottomNavBarTheme && _other.buttonTheme == _this.buttonTheme && _other.checkboxTheme == _this.checkboxTheme && _other.commandChipTheme == _this.commandChipTheme && @@ -433,6 +441,7 @@ mixin _$StreamTheme on ThemeExtension { _this.badgeCountTheme, _this.badgeNotificationTheme, _this.bottomAppBarTheme, + _this.bottomNavBarTheme, _this.buttonTheme, _this.checkboxTheme, _this.commandChipTheme, diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart index 67de4b23..b3025fd1 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart @@ -6,6 +6,7 @@ import 'components/stream_avatar_theme.dart'; import 'components/stream_badge_count_theme.dart'; import 'components/stream_badge_notification_theme.dart'; import 'components/stream_bottom_app_bar_theme.dart'; +import 'components/stream_bottom_nav_bar_theme.dart'; import 'components/stream_button_theme.dart'; import 'components/stream_checkbox_theme.dart'; import 'components/stream_command_chip_theme.dart'; @@ -108,6 +109,9 @@ extension StreamThemeExtension on BuildContext { /// Returns the [StreamBottomAppBarThemeData] from the nearest ancestor. StreamBottomAppBarThemeData get streamBottomAppBarTheme => StreamBottomAppBarTheme.of(this); + /// Returns the [StreamBottomNavBarThemeData] from the nearest ancestor. + StreamBottomNavBarThemeData get streamBottomNavBarTheme => StreamBottomNavBarTheme.of(this); + /// Returns the [StreamButtonThemeData] from the nearest ancestor. StreamButtonThemeData get streamButtonTheme => StreamButtonTheme.of(this); diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_golden_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_golden_test.dart new file mode 100644 index 00000000..6c831bae --- /dev/null +++ b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_golden_test.dart @@ -0,0 +1,144 @@ +import 'package:alchemist/alchemist.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_core_flutter/core.dart'; + +const _kBarWidth = 390.0; + +const _items = [ + StreamBottomNavBarItem( + icon: Icon(Icons.chat_bubble_outline), + selectedIcon: Icon(Icons.chat_bubble), + label: 'Chats', + ), + StreamBottomNavBarItem( + icon: Icon(Icons.alternate_email), + selectedIcon: Icon(Icons.alternate_email), + label: 'Mentions', + ), + StreamBottomNavBarItem( + icon: Icon(Icons.person_outline), + selectedIcon: Icon(Icons.person), + label: 'Profile', + ), +]; + +void main() { + group('StreamBottomNavBar Golden Tests', () { + goldenTest( + 'renders regular variants', + fileName: 'stream_bottom_nav_bar_regular', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'light', + child: _buildNavBarInTheme(_regularBar()), + ), + GoldenTestScenario( + name: 'dark', + child: _buildNavBarInTheme(_regularBar(), brightness: Brightness.dark), + ), + ], + ), + ); + + goldenTest( + 'renders floating variants', + fileName: 'stream_bottom_nav_bar_floating', + builder: () => GoldenTestGroup( + scenarioConstraints: const BoxConstraints(maxWidth: _kBarWidth), + children: [ + GoldenTestScenario( + name: 'light', + child: _buildFloatingNavBarInTheme(_floatingBar()), + ), + GoldenTestScenario( + name: 'dark', + child: _buildFloatingNavBarInTheme(_floatingBar(), brightness: Brightness.dark), + ), + ], + ), + ); + }); +} + +Widget _regularBar() { + return StreamBottomNavBar( + items: _items, + currentIndex: 0, + onTap: (_) {}, + behavior: StreamBottomNavBarBehavior.regular, + ); +} + +Widget _floatingBar() { + return StreamBottomNavBar( + items: _items, + currentIndex: 1, + onTap: (_) {}, + behavior: StreamBottomNavBarBehavior.floating, + ); +} + +Widget _buildNavBarInTheme( + Widget navBar, { + Brightness brightness = Brightness.light, +}) { + final streamTheme = StreamTheme(brightness: brightness); + return Theme( + data: ThemeData( + brightness: brightness, + extensions: [streamTheme], + ), + child: Builder( + builder: (context) => Material( + color: StreamTheme.of(context).colorScheme.backgroundApp, + child: SizedBox(width: _kBarWidth, child: navBar), + ), + ), + ); +} + +/// Wraps a floating [StreamBottomNavBar] over a content gradient so the fade is +/// clearly visible in the snapshot. +Widget _buildFloatingNavBarInTheme( + Widget navBar, { + Brightness brightness = Brightness.light, +}) { + final streamTheme = StreamTheme(brightness: brightness); + return Theme( + data: ThemeData( + brightness: brightness, + extensions: [streamTheme], + ), + child: Builder( + builder: (context) { + final colorScheme = StreamTheme.of(context).colorScheme; + return SizedBox( + width: _kBarWidth, + height: kStreamToolbarHeight * 3, + child: Stack( + children: [ + Positioned.fill( + child: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + colorScheme.backgroundApp, + colorScheme.accentPrimary.withAlpha(0x40), + ], + ), + ), + ), + ), + Positioned(bottom: 0, left: 0, right: 0, child: navBar), + ], + ), + ); + }, + ), + ); +} diff --git a/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart index 91a987be..504e303b 100644 --- a/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart +++ b/packages/stream_core_flutter/test/components/toolbar/stream_bottom_nav_bar_test.dart @@ -22,6 +22,15 @@ Widget _withStreamTheme(Widget child, {StreamAppStyle appStyle = StreamAppStyle. ); } +/// Whether the bar resolved to the floating style, detected by the presence of +/// the gradient fade (only the floating chrome paints one). +bool _isFloating(WidgetTester tester) { + final boxes = tester.widgetList( + find.descendant(of: find.byType(StreamBottomNavBar), matching: find.byType(DecoratedBox)), + ); + return boxes.any((box) => (box.decoration as BoxDecoration).gradient != null); +} + void main() { testWidgets('renders a label for every item', (tester) async { await tester.pumpWidget( @@ -55,19 +64,30 @@ void main() { }); group('regular behavior', () { - testWidgets('renders a docked BottomNavigationBar', (tester) async { + testWidgets('renders a docked bar with a top border and no gradient', (tester) async { await tester.pumpWidget( _withStreamTheme( StreamBottomNavBar( items: _items, currentIndex: 0, onTap: (_) {}, - behavior: StreamBottomAppBarBehavior.regular, + behavior: StreamBottomNavBarBehavior.regular, ), ), ); - expect(find.byType(BottomNavigationBar), findsOneWidget); + final decoratedBox = tester.widget( + find + .descendant( + of: find.byType(StreamBottomNavBar), + matching: find.byType(DecoratedBox), + ) + .first, + ); + final decoration = decoratedBox.decoration as BoxDecoration; + expect(decoration.gradient, isNull); + expect(decoration.border, isNotNull); + expect(find.text('Chats'), findsOneWidget); }); }); @@ -79,7 +99,7 @@ void main() { items: _items, currentIndex: 0, onTap: (_) {}, - behavior: StreamBottomAppBarBehavior.floating, + behavior: StreamBottomNavBarBehavior.floating, ), ), ); @@ -96,7 +116,7 @@ void main() { items: _items, currentIndex: 0, onTap: (index) => tappedIndex = index, - behavior: StreamBottomAppBarBehavior.floating, + behavior: StreamBottomNavBarBehavior.floating, ), ), ); @@ -113,7 +133,7 @@ void main() { items: _items, currentIndex: 0, onTap: (_) {}, - behavior: StreamBottomAppBarBehavior.floating, + behavior: StreamBottomNavBarBehavior.floating, ), ), ); @@ -132,7 +152,22 @@ void main() { }); group('behavior resolution', () { - testWidgets('falls back to StreamBottomAppBarTheme when the instance behavior is unset', (tester) async { + testWidgets('resolves behavior from StreamBottomNavBarTheme', (tester) async { + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBarTheme( + data: const StreamBottomNavBarThemeData( + style: StreamBottomNavBarStyle(behavior: StreamBottomNavBarBehavior.floating), + ), + child: StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + ), + ), + ); + + expect(_isFloating(tester), isTrue); + }); + + testWidgets('is independent of StreamBottomAppBarTheme', (tester) async { await tester.pumpWidget( _withStreamTheme( StreamBottomAppBarTheme( @@ -144,7 +179,9 @@ void main() { ), ); - expect(find.byType(BottomNavigationBar), findsNothing); + // The nav bar resolves only from its own theme and StreamAppStyle, so a + // floating StreamBottomAppBarTheme has no effect (defaults to regular). + expect(_isFloating(tester), isFalse); }); testWidgets('falls back to the ambient StreamAppStyle when neither instance nor theme set a behavior', ( @@ -157,7 +194,51 @@ void main() { ), ); - expect(find.byType(BottomNavigationBar), findsNothing); + expect(_isFloating(tester), isTrue); + }); + }); + + group('StreamBottomNavBarTheme styling', () { + testWidgets('applies the selected item color to the selected tile', (tester) async { + const selectedColor = Color(0xFF123456); + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBarTheme( + data: const StreamBottomNavBarThemeData( + style: StreamBottomNavBarStyle(selectedItemColor: selectedColor), + ), + child: StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + ), + ), + ); + + final selectedLabel = tester.widget(find.text('Chats')); + expect(selectedLabel.style?.color, equals(selectedColor)); + }); + }); + + group('semantics', () { + testWidgets('marks each item as a button, flags the selected one, and labels tabs by index', (tester) async { + final handle = tester.ensureSemantics(); + await tester.pumpWidget( + _withStreamTheme( + StreamBottomNavBar(items: _items, currentIndex: 0, onTap: (_) {}), + ), + ); + + // Each tab announces its position (localized "Tab N of M"), merged onto + // the tile alongside its label (e.g. "Chats\nTab 1 of 2"). + final selected = find.semantics.byPredicate((n) => n.label.contains('Tab 1 of 2')); + final unselected = find.semantics.byPredicate((n) => n.label.contains('Tab 2 of 2')); + + expect(selected, findsOneWidget); + expect(unselected, findsOneWidget); + + // The selected item is a selected button; the other an unselected button. + expect(selected.evaluate().single, isSemantics(isButton: true, isSelected: true)); + expect(unselected.evaluate().single, isSemantics(isButton: true, isSelected: false)); + + handle.dispose(); }); }); } From ad88b65f9b0fdf132751ddb37ccd912b343e267a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 20 Jul 2026 14:20:00 +0200 Subject: [PATCH 32/35] fix(gallery): guard ScopedSemanticsDebugger against a null pipeline owner Toggling the semantics debugger on threw a null-check error: the pipeline owner was only wired in didChangeDependencies (gated on enabled), which isn't re-run on a plain prop toggle, so build hit `_pipelineOwner!` while still null. Sync the owner when enabling and fall back to the child when it is unset. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../widgets/scoped_semantics_debugger.dart | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/design_system_gallery/lib/widgets/scoped_semantics_debugger.dart b/apps/design_system_gallery/lib/widgets/scoped_semantics_debugger.dart index 4e86ab52..0b97528a 100644 --- a/apps/design_system_gallery/lib/widgets/scoped_semantics_debugger.dart +++ b/apps/design_system_gallery/lib/widgets/scoped_semantics_debugger.dart @@ -48,21 +48,29 @@ class _ScopedSemanticsDebuggerState extends State with @override void didUpdateWidget(ScopedSemanticsDebugger oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.enabled != oldWidget.enabled) { - widget.enabled ? _attach() : _detach(); + if (widget.enabled == oldWidget.enabled) return; + if (widget.enabled) { + _attach(); + // didChangeDependencies isn't re-run on a plain prop toggle, so wire the + // owner here — otherwise build sees a null owner right after enabling. + _syncOwner(); + } else { + _detach(); } } @override void didChangeDependencies() { super.didChangeDependencies(); - if (!widget.enabled) return; + if (widget.enabled) _syncOwner(); + } + + void _syncOwner() { final newOwner = View.pipelineOwnerOf(context); - if (newOwner != _pipelineOwner) { - _pipelineOwner?.semanticsOwner?.removeListener(_update); - newOwner.semanticsOwner?.addListener(_update); - _pipelineOwner = newOwner; - } + if (newOwner == _pipelineOwner) return; + _pipelineOwner?.semanticsOwner?.removeListener(_update); + newOwner.semanticsOwner?.addListener(_update); + _pipelineOwner = newOwner; } @override @@ -100,11 +108,12 @@ class _ScopedSemanticsDebuggerState extends State with @override Widget build(BuildContext context) { - if (!widget.enabled) return widget.child; + final owner = _pipelineOwner; + if (!widget.enabled || owner == null) return widget.child; return CustomPaint( key: _paintKey, foregroundPainter: _ScopedSemanticsDebuggerPainter( - owner: _pipelineOwner!, + owner: owner, generation: _generation, devicePixelRatio: View.of(context).devicePixelRatio, dimColor: context.streamColorScheme.backgroundApp, From 111b96a3c6dffdd9ba995796f95f33ccd28ad6c1 Mon Sep 17 00:00:00 2001 From: xsahil03x <25670178+xsahil03x@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:21:41 +0000 Subject: [PATCH 33/35] chore: Update Goldens --- .../ci/stream_bottom_nav_bar_floating.png | Bin 0 -> 11530 bytes .../ci/stream_bottom_nav_bar_regular.png | Bin 0 -> 858 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_floating.png create mode 100644 packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_regular.png diff --git a/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_floating.png b/packages/stream_core_flutter/test/components/toolbar/goldens/ci/stream_bottom_nav_bar_floating.png new file mode 100644 index 0000000000000000000000000000000000000000..cafa4f4c11f93b9a630f2f4e84c9437c8990efaa GIT binary patch literal 11530 zcmdUV`6E>S7x!(WB>IGqt+Iu(WXqm}EK%0%$!;u#vCm8;e3d2pI;LXmOZI9)C~L?v zgzUR9#yYYL&z-C1FL-`>{E+FI`+lGEIEWJ>#nMie+Cg9^pS7S zYP>!dH~-9O#hd^7(9H%$TPAw8(=;2}A5To)zq59Fmd~i*n(%`&Ld-uUjjoz<#yxL1 zd4c}b;}bMzM%H=D-@2P6MY+3mG$*~~FZDI;b+s9uM|7c`w&ixRa87}aqQrX1kfHD-e{%ODONU z6Q+$d$j>yLx2*o_W`CU50Ub6|zHG1ipw(ZII|k#&V@Ak!3v&^VV=JLv*ltq5PSY~I z$`|vw>cXILlRKtmdVVzBcQA*d7U=%bG(uM(zHMw)C8)z@p}y{5Oa9sJL#-u}dHa?4 zHv4jvoHmcGczYoexP3gLv&(_^f5B$*Rxew>oXfq86YGYyMDfT8n#r-Ba}C^>9b5x1 zsgSH)oNOZ_U%EX|1#LCLz!Dw_+C{pNABVs_78Vy2K_3;72Z*}H$GRy*E9s&0S1(g{ z%a!vIRbk;J-tE-}jk33?Xft8!CtWX3q_yK46ob6^t|>$0?-d+dFU)!Cy-M9{du+BQ z^)k+bM)JO>l5`V`B;?_k6Unw!{y&ABDR8T?vl#M!8V0-EH1i2u#j<%h47%J|jtw&NGG)&{okweYnGp9+jiF-)aa!9TcJ6d$dh;^f4=9(4KTmwb8K(#?>%|*qwR~Eqlzamh$^Du~px?<+vR;|UG zK6RY#k(PDITjd1my%-pY&#srXCbe>il-RzGH7K0%J!~Q#RH`ZH&!cUWYj@MEGf{K;o zB^K{{H7@eF5J9Rp<|ZW)y!-FY_E36eMeHlBy$eS+Z@f?o)Q)4eS4Obp(eXG@gG!3% z9&37gU;JUdkuaW==6CVtP1R~$w5L9uMp7v?cBF9B!d;kiLEGoexyJr@=$`QUX)ez` zo`ZvQA4h}|F0)vElf+B)&~qsGV9lf&I0pcA-Yp7aIfonJ^`(-@0~I16w3DqMLd#Ck zZpzPF1=H?Ayz?G=m^~85mvz}HCkgtqOLPW@&-t#|>4>7aAoC*w{IoS01>Ux0v?0~0 zH>r5r@9EHo+|W@QqJskMpSzi}nUFoj>k;B~IZOm%vfJE4H=;#Aak5ihU8y1HkL{!2zTQs%^y%&ZLsBk?W#W<_Ty(TT%0JBZ z;{{d7?24W5lcPQ?!}J>e1cXotFJqxF2W&3}v6V}l07+$#zmpIrp(@`j z?ijOl6yBH%vccNTzg*axoi~~Jp><2UlUVI_Q*P*QmqyM2M-XmI()zA*gDg~>&m0+l zZ*efy?c;$!b176e?L+!MfXU~p?6NwQLFh9AEqNB0)#qo*uR)K~` zS->MEgkTKO4HT{6lZ=C?6C>+~bnK8jCy0P)vOWlcv`B;DoG=EacZfBHX&Q6#@*Kuunep5E+Tljqm;11eJm%6u~i6`q)O7-@=_f?w?}ksQ^iC4+XL5PFk+SE<@pb({0KXMj8=` zF@YjkC|iRF?$Zh_-0?7h>Q=JK&Wn-FvF$%OXYb3VSS|%YiJuZa)-=Hv3;HrNuDHN= zyp6eQ_FsXjU7K^~8NIf79snjJx5u{hMxX5|z~4KpZ_z?3W!=X@W18YJTnMQ<2ZZp? ziF5Cu(95J-D3`BfK50Ay@@BG+CpdQ{n1q9uaXFe=%Czu77J-#C;fAcer>|kA=D*a` z(cUge+dt@uInoTU6cMlUsZq<`w4fS# zFe@0%Gr+4Eljp#z6)KCE!=DVYp=Q(mpTG@4KO3*O-44d-Z`2F>d)>$dt1kpZ4Z$Fn z&tdTXq&0*{GB2UGwy^rJxjR<)DCm1Bx7$l{_Y&x-WLN5(>-4j_?)zVI=UoUk%>L(~ zF)U-sqe*FOXIFEQI1&cDYsvTTHBBn8Tr8HV3An9 zRQ{Ukm&*R<7DmF~td@RX2Q7WCKpH3^+vXTozP^RCBr{&uXrOK%yjQ>1irbpRjpypr zx>jF^O>1aBN&PCK<3*KTm)1azq23QgNK{qEl?6v}1)G&eK|*(uMxTudaowhek}G*< z14Z#b%&77F3bZ8Hbj+tVLjt-(j;+#;vFI#>0#_KH$FbW2 zP?>I2`P<`1u;Z!IAv{BfS5d{os1)|sN`*X}zEL+_?%He#1T=t%>Ep<5x!hngb9RVqH&K&zq@I?;-H_pXNe1ZJ-1kp$G-s$uqWrgYsIsQD zkQ4H?bMae)z1htd>^_%<+$q+lsNb;m->@Lb6Ply1Lq*0|d4Fwt!Bctniu-Q|uvflk z@Rv(P-ao9tJ`vox4LSEFmwOJyA9R4Q+L7t1aPF)zLoh1z2>GX=M; z^WJ1S)Zaen)U2E|q3u=|u?Rnc|1(P4AV*S%S~Yko40k&kIFvVJm38z&c*&7a+o~Tt zv;M|lz~vh8?os=syaPh_K8u{daCNsf{NH!%t(J<`|7#wDYR3i%O@j{gUNkY8r`w*F zvv~*Q$Dh5{&#JUg>)2grDBs5?nG$d*)Bn;JYIOn|h*+YSX0G2n@0p{l*-Lr1O7qK2 z40Z*^2Qp3(iL4D6#bA7Y#D+>K_Cm(1?DPbA4$do6p1G&N=uGe1o_k5fv~KpBqoKBp z0#^uxu#?u%&WPho6b1^dMEc?8fZ+;2Z%GYLFtEM`E`h-8ysCZ)J1hGy*&d~9BrEMx z@3yb6$UgYltLoo$?H^NYD1C-q*lyWur5_Uk;mQ#Gns^R3iGdRpn109AjC}_7)PviQ zB?q&s76*&>W#<{ySrwR)N0kz&d8#sqBt-DaZ+{npho}psn|T=onjfXv&$;ArubTvU zu;Tma?GuBxcDj+;7L)Kj3KqO{?8^Qe&!@$?%@<+J$@ zjtc5vt_oIC$7AN)JE)Xaq+t%Tn7WkO+~V0cd8qDUyivQ}B)r--N@JwQTde*C6)5Yu z%c!Q@j<9ncP_)Lx#NvrA@FDJ_T7m9F{cURL%e=~?6*<5OX>F~_#%Beezc1?XzMG0d z^_HJ7)MXB459mUwhI9?dIo;4eF(yVzAYbUpmelQXsMW}XbS_a=Wsf!n=SF`exwhv< z_ff;LLBxC_)dv1;=yp-~Vp}=_Rbkt6^#?&HvLj3B=Z2fF{?*A5*)A?T_N){BoN0D2 zW1-a7TqqT-9X2FArbmPxwlo-r|mda>}(o6EnN$Ge?@Lx>iZ= z@^_Q|h^yG5WbqL8994$ix|38581vuoM3E$tWB7XCgv3IzrL@nl9Exx$1f#w*J}yrc z$nvSbKxI_z&ler~Ev?)LQO78#73{9*mJoOwM*bK_t)YW%$X%4u+%9i~vM7ha%zsB3 zw88l2y(Xi|JM=m$JzB?O2` z-4`=Yr-Q&kW4|Vg54DFtlW5D({&x$8-@`_1LJAXW$SSyE9lH@DqDwv?ERJC}PcOeoHf1;rP6|2f{^)GjFL7 z)^pC}KKZ?T?kN8i6tG#R1+lsO5cLUe$o+GgXmA@ocjP2Oerv&2`l5B^xD9xG!+HMd z{5tIz#G|15sGFhN;@KmKkrI%MNTs882%2cRT!(CEla{aWzj|n8bbzPwNep=v&m9Fs!_1UYig2YI&Ih;5^a-hghi!~T>QGRx(6rENJzWN=CEe;(vGjE zL&#e(te?Ryvw1+yl9scV9h3w{np~mvpUE8V4|0oMzr*O5rg79RjgvS7>buavcX3r> zN+~v%sa$tj;U)a}mg%0CR`HyaM+CV zn`|`HB3F;?PY}vk!k($UzBB(4Dlp{EES_IK1fvT-|Ls-sfC@;AoR`PXGIq5VCy4K7 zF>vPQl!Ghmi`uW+O6J3luCnsTvCv#NGC&?%8|JOiuJFd~sV!YVCA1Y1F<}`fALb2q zmJqJ)T@uaq=>IJ`$sP>`;j-h07#^Q?&5P~-N-m|813^bL%dSZ z0sH-%X805+MR|hX-Ep$jlxKu8C$Uep$$9?2$b1N_23i@yjb7Pc`J>ookXcksI`458 zLkjKZSvPO0f*~`2t+vu=%S!KDXrHSnA|UYnYGg=kIqmei?I~(-5vyvseAIb7QCLf3 z=cfTVM?dQ84%0skvpQTmCP=lgwnaIw_)RX}JaA~XH&1-4k`~%UhsWN+bT8Kq;^6dk ztdeH6pLB7~M-O*sfJl`c-|1ldbf6TF3r(eB-lV^@Rfxq%^Nt@ZVU6b?hec^+(hbUG zMsd(c23Ff;A9}-E{7~txbKKyn-}DQi&Wc|JkozI7MHpl69g*D)T__y5i+Wnx3TKlk zA5x&Y5SvVs>j;(bJ=cRZu>*9xrLRP-VyoN{V1hBI2RIHVy!k=<0T)F`fC_3*YDlm~ z8`&xI^$^tGAp^87$@4csn9jRdQ_gO)2A&3hRra7M528ngA#7HpbixC?@M4pl#`Mn! zWHqKDJGSp8BoyA#vUCdVujF3)>k;wSK6heag-Zi35h|jC?`jAmA^kpmAl&Fm6=gjcbf-6vxRhnEl`T_ z1Wzi_FaD?%hKkZ!9A7+Fm8R0|ux;{yDc9-tS&iSi9?`wHV^L zxLzsp$9=cH5wr}Pms;hL$t)CMh}>y=KQV%;4FOL)AxJ|RyZ&VP`xz3eN=5%9zy+Y2 zZqkYpuCGU6l_1HhU0YIF$SIl|iiC>q-bAPD{!gb}t5=q`JGNrfRa6F*6}@Ao=5mH% zHj)R{VCY}3hLs++9lROQwaqyi5*_+(i4MX<@|DDJ9uN%zh#2Su!^m|lmBubIgJVSs z(gvI8#>@37D-XTAXqD@yusXXhOiLEO;NzC?xA9)@t{M57UkAP|KfC#wDc5AsrN$kO ztjHZv_SM=}8CHBioHv}k{PqcK)-A5KQt&O@_i24(QK#|>5Ku$;-yf`g+h(`M zy**1>!-&o?z%kTYZ-8CylvfTPs}Z*MwGUB*<$CSH?JA7vRF*lvZj7G6<@t=`@g}Kv zlz{`7r{w@6vMYLNkJl8MiIPxpj|$f)yi{A zTC60WRe?)xw8xzXm)*_d$=yn>T8RIZN4PNb34JiMt}=bB$anr>st(4WUqSHm-BAzI zXPmhx+EAXIvN8auXxuzR$^ZRN-O1QPNxyY}49ctwe)&UisNxLI!L!-4mq@z+-tfJLXGSl`eF9gM_%a@2;P%drWJe zsuq{vm9|L>#eO!o&JzjNpII--adZfb`ph=WFv_Nc#CIbe^{lAf)Y3=mY2t=%9|I=d zO=K9x@oC4+++;f^H3b)#JqKl0F^+8ekBmi3jq4@Yh4 z3rKrm#(0rf*R#f_j)~9$tINFfCvLoQxM9>`UT!jecrMnOvd%w>Bqfb)FGighJXi_S z=(=daw!T-fq@j#V8goPH^^oV8w}*$_r0k1pU)CQ3o`|cQXSpF?27EZ+L9Xgjw1+M&R8S+9;M z7GEYUa&BqoVRq~0odd2A@0u9{0ME5#ZF4KSt*d?grFC;OlriEweq|Wp9;0J>8D{r6 z`v&39yAAOi4DnuO7-PSo1BF|C$r<4tZ+r?^eW{n56%}=^xad*n{CL*fa829E#MJ8g zpq)JHb7JFD@=d`MbFFK81unu^rs!l0olCU{|ll4Isj%-(W zV6uMQlQHRa-zsJ29coln>+7;D#|CalmTTz~EG#m-P6F2dwUiAE4pxeHt@ z7VlD-MzMGi8-+gdr<5#n>8~%vg4T_+HOANQaFD76#*A~1Cv$D~U`!Os*k+hb>H>+@ zwE0{&s_ibSzAragcXK;Lq$wN~vlaR}GPZ7ykmN(qd;$-wz?j99hi6V_O9!XKiH?uR zyYPH^)Y0}|)o}3%g-8C=9OJio#z{Hp9%;~mWp*tByL+Sl(^23)6YZ;$<91m+Z@u+I z@J(N`lXV2rwDcXPySQwQwB|({@uE-(fV_ETiR+r2N5Nd#m$=zt&`OX*Gbo zuT?}o|C(-PS*=oo$~oX$@WyFD@E>>}l-%#?w>dR$;RHQs-jEwa*=^}@fsNgl;J55Dp3@qu5j40^u5l#ZDi5gk& zVM$5-kMwJz^|BD$TMwDjYV~_ko+2jU{D~iKW1Uga&rSjUG6urxuN!ZRAwA4u(8T+- zwG79#y4r_kv=~Oxb!&6R9>(3;3al0Rs|Ntj`QSJ!Ggy_0`;tM0BHmZN6m&diU#ORV z#kFnCO9o7@+qEXf8B)fjua*RYRNl(uUpg67Dz1Bpw{SKvyE7^(AIS|o53qM~(kv`2 z{L;VBE|ju6|K`I3!*S*yXQ2n@?>%f?0=d@5Pp5Y3MUS@Cu$yZE5zdy9S|onm1nu^O zxn&KB3Iam_|NiVctk@O%C`#`Zg(b{DN?w>9ku$lp@x-_w!T%RKFp+8?npj!+t8e93 zMZ@x!`FH@J&!fHz5bs%ff>+L|B0RIA(5_m{D$1rPOmTr8c*^2~v$|n&!d+Huyd+IB zpR9lgvu&S_`*kZ(r^l`S4Oj>6erC?^Tg>r%lIa+PcGrs2*(EuB^d$vK*O?T%2I1hR zP+kD=`wb|Av$GCuaKT|^(rmaX+aGQwJ@w2NrAd()Q*II{RHnt);m=}K^ZO* z@5u_S)qF#I=(2K?&@?~ptU*j>si_*fo&Rsp4dI2Yz?;o^7tE?~zE_DGw|LZTkq55I zO)~;%Fo%{PRsayV{h7I~O{m&Ym{=80@C40j?ozaJw<$8z+lYm4?hi>0sti)d4fz{4blG@4=PfGx1`5ZZ#*e zd_o(V!RKRc*JCl65)qsyUtB*y1KQVYUMPOL*FD?Nxpae**(ph*TPN+Fub#l;Z&b6g zM?(K>4igUUY_|3U@@lTQY%bL1E;hYAb^`du_i;e@^vj4Ua7+7LF{0L?A?833rlQv>fd*owQqbJ!*Dwc$}}V3-7X#P4}PpgaFEW#%@@ zwCw8kIt4s$lZYaJNy&{$#S0#%T3AH#8ST&X^NrIPHa9D&Xa@~T}h=>F(w5~0pZHz2!#ebycoNI`i(9_a3Cd&?m;M2Masw1;+ zMKkU{2fZG;eg5R@Y5z1_tbM*2b~7QO}}e>;L|e_ z)z3k26J~eAjhSf~;|q#?HAOn!xK^3R?=%B|zc#bFs~hoN*L`el7i^b1tkHU4lXWph z$_7n>+ieA|;gKrfxSKoj22b1)7*HlHN(;cekal)DvtB!N2j9T~#NJ4l#of*AoK?EU z9@ja?jLfO5%=e60_u`maB0elkD1*KF)3=L1A|kU5j4nx47&_PQ!RWI{wro4Ua)ZB5 zY6a&Gf}JjSh_W56 zHFAOc1pcM0@p6WFkkaPOs(fE%jdY69H;w4yjid6r z`@OzN?b z62oII_NF;It=_hws`}sqPKL$^GHRmv>`&jFDgmaGOfXDK zfDj@)x?`zweRntPA}ed|miq}H#RB|PRaPd{nODmY88*Ht7iBK2?kbhG^dllrf{KT! zwpcVvOT?w99Br)g5)r;@Slv5eNxs)4Ro=5G*d_e>gB$)N0F=D)`doDFwa;9H_Yf{1 zXVhA!As)^h__}LW8}Zr5z};50)8VykRd3`lVbeH0fKkGrGlif(82&Kt^67rp z8i(T9W6r>Hk#~K>HnUul!s5&H%wdz?N9M~kOSBEgnMCB2o~?Y1l*mXq2|PVzRA{W# z%QWBRXqq#w2LoUKkoDr;p7B1QU9KF7i#18Uda5B)i5Yml{fJOG;#N57nr~8AXrAvX zLxgu-m%qY0pV5U@DJ7KR^lGj3Wzr>10MBh-Uj8*T^&!)LYWZG>5``?U#4j|8O+YLy z&S+zczOliBtmI%-qt4dk58%PdJ^k_#52@J<<2b&X8U-f8hA@m+honEFT3MzF>S3{o z4p?=YG;ttH6S%a?zI-WgtjIr`Jm55@mz&F%y6h7vG`Muf`0QC}cMp$t^TK8iSm3xB zSk;9TaQDrez(D3}R~3YYhJvkEXgHgrQQvwiZ;Y_kg&SgG`m;fFz^a>LK!Dk^jD;Re z9zuP$V^T=i=Kbzap1z-nUS_K2odaCVI0%HLttZkWoKU*8NVKTJ}za!Ri$9%?p6eIanWjK!@E|caw~vu zZPclkq9_FTR6lRXn;h}iDdu`&VEAfhbZm-zamAyfqivK10LTpOC%}yhjk)B!bcuR` zFtM|Sijppv#M6jM{vZUNj^wOF&2yi5BJjOO`q1dL&4}UtTXspi!YvcL`nlz&eEJa}s4xvt$fNwhM zP8YSY<=o0%+2W6WDOYxjBETn{L8eZ|u&PbPwQF=$Un`5Y-mo&al*#z{%3V1De7#y` zlCFRQ$J}I5%U|v5UgVn<_o~bhbHoab0~B&dF*?1Dk(EJ2??Q2LF}9`cIN*PW zEll2L;cZ}TX5G`jALY@@@RO3xsFt0Hn+jQ$g?Q$$_l@GemX^|FWM!EBaKpdHj0^i% zfNx*>T>Yv(*A`mW6h>{q!PSIM9}l&CXI?B*LG~vtleaXV6i0K)6%-fW;F9;bwuc0O zpR!cFr2Ou$?us2^A?|5l)q63E%%As2hc!{PA{F|TX7zJ#g1 z+nxH5hQnzW;h!KLj#}$;u!`jwSiOxmWY#b*GG;#6fIoBxfMwnRbLlkqA6g$Av)=3B zKpEjz#~SSJ-#+hLW}STIB?6X=WiR!%c`-gV2JUPN0<##<9pn+{47TEYTFr<;P@7m@ z+2(<=!*1uZJ|hH{oyb3B^+eB=tRB{2&=T8sKd|c3>Gyv;EAslBtv1MMklWX@`(vX( zOjJnkNvP`oJ*~Ov4`wB;))PGO#}YYEyT~{f-@oFa_U6r-0vqo9RL0M*KYHdlKK^Ss~}<(*jM%~=8X`Aqo>PwXu&G?zYq6jz04A| z)w|@-^-on#Cb5JIIcQLE4X^>Tag6i5W|4XrZrFKC;C=_Gi3`8$`Y;T_wnokP+1Cg zfRSxqUN>;|A!kEFH#f6K9V_bZ7!=|w9~8C;M5J}*$jA;jp!=q#;@W4+Uy5tjh_Lg{ z--V9pR2=S!a)|Slfqk?uhe904RabKhtA}i1l*6=K9@adQQjsOh@ybKuv)6?FzZAAsk@fR?)6-I6Bhlnx-Du{g-x ziDBJ2nU_G-ES@foAr*7p-rblL9LR9&qp)U%ELT&smPL!+FQ$F%`WFo^teow={E~H< zR_Mfr=JOANOEhohv_~1VMY#yB^Zy{)o_)^nUmbtJJNBI{|K>Qj`5*KDeaI_kZ$)S| z(}B5W`R7jc`^%rc{s9#jn$s z{!e6BFeT{J@0;zP-o1VO>GSpNw}KfmjvRaJ9=+9^;X+3{|GVk8Z{OY&QMb;PwZZL& zrx0N;NN;8TU4=q@BIrA-N_VTOcPvZZsxl2tSn7sPEZ@n#3gV~&UXS}Yzopr0Q8j*@&Et; literal 0 HcmV?d00001 From f212d5a058416d4a6f8e727d32785804855fb0dc Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 20 Jul 2026 14:27:59 +0200 Subject: [PATCH 34/35] refactor(ui): align StreamAppBar background resolution with StreamBottomNavBar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve the regular and floating backgrounds as separate, unconditional effective-value locals (effectiveBackgroundColor / effectiveFloatingBackgroundColor) instead of a behavior switch that collapsed them into one value, and rename effectiveStreamAppBarBehavior to effectiveBehavior. Behavior-preserving — the rendered output is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../components/toolbar/stream_app_bar.dart | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart index 333c14a6..4a275114 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_app_bar.dart @@ -215,17 +215,16 @@ class DefaultStreamAppBar extends StatelessWidget { final icons = context.streamIcons; final spacing = context.streamSpacing; + final appStyle = context.streamTheme.appStyle; + final style = context.streamAppBarTheme.style?.merge(props.style) ?? props.style; final defaults = _StreamAppBarStyleDefaults(context); - final effectiveStreamAppBarBehavior = - style?.behavior ?? - (context.streamTheme.appStyle.isFloating ? StreamAppBarBehavior.floating : StreamAppBarBehavior.regular); + var effectiveBehavior = style?.behavior ?? defaults.behavior; + effectiveBehavior ??= appStyle.isFloating ? .floating : .regular; - final effectiveBackgroundColor = switch (effectiveStreamAppBarBehavior) { - .floating => style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor, - .regular => style?.backgroundColor ?? defaults.backgroundColor, - }; + final effectiveBackgroundColor = style?.backgroundColor ?? defaults.backgroundColor; + final effectiveFloatingBackgroundColor = style?.floatingBackgroundColor ?? defaults.floatingBackgroundColor; final effectivePadding = style?.padding ?? defaults.padding; final effectiveSpacing = style?.spacing ?? defaults.spacing; final effectiveTitleTextStyle = style?.titleTextStyle ?? defaults.titleTextStyle; @@ -250,11 +249,11 @@ class DefaultStreamAppBar extends StatelessWidget { final useCloseIcon = parentRoute is PageRoute && parentRoute.fullscreenDialog; final localizations = MaterialLocalizations.of(context); leading = StreamButton.icon( - type: switch (effectiveStreamAppBarBehavior) { + type: switch (effectiveBehavior) { .floating => .outline, .regular => .ghost, }, - isFloating: effectiveStreamAppBarBehavior == .floating, + isFloating: effectiveBehavior == .floating, style: .secondary, tooltip: useCloseIcon ? localizations.closeButtonTooltip : localizations.backButtonTooltip, icon: Icon(useCloseIcon ? icons.xmark : backIcon), @@ -360,15 +359,15 @@ class DefaultStreamAppBar extends StatelessWidget { container: true, child: DecoratedBox( decoration: BoxDecoration( - color: switch (effectiveStreamAppBarBehavior) { + color: switch (effectiveBehavior) { .floating => null, .regular => effectiveBackgroundColor, }, - gradient: switch (effectiveStreamAppBarBehavior) { - .floating => _getFloatingGradient(context, effectiveBackgroundColor: effectiveBackgroundColor), + gradient: switch (effectiveBehavior) { + .floating => _getFloatingGradient(context, color: effectiveFloatingBackgroundColor), .regular => null, }, - border: switch (effectiveStreamAppBarBehavior) { + border: switch (effectiveBehavior) { .floating => null, .regular => Border(bottom: BorderSide(color: context.streamColorScheme.borderSubtle)), }, @@ -380,7 +379,7 @@ class DefaultStreamAppBar extends StatelessWidget { LinearGradient _getFloatingGradient( BuildContext context, { - required Color effectiveBackgroundColor, + required Color color, }) { // Compute the fraction of the total bar height occupied by the system // safe area so the gradient is solid through the status bar and fades only @@ -389,7 +388,7 @@ class DefaultStreamAppBar extends StatelessWidget { final totalHeight = safeAreaTop + kStreamToolbarHeight; final solidFraction = totalHeight > 0 ? safeAreaTop / totalHeight : 0.0; - return streamFloatingFadeLinearGradient(color: effectiveBackgroundColor, solidFraction: solidFraction); + return streamFloatingFadeLinearGradient(color: color, solidFraction: solidFraction); } } From eed05d07bbb7b31babb429c09184e6470dd15831 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 29 Jul 2026 11:22:39 +0200 Subject: [PATCH 35/35] coderabbit comments --- .../components/toolbar/stream_bottom_nav_bar.dart | 5 +++++ packages/stream_core_flutter/CHANGELOG.md | 2 +- .../components/toolbar/stream_bottom_nav_bar.dart | 12 +++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart b/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart index 089e7f86..5ff177f9 100644 --- a/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart +++ b/apps/design_system_gallery/lib/components/toolbar/stream_bottom_nav_bar.dart @@ -216,6 +216,11 @@ class _BarExample extends StatelessWidget { decoration: BoxDecoration( color: colorScheme.backgroundSurface, borderRadius: BorderRadius.all(radius.lg), + ), + // The clip follows the outer rounded rect, so at the corners the bar + // paints over an inside-aligned border. Draw it in the foreground. + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.all(radius.lg), border: Border.all(color: colorScheme.borderSubtle), ), child: bar, diff --git a/packages/stream_core_flutter/CHANGELOG.md b/packages/stream_core_flutter/CHANGELOG.md index 4a2eeb19..1d1cf953 100644 --- a/packages/stream_core_flutter/CHANGELOG.md +++ b/packages/stream_core_flutter/CHANGELOG.md @@ -24,7 +24,7 @@ - Split the public API into `package:stream_core_flutter/core.dart` (shared primitives for any Stream SDK) and `package:stream_core_flutter/chat.dart` (chat-only widgets; re-exports `core.dart`); the convenience barrel `package:stream_core_flutter/stream_core_flutter.dart` is now deprecated. - Added `StreamScaffold` — a full-page scaffold that supports both regular and floating app-bar / bottom-bar layouts. Injects `StreamScaffoldInsets` into the widget tree so scrollable bodies can read the effective top and bottom padding from floating bars without coupling to layout details. -- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Renders either a regular docked bar or a floating pill with a gradient fade-out beneath it, resolved from the per-instance `behavior`, the `StreamBottomNavBarTheme`, the `StreamBottomAppBarTheme` (kept in sync with `StreamScaffold`), then `StreamAppStyle`. Follows the standard `Props`/`Default`/`StreamComponentFactory` pattern (`bottomNavBar` builder) and is themeable via `StreamBottomNavBarTheme` / `StreamBottomNavBarStyle` (selected/unselected item colours, icon size, label styles, border, pill radius). Items announce themselves as accessible buttons via `Semantics`. +- Added `StreamBottomNavBar` and `StreamBottomNavBarItem` — a bottom navigation bar with icon, selected-icon, and label slots per item. Renders either a regular docked bar or a floating pill with a gradient fade-out beneath it, resolved from the per-instance `behavior`, the `StreamBottomNavBarTheme`, then `StreamAppStyle`. Follows the standard `Props`/`Default`/`StreamComponentFactory` pattern (`bottomNavBar` builder) and is themeable via `StreamBottomNavBarTheme` / `StreamBottomNavBarStyle` (selected/unselected item colours, icon size, label styles, border, pill radius). Items announce themselves as accessible buttons via `Semantics`. - Added floating-bar support to `StreamAppBar` via a new `appBarBehavior` property. When set to `StreamAppBarBehavior.floating`, the app bar renders above the body with a translucent background and a gradient overlay. - Added `showShadow` to `StreamAvatar`, `StreamAvatarGroup`, and `StreamAvatarStack`. When true, applies the `StreamAvatarThemeData.boxShadow` (falling back to `StreamBoxShadow.elevation3`) as a drop shadow around the avatar shape. Fixed: a themed `boxShadow` in `StreamAvatarThemeData` no longer bleeds onto avatars where `showShadow` is `false`. - Added `streamFloatingFade` helper — a shared `LinearGradient` factory (alpha stops `0xE8/0xA8/0x40/0x00` with solid-fraction support for safe-area zones) used internally by `StreamAppBar`, `StreamBottomNavBar`, and `StreamMessageComposer` floating fade effects. diff --git a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart index dbaf3b11..57d4b274 100644 --- a/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart +++ b/packages/stream_core_flutter/lib/src/components/toolbar/stream_bottom_nav_bar.dart @@ -102,6 +102,11 @@ class StreamBottomNavBar extends StatelessWidget { StreamBottomNavBarBehavior? behavior, StreamBottomNavBarStyle? style, }) : assert(items.length >= 2, 'StreamBottomNavBar requires at least 2 items'), + assert( + currentIndex >= 0 && currentIndex < items.length, + 'currentIndex must be within the items range: ' + '0 <= $currentIndex < ${items.length}', + ), props = .new( items: items, currentIndex: currentIndex, @@ -138,7 +143,10 @@ class StreamBottomNavBarProps { required this.onTap, this.behavior, this.style, - }); + }) : assert( + currentIndex >= 0 && currentIndex < items.length, + 'currentIndex must be within the items range', + ); /// The list of items to display in the navigation bar. /// @@ -146,6 +154,8 @@ class StreamBottomNavBarProps { final List items; /// The index of the currently selected item. + /// + /// Must be a valid index into [items]. final int currentIndex; /// Called when the user taps a navigation item.