import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// {@template streamChannelInfo} /// Displays information about the current [Channel]. /// {@endtemplate} class StreamChannelInfo extends StatelessWidget { /// {@macro streamChannelInfo} const StreamChannelInfo({ super.key, required this.channel, this.textStyle, this.showTypingIndicator = true, this.parentId, }); /// The channel to display information about final Channel channel; /// The style of the text displayed final TextStyle? textStyle; /// Whether to show the typing indicator /// /// Defaults to `true` final bool showTypingIndicator; /// The ID of the parent message (in the case of a thread) final String? parentId; @override Widget build(BuildContext context) { final client = StreamChat.of(context).client; return BetterStreamBuilder>( stream: channel.state!.membersStream, initialData: channel.state!.members, builder: (context, data) => StreamConnectionStatusBuilder( statusBuilder: (context, status) { switch (status) { case ConnectionStatus.connected: return _ConnectedTitleState( channel: channel, showTypingIndicator: showTypingIndicator, textStyle: textStyle, members: data, parentId: parentId, ); case ConnectionStatus.connecting: return _ConnectingTitleState(textStyle: textStyle); case ConnectionStatus.disconnected: return _DisconnectedTitleState( client: client, textStyle: textStyle, ); default: return const Offstage(); } }, ), ); } } class _ConnectedTitleState extends StatelessWidget { const _ConnectedTitleState({ required this.channel, required this.showTypingIndicator, this.members, this.textStyle, this.parentId, }); final Channel channel; final List? members; final TextStyle? textStyle; final bool showTypingIndicator; final String? parentId; @override Widget build(BuildContext context) { Widget? alternativeWidget; final memberCount = channel.memberCount; if (memberCount != null && memberCount > 2) { var text = context.translations.membersCountText(memberCount); final onlineCount = members?.where((m) => m.user?.online == true).length ?? 0; if (onlineCount > 0) { text += ', ${context.translations.watchersCountText(onlineCount)}'; } alternativeWidget = Text( text, style: StreamChannelHeaderTheme.of(context).subtitleStyle, ); } else { final userId = StreamChat.of(context).currentUser?.id; final otherMember = members?.firstWhereOrNull( (element) => element.userId != userId, ); if (otherMember != null) { if (otherMember.user?.online == true) { alternativeWidget = Text( context.translations.userOnlineText, style: textStyle, ); } else { alternativeWidget = Text( '${context.translations.userLastOnlineText} ' '${Jiffy(otherMember.user?.lastActive).fromNow()}', style: textStyle, ); } } } if (!showTypingIndicator) { return alternativeWidget ?? const Offstage(); } return StreamTypingIndicator( parentId: parentId, alternativeWidget: alternativeWidget, style: textStyle, ); } } class _ConnectingTitleState extends StatelessWidget { const _ConnectingTitleState({ this.textStyle, }); final TextStyle? textStyle; @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox( height: 16, width: 16, child: Center( child: CircularProgressIndicator.adaptive(), ), ), const SizedBox(width: 10), Text( context.translations.searchingForNetworkText, style: textStyle, ), ], ); } } class _DisconnectedTitleState extends StatelessWidget { const _DisconnectedTitleState({ required this.client, this.textStyle, }); final StreamChatClient client; final TextStyle? textStyle; @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( context.translations.offlineLabel, style: textStyle, ), TextButton( style: TextButton.styleFrom( padding: EdgeInsets.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity( horizontal: VisualDensity.minimumDensity, vertical: VisualDensity.minimumDensity, ), ), onPressed: () => client ..closeConnection() ..openConnection(), child: Text( context.translations.tryAgainLabel, style: textStyle?.copyWith( color: StreamChatTheme.of(context).colorTheme.accentPrimary, ), ), ), ], ); } }