200 lines
5.4 KiB
Dart
200 lines
5.4 KiB
Dart
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<List<Member>>(
|
|
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<Member>? 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,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|