Skip to content

Commit a0e886b

Browse files
authored
refactor(ui): unread indicator redesign (#2548)
* unread indicator redesign * tweak
1 parent 64253d7 commit a0e886b

File tree

4 files changed

+86
-35
lines changed

4 files changed

+86
-35
lines changed

packages/stream_chat_flutter/lib/src/components/stream_chat_component_builders.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Iterable<StreamComponentBuilderExtension<Object>> streamChatComponentBuilders({
1212
StreamComponentBuilder<MessageComposerInputHeaderProps>? messageComposerInputHeader,
1313
StreamComponentBuilder<MessageComposerInputTrailingProps>? messageComposerInputTrailing,
1414
StreamComponentBuilder<StreamMessageWidgetProps>? messageWidget,
15+
StreamComponentBuilder<UnreadIndicatorProps>? unreadIndicator,
1516
}) {
1617
final builders = [
1718
if (channelListItem != null) StreamComponentBuilderExtension(builder: channelListItem),
@@ -23,6 +24,7 @@ Iterable<StreamComponentBuilderExtension<Object>> streamChatComponentBuilders({
2324
if (messageComposerInputHeader != null) StreamComponentBuilderExtension(builder: messageComposerInputHeader),
2425
if (messageComposerInputTrailing != null) StreamComponentBuilderExtension(builder: messageComposerInputTrailing),
2526
if (messageWidget != null) StreamComponentBuilderExtension(builder: messageWidget),
27+
if (unreadIndicator != null) StreamComponentBuilderExtension(builder: unreadIndicator),
2628
];
2729

2830
return builders;

packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'package:stream_chat_flutter/src/message_list_view/floating_date_divider.
99
import 'package:stream_chat_flutter/src/message_list_view/loading_indicator.dart';
1010
import 'package:stream_chat_flutter/src/message_list_view/mlv_utils.dart';
1111
import 'package:stream_chat_flutter/src/message_list_view/thread_separator.dart';
12-
import 'package:stream_chat_flutter/src/message_list_view/unread_indicator_button.dart';
1312
import 'package:stream_chat_flutter/src/message_list_view/unread_messages_separator.dart';
1413
import 'package:stream_chat_flutter/src/message_widget/ephemeral_message.dart';
1514
import 'package:stream_chat_flutter/src/misc/empty_widget.dart';
@@ -1115,8 +1114,8 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
11151114
);
11161115

11171116
return Positioned(
1118-
bottom: 8,
1119-
right: 8,
1117+
bottom: 16,
1118+
right: 16,
11201119
width: 40,
11211120
height: 40,
11221121
child: Stack(

packages/stream_chat_flutter/lib/src/message_list_view/unread_indicator_button.dart

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
2+
import 'package:stream_chat_flutter/src/components/stream_chat_component_builders.dart';
23
import 'package:stream_chat_flutter/src/misc/empty_widget.dart';
3-
import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart';
44
import 'package:stream_chat_flutter/src/utils/extensions.dart';
55
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
66
import 'package:stream_core_flutter/stream_core_flutter.dart';
@@ -24,6 +24,32 @@ typedef UnreadIndicatorBuilder =
2424
OnUnreadIndicatorDismissTap onDismissTap,
2525
);
2626

27+
/// Properties for configuring an [UnreadIndicatorButton].
28+
///
29+
/// This class holds all the configuration options for an unread indicator,
30+
/// allowing them to be passed through the [StreamComponentFactory].
31+
///
32+
/// See also:
33+
///
34+
/// * [UnreadIndicatorButton], which uses these properties.
35+
class UnreadIndicatorProps {
36+
/// Creates properties for an unread indicator.
37+
const UnreadIndicatorProps({
38+
required this.unreadCount,
39+
required this.onTap,
40+
required this.onDismissTap,
41+
});
42+
43+
/// The number of unread messages.
44+
final int unreadCount;
45+
46+
/// Callback triggered when the indicator is tapped.
47+
final OnUnreadIndicatorTap onTap;
48+
49+
/// Callback triggered when the dismiss button is tapped.
50+
final OnUnreadIndicatorDismissTap onDismissTap;
51+
}
52+
2753
/// {@template unreadIndicatorButton}
2854
/// A button that displays the number of unread messages in a channel.
2955
///
@@ -52,7 +78,8 @@ class UnreadIndicatorButton extends StatelessWidget {
5278

5379
/// Optional builder for customizing the appearance of the unread indicator.
5480
///
55-
/// If not provided, a default indicator will be built.
81+
/// If not provided, falls back to [StreamComponentFactory], then to the
82+
/// default indicator.
5683
final UnreadIndicatorBuilder? unreadIndicatorBuilder;
5784

5885
@override
@@ -67,46 +94,68 @@ class UnreadIndicatorButton extends StatelessWidget {
6794
final unreadCount = currentUserRead.unreadMessages;
6895
if (unreadCount <= 0) return const Empty();
6996

97+
final props = UnreadIndicatorProps(
98+
unreadCount: unreadCount,
99+
onTap: onTap,
100+
onDismissTap: onDismissTap,
101+
);
102+
70103
if (unreadIndicatorBuilder case final builder?) {
71104
return builder(unreadCount, onTap, onDismissTap);
72105
}
73106

74-
final theme = StreamChatTheme.of(context);
75-
final textTheme = theme.textTheme;
76-
final colorTheme = theme.colorTheme;
107+
final factoryBuilder = context.chatComponentBuilder<UnreadIndicatorProps>();
108+
if (factoryBuilder != null) return factoryBuilder(context, props);
109+
110+
final colorTheme = context.streamColorScheme;
111+
final textTheme = context.streamTextTheme;
77112

78113
return Material(
79-
elevation: 4,
114+
elevation: 3,
80115
clipBehavior: Clip.antiAlias,
81-
color: colorTheme.textLowEmphasis,
116+
color: colorTheme.backgroundElevation1,
82117
shape: RoundedRectangleBorder(
83-
borderRadius: BorderRadius.circular(18),
118+
borderRadius: BorderRadiusDirectional.all(context.streamRadius.max),
84119
),
85-
child: InkWell(
86-
onTap: () => onTap(currentUserRead.lastReadMessageId),
87-
child: Padding(
88-
padding: const EdgeInsets.fromLTRB(16, 2, 8, 2),
89-
child: Row(
90-
children: [
91-
Text(
92-
context.translations.unreadCountIndicatorLabel(
93-
unreadCount: unreadCount,
94-
),
95-
style: textTheme.body.copyWith(color: colorTheme.barsBg),
96-
),
97-
const SizedBox(width: 12),
98-
IconButton(
99-
iconSize: 24,
100-
icon: Icon(context.streamIcons.crossMedium),
101-
padding: const EdgeInsets.all(4),
102-
style: IconButton.styleFrom(
103-
foregroundColor: colorTheme.barsBg,
104-
minimumSize: const Size.square(24),
105-
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
106-
),
107-
onPressed: onDismissTap,
120+
child: SizedBox(
121+
height: 40,
122+
child: InkWell(
123+
onTap: () => onTap(currentUserRead.lastReadMessageId),
124+
child: Padding(
125+
padding: const EdgeInsets.fromLTRB(16, 2, 8, 2),
126+
child: IntrinsicHeight(
127+
child: Row(
128+
children: [
129+
Icon(
130+
context.streamIcons.arrowUp,
131+
size: 20,
132+
),
133+
SizedBox(width: context.streamSpacing.xs),
134+
Text(
135+
context.translations.unreadCountIndicatorLabel(
136+
unreadCount: unreadCount,
137+
),
138+
style: textTheme.bodyEmphasis.copyWith(color: colorTheme.textSecondary),
139+
),
140+
SizedBox(width: context.streamSpacing.md),
141+
VerticalDivider(
142+
color: colorTheme.borderDefault,
143+
thickness: 1,
144+
),
145+
IconButton(
146+
iconSize: 20,
147+
icon: Icon(context.streamIcons.crossMedium),
148+
padding: const EdgeInsets.all(5),
149+
style: IconButton.styleFrom(
150+
foregroundColor: colorTheme.textSecondary,
151+
minimumSize: const Size.square(20),
152+
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
153+
),
154+
onPressed: onDismissTap,
155+
),
156+
],
108157
),
109-
],
158+
),
110159
),
111160
),
112161
),

packages/stream_chat_flutter/lib/stream_chat_flutter.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export 'src/message_input/stream_message_send_button.dart';
108108
export 'src/message_input/stream_message_text_field.dart';
109109
export 'src/message_list_view/message_details.dart';
110110
export 'src/message_list_view/message_list_view.dart';
111+
export 'src/message_list_view/unread_indicator_button.dart';
111112
export 'src/message_modal/message_action_confirmation_modal.dart';
112113
export 'src/message_modal/message_actions_modal.dart';
113114
export 'src/message_modal/message_modal.dart';

0 commit comments

Comments
 (0)