diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 81f69a0c..12af5a99 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,5 +1,9 @@ ## Upcoming +✅ Added + +- `centerTitle` and `elevation` properties to `ChannelHeader`, `ThreadHeader` and `ChannelListHeader`. + 🐞 Fixed - [[#1067]](https://github.com/GetStream/stream-chat-flutter/issues/1067): Fix name text overflow in reaction card. diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 954aa758..2716ea00 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -61,9 +61,11 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { this.showConnectionStateTile = false, this.title, this.subtitle, + this.centerTitle, this.leading, this.actions, this.backgroundColor, + this.elevation = 1, }) : preferredSize = const Size.fromHeight(kToolbarHeight), super(key: key); @@ -92,6 +94,9 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// Subtitle widget final Widget? subtitle; + /// Whether the title should be centered + final bool? centerTitle; + /// Leading widget final Widget? leading; @@ -102,8 +107,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// The background color for this [ChannelHeader]. final Color? backgroundColor; + /// The elevation for this [ChannelHeader]. + final double elevation; + @override Widget build(BuildContext context) { + final effectiveCenterTitle = getEffectiveCenterTitle( + Theme.of(context), + actions: actions, + centerTitle: centerTitle, + ); final channel = StreamChannel.of(context).channel; final channelHeaderTheme = ChannelHeaderTheme.of(context); @@ -144,7 +157,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { systemOverlayStyle: theme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, - elevation: 1, + elevation: elevation, leading: leadingWidget, backgroundColor: backgroundColor ?? channelHeaderTheme.color, actions: actions ?? @@ -162,14 +175,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { ), ), ], - centerTitle: true, + centerTitle: centerTitle, title: InkWell( onTap: onTitleTap, child: SizedBox( height: preferredSize.height, - width: preferredSize.width, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: effectiveCenterTitle + ? CrossAxisAlignment.center + : CrossAxisAlignment.stretch, children: [ title ?? ChannelName( diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index 6c54ad89..fbe71ff7 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -56,9 +56,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.showConnectionStateTile = false, this.preNavigationCallback, this.subtitle, + this.centerTitle, this.leading, this.actions, this.backgroundColor, + this.elevation = 1, }) : super(key: key); /// Pass this if you don't have a [StreamChatClient] in your widget tree. @@ -83,6 +85,9 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// Subtitle widget final Widget? subtitle; + /// Whether the title should be centered + final bool? centerTitle; + /// Leading widget /// By default it shows the logged in user avatar final Widget? leading; @@ -94,6 +99,9 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// The background color for this [ChannelListHeader]. final Color? backgroundColor; + /// The elevation for this [ChannelListHeader]. + final double elevation; + @override Widget build(BuildContext context) { final _client = client ?? StreamChat.of(context).client; @@ -128,10 +136,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { systemOverlayStyle: theme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, - elevation: 1, + elevation: elevation, backgroundColor: backgroundColor ?? channelListHeaderThemeData.color, - centerTitle: true, + centerTitle: centerTitle, leading: leading ?? Center( child: user != null diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index cf4b1cd0..ed1ea56e 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -528,6 +528,7 @@ class _MessageListViewState extends State { return ((index + 2) * 2) - 1; } } + return null; }, // Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages) diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index aae1d8f9..199b8a44 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -65,11 +65,13 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { this.onBackPressed, this.title, this.subtitle, + this.centerTitle, this.leading, this.actions, this.onTitleTap, this.showTypingIndicator = true, this.backgroundColor, + this.elevation = 1, }) : preferredSize = const Size.fromHeight(kToolbarHeight), super(key: key); @@ -92,6 +94,9 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { /// Subtitle widget final Widget? subtitle; + /// Whether the title should be centered + final bool? centerTitle; + /// Leading widget final Widget? leading; @@ -105,8 +110,17 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { /// The background color of this [ThreadHeader]. final Color? backgroundColor; + /// The elevation for this [ThreadHeader]. + final double elevation; + @override Widget build(BuildContext context) { + final effectiveCenterTitle = getEffectiveCenterTitle( + Theme.of(context), + actions: actions, + centerTitle: centerTitle, + ); + final channelHeaderTheme = ChannelHeaderTheme.of(context); final defaultSubtitle = subtitle ?? @@ -134,7 +148,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { systemOverlayStyle: theme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, - elevation: 1, + elevation: elevation, leading: leading ?? (showBackButton ? StreamBackButton( @@ -144,7 +158,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { ) : const SizedBox()), backgroundColor: backgroundColor ?? channelHeaderTheme.color, - centerTitle: true, + centerTitle: centerTitle, actions: actions, title: InkWell( onTap: onTitleTap, @@ -153,6 +167,9 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { width: 250, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: effectiveCenterTitle + ? CrossAxisAlignment.center + : CrossAxisAlignment.stretch, children: [ title ?? Text( diff --git a/packages/stream_chat_flutter/lib/src/typing_indicator.dart b/packages/stream_chat_flutter/lib/src/typing_indicator.dart index d961a8ff..5bf7358a 100644 --- a/packages/stream_chat_flutter/lib/src/typing_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/typing_indicator.dart @@ -47,6 +47,12 @@ class TypingIndicator extends StatelessWidget { .where((element) => element.value.parentId == parentId) .map((e) => e.key)), builder: (context, data) => AnimatedSwitcher( + layoutBuilder: (currentChild, previousChildren) => Stack( + children: [ + ...previousChildren, + if (currentChild != null) currentChild, + ], + ), duration: const Duration(milliseconds: 300), child: data.isNotEmpty ? Padding( diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 3825263d..3d012194 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -17,6 +17,28 @@ Future launchURL(BuildContext context, String url) async { } } +/// Get centerTitle considering a default and platform specific behaviour +bool getEffectiveCenterTitle( + ThemeData theme, { + bool? centerTitle, + List? actions, +}) { + if (centerTitle != null) return centerTitle; + if (theme.appBarTheme.centerTitle != null) { + return theme.appBarTheme.centerTitle!; + } + switch (theme.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return false; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return actions == null || actions.length < 2; + } +} + /// Shows confirmation dialog Future showConfirmationDialog( BuildContext context, { diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart index 0c7ce68e..16838cf5 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart @@ -74,6 +74,8 @@ GlobalStreamChatLocalizations? getStreamChatTranslation(Locale locale) { return const StreamChatLocalizationsKo(); case 'pt': return const StreamChatLocalizationsPt(); + default: + return null; } }