Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Iterable<StreamComponentBuilderExtension<Object>> streamChatComponentBuilders({
StreamComponentBuilder<MessageComposerInputHeaderProps>? messageComposerInputHeader,
StreamComponentBuilder<MessageComposerInputTrailingProps>? messageComposerInputTrailing,
StreamComponentBuilder<StreamMessageWidgetProps>? messageWidget,
StreamComponentBuilder<UnreadIndicatorProps>? unreadIndicator,
}) {
final builders = [
if (channelListItem != null) StreamComponentBuilderExtension(builder: channelListItem),
Expand All @@ -23,6 +24,7 @@ Iterable<StreamComponentBuilderExtension<Object>> streamChatComponentBuilders({
if (messageComposerInputHeader != null) StreamComponentBuilderExtension(builder: messageComposerInputHeader),
if (messageComposerInputTrailing != null) StreamComponentBuilderExtension(builder: messageComposerInputTrailing),
if (messageWidget != null) StreamComponentBuilderExtension(builder: messageWidget),
if (unreadIndicator != null) StreamComponentBuilderExtension(builder: unreadIndicator),
];

return builders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'package:stream_chat_flutter/src/message_list_view/floating_date_divider.
import 'package:stream_chat_flutter/src/message_list_view/loading_indicator.dart';
import 'package:stream_chat_flutter/src/message_list_view/mlv_utils.dart';
import 'package:stream_chat_flutter/src/message_list_view/thread_separator.dart';
import 'package:stream_chat_flutter/src/message_list_view/unread_indicator_button.dart';
import 'package:stream_chat_flutter/src/message_list_view/unread_messages_separator.dart';
import 'package:stream_chat_flutter/src/message_widget/ephemeral_message.dart';
import 'package:stream_chat_flutter/src/misc/empty_widget.dart';
Expand Down Expand Up @@ -1115,8 +1114,8 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
);

return Positioned(
bottom: 8,
right: 8,
bottom: 16,
right: 16,
width: 40,
height: 40,
child: Stack(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/components/stream_chat_component_builders.dart';
import 'package:stream_chat_flutter/src/misc/empty_widget.dart';
import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/utils/extensions.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_core_flutter/stream_core_flutter.dart';
Expand All @@ -24,6 +24,32 @@ typedef UnreadIndicatorBuilder =
OnUnreadIndicatorDismissTap onDismissTap,
);

/// Properties for configuring an [UnreadIndicatorButton].
///
/// This class holds all the configuration options for an unread indicator,
/// allowing them to be passed through the [StreamComponentFactory].
///
/// See also:
///
/// * [UnreadIndicatorButton], which uses these properties.
class UnreadIndicatorProps {
/// Creates properties for an unread indicator.
const UnreadIndicatorProps({
required this.unreadCount,
required this.onTap,
required this.onDismissTap,
});

/// The number of unread messages.
final int unreadCount;

/// Callback triggered when the indicator is tapped.
final OnUnreadIndicatorTap onTap;

/// Callback triggered when the dismiss button is tapped.
final OnUnreadIndicatorDismissTap onDismissTap;
}

/// {@template unreadIndicatorButton}
/// A button that displays the number of unread messages in a channel.
///
Expand Down Expand Up @@ -52,7 +78,8 @@ class UnreadIndicatorButton extends StatelessWidget {

/// Optional builder for customizing the appearance of the unread indicator.
///
/// If not provided, a default indicator will be built.
/// If not provided, falls back to [StreamComponentFactory], then to the
/// default indicator.
final UnreadIndicatorBuilder? unreadIndicatorBuilder;

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

final props = UnreadIndicatorProps(
unreadCount: unreadCount,
onTap: onTap,
onDismissTap: onDismissTap,
);

if (unreadIndicatorBuilder case final builder?) {
return builder(unreadCount, onTap, onDismissTap);
}

final theme = StreamChatTheme.of(context);
final textTheme = theme.textTheme;
final colorTheme = theme.colorTheme;
final factoryBuilder = context.chatComponentBuilder<UnreadIndicatorProps>();
if (factoryBuilder != null) return factoryBuilder(context, props);

final colorTheme = context.streamColorScheme;
final textTheme = context.streamTextTheme;

return Material(
elevation: 4,
elevation: 3,
clipBehavior: Clip.antiAlias,
color: colorTheme.textLowEmphasis,
color: colorTheme.backgroundElevation1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
borderRadius: BorderRadiusDirectional.all(context.streamRadius.max),
),
child: InkWell(
onTap: () => onTap(currentUserRead.lastReadMessageId),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 2, 8, 2),
child: Row(
children: [
Text(
context.translations.unreadCountIndicatorLabel(
unreadCount: unreadCount,
),
style: textTheme.body.copyWith(color: colorTheme.barsBg),
),
const SizedBox(width: 12),
IconButton(
iconSize: 24,
icon: Icon(context.streamIcons.crossMedium),
padding: const EdgeInsets.all(4),
style: IconButton.styleFrom(
foregroundColor: colorTheme.barsBg,
minimumSize: const Size.square(24),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
onPressed: onDismissTap,
child: SizedBox(
height: 40,
child: InkWell(
onTap: () => onTap(currentUserRead.lastReadMessageId),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 2, 8, 2),
child: IntrinsicHeight(
child: Row(
children: [
Icon(
context.streamIcons.arrowUp,
size: 20,
),
SizedBox(width: context.streamSpacing.xs),
Text(
context.translations.unreadCountIndicatorLabel(
unreadCount: unreadCount,
),
style: textTheme.bodyEmphasis.copyWith(color: colorTheme.textSecondary),
),
SizedBox(width: context.streamSpacing.md),
VerticalDivider(
color: colorTheme.borderDefault,
thickness: 1,
),
IconButton(
iconSize: 20,
icon: Icon(context.streamIcons.crossMedium),
padding: const EdgeInsets.all(5),
style: IconButton.styleFrom(
foregroundColor: colorTheme.textSecondary,
minimumSize: const Size.square(20),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
onPressed: onDismissTap,
),
],
),
],
),
),
),
),
Expand Down
1 change: 1 addition & 0 deletions packages/stream_chat_flutter/lib/stream_chat_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export 'src/message_input/stream_message_send_button.dart';
export 'src/message_input/stream_message_text_field.dart';
export 'src/message_list_view/message_details.dart';
export 'src/message_list_view/message_list_view.dart';
export 'src/message_list_view/unread_indicator_button.dart';
export 'src/message_modal/message_action_confirmation_modal.dart';
export 'src/message_modal/message_actions_modal.dart';
export 'src/message_modal/message_modal.dart';
Expand Down
Loading