Merge pull request #938 from S-ecki/develop

feat(ui): Add Channel Header customization
This commit is contained in:
Salvatore Giordano
2022-04-27 13:31:45 +02:00
committed by GitHub
8 changed files with 82 additions and 7 deletions
@@ -1,5 +1,9 @@
## Upcoming ## Upcoming
✅ Added
- `centerTitle` and `elevation` properties to `ChannelHeader`, `ThreadHeader` and `ChannelListHeader`.
🐞 Fixed 🐞 Fixed
- [[#1067]](https://github.com/GetStream/stream-chat-flutter/issues/1067): Fix name text overflow in reaction card. - [[#1067]](https://github.com/GetStream/stream-chat-flutter/issues/1067): Fix name text overflow in reaction card.
@@ -61,9 +61,11 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
this.showConnectionStateTile = false, this.showConnectionStateTile = false,
this.title, this.title,
this.subtitle, this.subtitle,
this.centerTitle,
this.leading, this.leading,
this.actions, this.actions,
this.backgroundColor, this.backgroundColor,
this.elevation = 1,
}) : preferredSize = const Size.fromHeight(kToolbarHeight), }) : preferredSize = const Size.fromHeight(kToolbarHeight),
super(key: key); super(key: key);
@@ -92,6 +94,9 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
/// Subtitle widget /// Subtitle widget
final Widget? subtitle; final Widget? subtitle;
/// Whether the title should be centered
final bool? centerTitle;
/// Leading widget /// Leading widget
final Widget? leading; final Widget? leading;
@@ -102,8 +107,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
/// The background color for this [ChannelHeader]. /// The background color for this [ChannelHeader].
final Color? backgroundColor; final Color? backgroundColor;
/// The elevation for this [ChannelHeader].
final double elevation;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final effectiveCenterTitle = getEffectiveCenterTitle(
Theme.of(context),
actions: actions,
centerTitle: centerTitle,
);
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
final channelHeaderTheme = ChannelHeaderTheme.of(context); final channelHeaderTheme = ChannelHeaderTheme.of(context);
@@ -144,7 +157,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
systemOverlayStyle: theme.brightness == Brightness.dark systemOverlayStyle: theme.brightness == Brightness.dark
? SystemUiOverlayStyle.light ? SystemUiOverlayStyle.light
: SystemUiOverlayStyle.dark, : SystemUiOverlayStyle.dark,
elevation: 1, elevation: elevation,
leading: leadingWidget, leading: leadingWidget,
backgroundColor: backgroundColor ?? channelHeaderTheme.color, backgroundColor: backgroundColor ?? channelHeaderTheme.color,
actions: actions ?? actions: actions ??
@@ -162,14 +175,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
), ),
), ),
], ],
centerTitle: true, centerTitle: centerTitle,
title: InkWell( title: InkWell(
onTap: onTitleTap, onTap: onTitleTap,
child: SizedBox( child: SizedBox(
height: preferredSize.height, height: preferredSize.height,
width: preferredSize.width,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: effectiveCenterTitle
? CrossAxisAlignment.center
: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
title ?? title ??
ChannelName( ChannelName(
@@ -56,9 +56,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
this.showConnectionStateTile = false, this.showConnectionStateTile = false,
this.preNavigationCallback, this.preNavigationCallback,
this.subtitle, this.subtitle,
this.centerTitle,
this.leading, this.leading,
this.actions, this.actions,
this.backgroundColor, this.backgroundColor,
this.elevation = 1,
}) : super(key: key); }) : super(key: key);
/// Pass this if you don't have a [StreamChatClient] in your widget tree. /// 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 /// Subtitle widget
final Widget? subtitle; final Widget? subtitle;
/// Whether the title should be centered
final bool? centerTitle;
/// Leading widget /// Leading widget
/// By default it shows the logged in user avatar /// By default it shows the logged in user avatar
final Widget? leading; final Widget? leading;
@@ -94,6 +99,9 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
/// The background color for this [ChannelListHeader]. /// The background color for this [ChannelListHeader].
final Color? backgroundColor; final Color? backgroundColor;
/// The elevation for this [ChannelListHeader].
final double elevation;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final _client = client ?? StreamChat.of(context).client; final _client = client ?? StreamChat.of(context).client;
@@ -128,10 +136,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
systemOverlayStyle: theme.brightness == Brightness.dark systemOverlayStyle: theme.brightness == Brightness.dark
? SystemUiOverlayStyle.light ? SystemUiOverlayStyle.light
: SystemUiOverlayStyle.dark, : SystemUiOverlayStyle.dark,
elevation: 1, elevation: elevation,
backgroundColor: backgroundColor:
backgroundColor ?? channelListHeaderThemeData.color, backgroundColor ?? channelListHeaderThemeData.color,
centerTitle: true, centerTitle: centerTitle,
leading: leading ?? leading: leading ??
Center( Center(
child: user != null child: user != null
@@ -528,6 +528,7 @@ class _MessageListViewState extends State<MessageListView> {
return ((index + 2) * 2) - 1; return ((index + 2) * 2) - 1;
} }
} }
return null;
}, },
// Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages) // Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages)
@@ -65,11 +65,13 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
this.onBackPressed, this.onBackPressed,
this.title, this.title,
this.subtitle, this.subtitle,
this.centerTitle,
this.leading, this.leading,
this.actions, this.actions,
this.onTitleTap, this.onTitleTap,
this.showTypingIndicator = true, this.showTypingIndicator = true,
this.backgroundColor, this.backgroundColor,
this.elevation = 1,
}) : preferredSize = const Size.fromHeight(kToolbarHeight), }) : preferredSize = const Size.fromHeight(kToolbarHeight),
super(key: key); super(key: key);
@@ -92,6 +94,9 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
/// Subtitle widget /// Subtitle widget
final Widget? subtitle; final Widget? subtitle;
/// Whether the title should be centered
final bool? centerTitle;
/// Leading widget /// Leading widget
final Widget? leading; final Widget? leading;
@@ -105,8 +110,17 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
/// The background color of this [ThreadHeader]. /// The background color of this [ThreadHeader].
final Color? backgroundColor; final Color? backgroundColor;
/// The elevation for this [ThreadHeader].
final double elevation;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final effectiveCenterTitle = getEffectiveCenterTitle(
Theme.of(context),
actions: actions,
centerTitle: centerTitle,
);
final channelHeaderTheme = ChannelHeaderTheme.of(context); final channelHeaderTheme = ChannelHeaderTheme.of(context);
final defaultSubtitle = subtitle ?? final defaultSubtitle = subtitle ??
@@ -134,7 +148,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
systemOverlayStyle: theme.brightness == Brightness.dark systemOverlayStyle: theme.brightness == Brightness.dark
? SystemUiOverlayStyle.light ? SystemUiOverlayStyle.light
: SystemUiOverlayStyle.dark, : SystemUiOverlayStyle.dark,
elevation: 1, elevation: elevation,
leading: leading ?? leading: leading ??
(showBackButton (showBackButton
? StreamBackButton( ? StreamBackButton(
@@ -144,7 +158,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
) )
: const SizedBox()), : const SizedBox()),
backgroundColor: backgroundColor ?? channelHeaderTheme.color, backgroundColor: backgroundColor ?? channelHeaderTheme.color,
centerTitle: true, centerTitle: centerTitle,
actions: actions, actions: actions,
title: InkWell( title: InkWell(
onTap: onTitleTap, onTap: onTitleTap,
@@ -153,6 +167,9 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
width: 250, width: 250,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: effectiveCenterTitle
? CrossAxisAlignment.center
: CrossAxisAlignment.stretch,
children: [ children: [
title ?? title ??
Text( Text(
@@ -47,6 +47,12 @@ class TypingIndicator extends StatelessWidget {
.where((element) => element.value.parentId == parentId) .where((element) => element.value.parentId == parentId)
.map((e) => e.key)), .map((e) => e.key)),
builder: (context, data) => AnimatedSwitcher( builder: (context, data) => AnimatedSwitcher(
layoutBuilder: (currentChild, previousChildren) => Stack(
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
),
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: data.isNotEmpty child: data.isNotEmpty
? Padding( ? Padding(
@@ -17,6 +17,28 @@ Future<void> launchURL(BuildContext context, String url) async {
} }
} }
/// Get centerTitle considering a default and platform specific behaviour
bool getEffectiveCenterTitle(
ThemeData theme, {
bool? centerTitle,
List<Widget>? 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 /// Shows confirmation dialog
Future<bool?> showConfirmationDialog( Future<bool?> showConfirmationDialog(
BuildContext context, { BuildContext context, {
@@ -74,6 +74,8 @@ GlobalStreamChatLocalizations? getStreamChatTranslation(Locale locale) {
return const StreamChatLocalizationsKo(); return const StreamChatLocalizationsKo();
case 'pt': case 'pt':
return const StreamChatLocalizationsPt(); return const StreamChatLocalizationsPt();
default:
return null;
} }
} }