Merge remote-tracking branch 'origin/develop' into v7.0.0

# Conflicts:
#	packages/stream_chat/CHANGELOG.md
#	packages/stream_chat_flutter/CHANGELOG.md
#	packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart
#	packages/stream_chat_flutter_core/CHANGELOG.md
This commit is contained in:
Sahil Kumar
2023-09-07 16:19:20 +05:30
19 changed files with 192 additions and 138 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
name: Publish docusaurus docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Node 16
uses: actions/setup-node@v3
with:
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Git Checkout"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
+5 -5
View File
@@ -23,7 +23,7 @@ jobs:
stream_chat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
id: analysis
with:
@@ -43,7 +43,7 @@ jobs:
stream_chat_persistence:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
id: analysis
with:
@@ -64,7 +64,7 @@ jobs:
stream_chat_flutter_core:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
id: analysis
with:
@@ -84,7 +84,7 @@ jobs:
stream_chat_flutter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
id: analysis
with:
@@ -104,7 +104,7 @@ jobs:
stream_chat_localizations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
id: analysis
with:
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Git Checkout"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: "Install Flutter"
@@ -57,7 +57,7 @@ jobs:
timeout-minutes: 15
steps:
- name: "Git Checkout"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: "Install Flutter"
@@ -82,7 +82,7 @@ jobs:
timeout-minutes: 30
steps:
- name: "Git Checkout"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: "Install Flutter"
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
name: Vale doc linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: errata-ai/vale-action@reviewdog
with:
# added, diff_context, file, nofilter
+7
View File
@@ -1,3 +1,10 @@
## Upcoming
🐞 Fixed
- [[#1716]](https://github.com/GetStream/stream-chat-flutter/issues/1716) Fixed client not able to
update message with `type: reply`.
## 7.0.0-beta.3
- Included the changes from version [6.8.0](#670).
@@ -87,8 +87,16 @@ class Message extends Equatable {
final MessageState state;
/// The message type.
@JsonKey(includeIfNull: false, toJson: _typeToJson)
final String type;
// We need to skip passing type if it's not regular or system as the API
// does not expect it.
static String? _typeToJson(String type) {
if (['regular', 'system'].contains(type)) return type;
return null;
}
/// The list of attachments, either provided by the user or generated from a
/// command or as a result of URL scraping.
@JsonKey(includeIfNull: false)
@@ -71,17 +71,27 @@ Message _$MessageFromJson(Map<String, dynamic> json) => Message(
),
);
Map<String, dynamic> _$MessageToJson(Message instance) => <String, dynamic>{
'id': instance.id,
'text': instance.text,
'type': instance.type,
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
'mentioned_users': User.toIds(instance.mentionedUsers),
'parent_id': instance.parentId,
'quoted_message_id': instance.quotedMessageId,
'show_in_channel': instance.showInChannel,
'silent': instance.silent,
'pinned': instance.pinned,
'pin_expires': instance.pinExpires?.toIso8601String(),
'extra_data': instance.extraData,
};
Map<String, dynamic> _$MessageToJson(Message instance) {
final val = <String, dynamic>{
'id': instance.id,
'text': instance.text,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('type', Message._typeToJson(instance.type));
val['attachments'] = instance.attachments.map((e) => e.toJson()).toList();
val['mentioned_users'] = User.toIds(instance.mentionedUsers);
val['parent_id'] = instance.parentId;
val['quoted_message_id'] = instance.quotedMessageId;
val['show_in_channel'] = instance.showInChannel;
val['silent'] = instance.silent;
val['pinned'] = instance.pinned;
val['pin_expires'] = instance.pinExpires?.toIso8601String();
val['extra_data'] = instance.extraData;
return val;
}
+10 -1
View File
@@ -1,3 +1,11 @@
## Upcoming
✅ Added
- Added support for overriding the `MessageWidget.onReactionsHover` callback.
> **Note**
> Used only in desktop devices (web and desktop).
## 7.0.0-beta.4
- Included the changes from version [6.9.0](#681).
@@ -18,7 +26,8 @@
- Added support for listening error events in AttachmentPickerBottomSheet.
- Added support for overriding the `MessageWidget.onReactionTap` callback.
- Added support for `StreamMessageInput.contentInsertionConfiguration` to specify the content insertion configuration.
- Added support for `StreamMessageInput.contentInsertionConfiguration` to specify the content
insertion configuration.
[#1613](https://github.com/GetStream/stream-chat-flutter/issues/1613)
```dart
@@ -159,7 +159,6 @@
C4CD72858CD59598795BB48E /* Pods-Runner.release.xcconfig */,
2BCA7399119839DE435DACD6 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@@ -203,7 +202,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
@@ -427,7 +426,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
@@ -554,7 +553,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -575,7 +574,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -55,6 +55,7 @@ class StreamMessageWidget extends StatefulWidget {
this.onMentionTap,
this.onMessageTap,
this.onReactionsTap,
this.onReactionsHover,
this.showReactionPicker = true,
@internal this.showReactionPickerTail = false,
this.showUserAvatar = DisplayWidget.show,
@@ -486,8 +487,16 @@ class StreamMessageWidget extends StatefulWidget {
final void Function(Message)? onMessageTap;
/// {@macro onReactionsTap}
///
/// Note: Only used in mobile devices (iOS and Android). Do not confuse this
/// with the tap action on the reactions picker.
final OnReactionsTap? onReactionsTap;
/// {@template onReactionsHover}
///
/// Note: Only used in desktop devices (web and desktop).
final OnReactionsHover? onReactionsHover;
/// {@template customActions}
/// List of custom actions shown on message long tap
/// {@endtemplate}
@@ -547,6 +556,7 @@ class StreamMessageWidget extends StatefulWidget {
bool? showInChannelIndicator,
void Function(User)? onUserAvatarTap,
void Function(String)? onLinkTap,
bool? showReactionBrowser,
bool? showReactionPicker,
@internal bool? showReactionPickerTail,
List<Read>? readList,
@@ -567,6 +577,7 @@ class StreamMessageWidget extends StatefulWidget {
OnQuotedMessageTap? onQuotedMessageTap,
void Function(Message)? onMessageTap,
OnReactionsTap? onReactionsTap,
OnReactionsHover? onReactionsHover,
List<StreamMessageAction>? customActions,
void Function(Message message, Attachment attachment)? onAttachmentTap,
Widget Function(BuildContext, User)? userAvatarBuilder,
@@ -629,6 +640,7 @@ class StreamMessageWidget extends StatefulWidget {
onQuotedMessageTap: onQuotedMessageTap ?? this.onQuotedMessageTap,
onMessageTap: onMessageTap ?? this.onMessageTap,
onReactionsTap: onReactionsTap ?? this.onReactionsTap,
onReactionsHover: onReactionsHover ?? this.onReactionsHover,
customActions: customActions ?? this.customActions,
onAttachmentTap: onAttachmentTap ?? this.onAttachmentTap,
userAvatarBuilder: userAvatarBuilder ?? this.userAvatarBuilder,
@@ -839,7 +851,6 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
reverse: widget.reverse,
message: widget.message,
hasNonUrlAttachments: hasNonUrlAttachments,
shouldShowReactions: shouldShowReactions,
hasQuotedMessage: hasQuotedMessage,
textPadding: widget.textPadding,
attachmentBuilders: widget.attachmentBuilders,
@@ -864,6 +875,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
? widget.onReactionsTap!(widget.message)
: _showMessageReactionsModal(context);
},
onReactionsHover: widget.onReactionsHover,
showUserAvatar: widget.showUserAvatar,
streamChat: _streamChat,
translateUserAvatar: widget.translateUserAvatar,
@@ -1125,7 +1137,8 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
translateUserAvatar: false,
showSendingIndicator: false,
padding: EdgeInsets.zero,
// Show both the tail and indicator if the indicator is shown.
// Show both the tail if the picker is shown.
showReactionPicker: widget.showReactionPicker,
showReactionPickerTail: widget.showReactionPicker,
showPinHighlight: false,
showUserAvatar: widget.message.user!.id ==
@@ -37,8 +37,8 @@ class MessageWidgetContent extends StatelessWidget {
required this.avatarWidth,
required this.showReactions,
required this.onReactionsTap,
required this.onReactionsHover,
required this.messageTheme,
required this.shouldShowReactions,
required this.streamChatTheme,
required this.isFailedState,
required this.hasQuotedMessage,
@@ -101,17 +101,15 @@ class MessageWidgetContent extends StatelessWidget {
/// {@macro showReactions}
final bool showReactions;
/// Callback called when the reactions icon is tapped.
///
/// Do not confuse this with the tap action on the reactions picker.
/// {@macro onReactionsTap}
final VoidCallback onReactionsTap;
/// {@macro onReactionsHover}
final OnReactionsHover? onReactionsHover;
/// {@macro messageTheme}
final StreamMessageThemeData messageTheme;
/// {@macro shouldShowReactions}
final bool shouldShowReactions;
/// {@macro onUserAvatarTap}
final void Function(User)? onUserAvatarTap;
@@ -285,7 +283,6 @@ class MessageWidgetContent extends StatelessWidget {
messageTheme: messageTheme,
ownId: streamChat.currentUser!.id,
reverse: reverse,
shouldShowReactions: shouldShowReactions,
onTap: onReactionsTap,
)
: null,
@@ -304,25 +301,15 @@ class MessageWidgetContent extends StatelessWidget {
children: [
Padding(
padding: showReactions
? EdgeInsets.only(
top: message.reactionCounts
?.isNotEmpty ==
true
? 18
: 0,
)
? const EdgeInsets.only(top: 18)
: EdgeInsets.zero,
child: (message.isDeleted && !isFailedState)
? Container(
// ignore: lines_longer_than_80_chars
margin: EdgeInsets.symmetric(
horizontal:
// ignore: lines_longer_than_80_chars
showUserAvatar ==
// ignore: lines_longer_than_80_chars
DisplayWidget.gone
? 0
: 4.0,
horizontal: showUserAvatar ==
DisplayWidget.gone
? 0
: 4.0,
),
child: StreamDeletedMessage(
borderRadiusGeometry:
@@ -401,7 +388,7 @@ class MessageWidgetContent extends StatelessWidget {
SizedBox(width: avatarWidth + 4),
],
),
if (isDesktopDeviceOrWeb && shouldShowReactions) ...[
if (isDesktopDeviceOrWeb && showReactions) ...[
Padding(
padding: showUserAvatar != DisplayWidget.gone
? EdgeInsets.only(
@@ -412,7 +399,7 @@ class MessageWidgetContent extends StatelessWidget {
child: DesktopReactionsBuilder(
message: message,
messageTheme: messageTheme,
shouldShowReactions: shouldShowReactions,
onHover: onReactionsHover,
borderSide: borderSide,
reverse: reverse,
),
@@ -1,3 +1,5 @@
// ignore_for_file: cascade_invocations
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -5,8 +7,6 @@ import 'package:flutter_portal/flutter_portal.dart';
import 'package:stream_chat_flutter/src/message_widget/reactions/reactions_card.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
// ignore_for_file: cascade_invocations
/// {@template desktopReactionsBuilder}
/// Builds a list of reactions to a message on desktop & web.
///
@@ -16,16 +16,13 @@ class DesktopReactionsBuilder extends StatefulWidget {
/// {@macro desktopReactionsBuilder}
const DesktopReactionsBuilder({
super.key,
required this.shouldShowReactions,
required this.message,
required this.messageTheme,
this.onHover,
this.borderSide,
required this.reverse,
});
/// Whether reactions should be shown.
final bool shouldShowReactions;
/// The message to show reactions for.
final Message message;
@@ -35,6 +32,9 @@ class DesktopReactionsBuilder extends StatefulWidget {
/// reactions matches the design spec for messages.
final StreamMessageThemeData messageTheme;
/// Callback to run when the mouse enters or exits the reactions.
final OnReactionsHover? onHover;
/// {@macro borderSide}
final BorderSide? borderSide;
@@ -48,12 +48,6 @@ class DesktopReactionsBuilder extends StatefulWidget {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(
DiagnosticsProperty<bool>(
'shouldShowReactions',
shouldShowReactions,
),
);
properties.add(
DiagnosticsProperty<Message>('message', message),
);
@@ -81,18 +75,15 @@ class _DesktopReactionsBuilderState extends State<DesktopReactionsBuilder> {
final streamChatTheme = StreamChatTheme.of(context);
final reactionsMap = <String, Reaction>{};
var reactionsList = <Reaction>[];
if (widget.shouldShowReactions) {
widget.message.latestReactions?.forEach((element) {
if (!reactionsMap.containsKey(element.type) ||
element.user!.id == currentUser.id) {
reactionsMap[element.type] = element;
}
});
widget.message.latestReactions?.forEach((element) {
if (!reactionsMap.containsKey(element.type) ||
element.user!.id == currentUser.id) {
reactionsMap[element.type] = element;
}
});
reactionsList = reactionsMap.values.toList()
..sort((a, b) => a.user!.id == currentUser.id ? 1 : -1);
}
final reactionsList = reactionsMap.values.toList()
..sort((a, b) => a.user!.id == currentUser.id ? 1 : -1);
return PortalTarget(
visible: _showReactionsPopup,
@@ -100,17 +91,11 @@ class _DesktopReactionsBuilderState extends State<DesktopReactionsBuilder> {
anchor: Aligned(
target: widget.reverse ? Alignment.topRight : Alignment.topLeft,
follower: widget.reverse ? Alignment.bottomRight : Alignment.bottomLeft,
shiftToWithinBound: const AxisFlag(
y: true,
),
shiftToWithinBound: const AxisFlag(y: true),
),
portalFollower: MouseRegion(
onEnter: (event) async {
setState(() => _showReactionsPopup = !_showReactionsPopup);
},
onExit: (event) {
setState(() => _showReactionsPopup = !_showReactionsPopup);
},
onEnter: (_) => _onReactionsHover(true),
onExit: (_) => _onReactionsHover(false),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 336,
@@ -125,12 +110,8 @@ class _DesktopReactionsBuilderState extends State<DesktopReactionsBuilder> {
),
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (event) async {
setState(() => _showReactionsPopup = !_showReactionsPopup);
},
onExit: (event) {
setState(() => _showReactionsPopup = !_showReactionsPopup);
},
onEnter: (_) => _onReactionsHover(true),
onExit: (_) => _onReactionsHover(false),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 2,
@@ -161,6 +142,14 @@ class _DesktopReactionsBuilderState extends State<DesktopReactionsBuilder> {
),
);
}
void _onReactionsHover(bool isHovering) {
if (widget.onHover != null) {
return widget.onHover!(isHovering);
}
setState(() => _showReactionsPopup = isHovering);
}
}
class _BottomReaction extends StatelessWidget {
@@ -13,7 +13,6 @@ class ReactionIndicator extends StatelessWidget {
super.key,
required this.ownId,
required this.message,
required this.shouldShowReactions,
required this.onTap,
required this.reverse,
required this.messageTheme,
@@ -25,9 +24,6 @@ class ReactionIndicator extends StatelessWidget {
/// {@macro message}
final Message message;
/// {@macro shouldShowReactions}
final bool shouldShowReactions;
/// The callback to perform when the widget is tapped or clicked.
final VoidCallback onTap;
@@ -50,34 +46,27 @@ class ReactionIndicator extends StatelessWidget {
..sort((a, b) => a.user!.id == ownId ? 1 : -1);
return Transform(
transform: Matrix4.translationValues(
reverse ? 12 : -12,
0,
0,
),
transform: Matrix4.translationValues(reverse ? 12 : -12, 0, 0),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 22 * 6.0,
),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: shouldShowReactions
? GestureDetector(
onTap: onTap,
child: StreamReactionBubble(
key: ValueKey('${message.id}.reactions'),
reverse: reverse,
flipTail: reverse,
backgroundColor: messageTheme.reactionsBackgroundColor ??
Colors.transparent,
borderColor:
messageTheme.reactionsBorderColor ?? Colors.transparent,
maskColor:
messageTheme.reactionsMaskColor ?? Colors.transparent,
reactions: reactionsList,
),
)
: const SizedBox(),
child: GestureDetector(
onTap: onTap,
child: StreamReactionBubble(
key: ValueKey('${message.id}.reactions'),
reverse: reverse,
flipTail: reverse,
backgroundColor:
messageTheme.reactionsBackgroundColor ?? Colors.transparent,
borderColor:
messageTheme.reactionsBorderColor ?? Colors.transparent,
maskColor: messageTheme.reactionsMaskColor ?? Colors.transparent,
reactions: reactionsList,
),
),
),
),
);
@@ -217,6 +217,12 @@ typedef OnMessageTap = void Function(Message);
/// {@endtemplate}
typedef OnReactionsTap = void Function(Message);
/// {@template onReactionsHover}
/// The action to perform when a message's reactions are hovered.
/// {@endtemplate}
// ignore: avoid_positional_boolean_parameters
typedef OnReactionsHover = void Function(bool isHovering);
/// {@template messageSearchItemTapCallback}
/// The action to perform when tapping or clicking on a user in a
/// [MessageSearchListView].
+11 -3
View File
@@ -1,3 +1,8 @@
## Upcoming
- Added support for `StreamChannel.loadingBuilder` and `StreamChannel.errorBuilder` to customize
loading and error states.
## 7.0.0-beta.3
- Updated minimum supported `SDK` version to Flutter 3.13/Dart 3.1
@@ -50,9 +55,11 @@
- Updated `dart` sdk environment range to support `3.0.0`.
- Updated `stream_chat` dependency to [`6.1.0`](https://pub.dev/packages/stream_chat/changelog).
- [[#1356]](https://github.com/GetStream/stream-chat-flutter/issues/1356) Channel doesn't auto display again after being
- [[#1356]](https://github.com/GetStream/stream-chat-flutter/issues/1356) Channel doesn't auto
display again after being
hidden.
- [[#1540]](https://github.com/GetStream/stream-chat-flutter/issues/1540) Use `CircularProgressIndicator.adaptive`
- [[#1540]](https://github.com/GetStream/stream-chat-flutter/issues/1540)
Use `CircularProgressIndicator.adaptive`
instead of material indicator.
## 6.0.0
@@ -71,7 +78,8 @@
## 5.1.0
- Deprecated the `sort` parameter in the `StreamChannelListController` in favor of `channelStateSort`.
- Deprecated the `sort` parameter in the `StreamChannelListController` in favor
of `channelStateSort`.
## 5.0.0
@@ -15,6 +15,15 @@ enum QueryDirection {
bottom,
}
/// Signature used by [StreamChannel.errorBuilder] to create a replacement
/// widget for an error that occurs while asynchronously building the channel.
// TODO: Remove once ErrorBuilder supports passing stacktrace.
typedef ErrorWidgetBuilder = Widget Function(
BuildContext context,
Object error,
StackTrace? stackTrace,
);
/// Widget used to provide information about the channel to the widget tree
///
/// Use [StreamChannel.of] to get the current [StreamChannelState] instance.
@@ -27,6 +36,8 @@ class StreamChannel extends StatefulWidget {
required this.channel,
this.showLoading = true,
this.initialMessageId,
this.errorBuilder = _defaultErrorBuilder,
this.loadingBuilder = _defaultLoadingBuilder,
});
/// The child of the widget
@@ -41,6 +52,31 @@ class StreamChannel extends StatefulWidget {
/// If passed the channel will load from this particular message.
final String? initialMessageId;
/// Widget builder used in case the channel is initialising.
final WidgetBuilder loadingBuilder;
/// Widget builder used in case an error occurs while building the channel.
final ErrorWidgetBuilder errorBuilder;
static Widget _defaultLoadingBuilder(BuildContext context) {
return const Center(child: CircularProgressIndicator.adaptive());
}
static Widget _defaultErrorBuilder(
BuildContext context,
Object error,
StackTrace? stackTrace,
) {
if (error is DioException) {
if (error.type == DioExceptionType.badResponse) {
return Center(child: Text(error.message ?? 'Bad response'));
}
return const Center(child: Text('Check your connection and retry'));
}
return Center(child: Text(error.toString()));
}
/// Use this method to get the current [StreamChannelState] instance
static StreamChannelState of(BuildContext context) {
StreamChannelState? streamChannelState;
@@ -430,22 +466,14 @@ class StreamChannelState extends State<StreamChannel> {
],
builder: (context, snapshot) {
if (snapshot.hasError) {
final error = snapshot.error;
if (error is DioException) {
if (error.type == DioExceptionType.badResponse) {
return Center(child: Text(error.message ?? 'Bad response'));
}
return const Center(child: Text('Check your connection and retry'));
}
return Center(child: Text(error.toString()));
final error = snapshot.error!;
final stackTrace = snapshot.stackTrace;
return widget.errorBuilder(context, error, stackTrace);
}
final dataLoaded = snapshot.data?.every((it) => it) == true;
if (widget.showLoading && !dataLoaded) {
return const Center(
child: CircularProgressIndicator.adaptive(),
);
return widget.loadingBuilder(context);
}
return widget.child;
},
@@ -4,6 +4,7 @@ import 'package:stream_chat/stream_chat.dart';
/// A signature for a callback which exposes an error and returns a function.
/// This Callback can be used in cases where an API failure occurs and the
/// widget is unable to render data.
// TODO: Add stacktrace as a parameter in v7.0.0
typedef ErrorBuilder = Widget Function(BuildContext context, Object error);
/// A Signature for a handler function which will expose a [event].