diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 410fec6b11..b936a4a1a1 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -6,6 +6,8 @@ `StreamComponentFactory.jumpToUnreadButton` instead. - Renamed `UnreadIndicatorButton.onTap` → `onJumpTap`. - Renamed stream icons to remove the size suffix from the icon names. +- Removed `StreamMessageThemeData` (ownMessageTheme and otherMessageTheme) and `StreamMessageInputThemeData` (messageInputTheme). +- Removed `AttachmentButton`, `StreamQuotedMessageWidget`, `EditMessageSheet`, `StreamMessageSendButton` and `DesktopReactionsBuilder`. ✅ Added diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart index 7ef017dacf..9d4bbe7a52 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart @@ -60,7 +60,6 @@ class MyApp extends StatelessWidget { ), ); final defaultTheme = StreamChatThemeData.fromTheme(themeData); - final colorTheme = defaultTheme.colorTheme; final customTheme = StreamChatThemeData( channelPreviewTheme: StreamChannelPreviewThemeData( avatarTheme: StreamAvatarThemeData( @@ -74,19 +73,6 @@ class MyApp extends StatelessWidget { fit: BoxFit.cover, ), ), - ownMessageTheme: const StreamMessageThemeData( - urlAttachmentTitleMaxLine: 1, - ), - otherMessageTheme: StreamMessageThemeData( - messageBackgroundColor: colorTheme.textHighEmphasis, - messageTextStyle: TextStyle( - color: colorTheme.barsBg, - ), - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(8), - ), - urlAttachmentTitleMaxLine: 1, - ), ).merge(defaultTheme); return MaterialApp( diff --git a/packages/stream_chat_flutter/lib/src/bottom_sheets/edit_message_sheet.dart b/packages/stream_chat_flutter/lib/src/bottom_sheets/edit_message_sheet.dart deleted file mode 100644 index c42baa1d6e..0000000000 --- a/packages/stream_chat_flutter/lib/src/bottom_sheets/edit_message_sheet.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// {@template showEditMessageSheet} -/// Displays an interactive modal bottom sheet to edit a message. -/// {@endtemplate} -Future showEditMessageSheet({ - required BuildContext context, - required Message message, - required Channel channel, - EditMessageInputBuilder? editMessageInputBuilder, -}) { - final messageInputTheme = StreamMessageInputTheme.of(context); - - return showModalBottomSheet( - context: context, - elevation: 2, - isScrollControlled: true, - clipBehavior: Clip.antiAlias, - backgroundColor: messageInputTheme.inputBackgroundColor, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - ), - ), - builder: (context) => EditMessageSheet( - channel: channel, - message: message, - editMessageInputBuilder: editMessageInputBuilder, - ), - ); -} - -/// {@template editMessageSheet} -/// Allows a user to edit the selected message. -/// {@endtemplate} -class EditMessageSheet extends StatefulWidget { - /// {@macro editMessageSheet} - const EditMessageSheet({ - super.key, - required this.message, - required this.channel, - this.editMessageInputBuilder, - }); - - /// {@macro editMessageInputBuilder} - final EditMessageInputBuilder? editMessageInputBuilder; - - /// The message to edit. - final Message message; - - /// The [StreamChannel] above this widget. - final Channel channel; - - @override - State createState() => _EditMessageSheetState(); -} - -class _EditMessageSheetState extends State { - late final controller = StreamMessageInputController( - message: widget.message, - ); - - @override - void dispose() { - controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final streamChatThemeData = StreamChatTheme.of(context); - return KeyboardShortcutRunner( - onEscapeKeypress: () => Navigator.of(context).pop(), - child: Padding( - padding: MediaQuery.of(context).viewInsets, - child: StreamChannel( - channel: widget.channel, - child: Flex( - direction: Axis.vertical, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(8), - child: Icon( - context.streamIcons.edit, - color: streamChatThemeData.colorTheme.disabled, - ), - ), - Text( - context.translations.editMessageLabel, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - IconButton( - visualDensity: VisualDensity.compact, - icon: Icon( - context.streamIcons.xmark, - color: streamChatThemeData.colorTheme.textLowEmphasis, - ), - onPressed: Navigator.of(context).pop, - ), - ], - ), - ), - if (widget.editMessageInputBuilder != null) - widget.editMessageInputBuilder!(context, widget.message) - else - StreamMessageInput( - messageInputController: controller, - preMessageSending: (m) { - FocusScope.of(context).unfocus(); - Navigator.of(context).pop(); - return m; - }, - ), - ], - ), - ), - ), - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_button.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_button.dart deleted file mode 100644 index 10b825731f..0000000000 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_button.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/message_input/stream_message_input_icon_button.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// {@template attachmentButton} -/// A button for adding attachments to a chat on mobile. -/// {@endtemplate} -class AttachmentButton extends StatelessWidget { - /// {@macro attachmentButton} - const AttachmentButton({ - super.key, - required this.onPressed, - this.color, - this.icon, - this.size = kDefaultMessageInputIconSize, - }); - - /// The color of the button. - /// Should be set if no [icon] is provided. - final Color? color; - - /// The callback to perform when the button is tapped or clicked. - final VoidCallback onPressed; - - /// The icon to display inside the button. - /// if not provided, a default icon will be used - /// and [color] property should be set. - final Widget? icon; - - /// The size of the button and splash radius. - final double size; - - /// Returns a copy of this object with the given fields updated. - AttachmentButton copyWith({ - Key? key, - Color? color, - VoidCallback? onPressed, - Widget? icon, - double? size, - }) { - return AttachmentButton( - key: key ?? this.key, - color: color ?? this.color, - onPressed: onPressed ?? this.onPressed, - icon: icon ?? this.icon, - size: size ?? this.size, - ); - } - - @override - Widget build(BuildContext context) { - return StreamMessageInputIconButton( - color: color, - iconSize: size, - onPressed: onPressed, - icon: icon ?? Icon(context.streamIcons.attachment), - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_image_picker.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_image_picker.dart index 7c78ef20ed..83e3e07cf5 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_image_picker.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_image_picker.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; /// Widget used to pick images from the device. class StreamImagePicker extends StatelessWidget { diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_poll_creator.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_poll_creator.dart index 2d6fd841ea..81a2c40acb 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_poll_creator.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_poll_creator.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; /// Widget used to create a poll. class StreamPollCreator extends StatelessWidget { diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_video_picker.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_video_picker.dart index 409b19fb3a..f45754ecca 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_video_picker.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/options/stream_video_picker.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; /// Widget used to capture video using the device camera. class StreamVideoPicker extends StatelessWidget { diff --git a/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart deleted file mode 100644 index bed4365e5f..0000000000 --- a/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart +++ /dev/null @@ -1,347 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/message_input/clear_input_item_button.dart'; -import 'package:stream_chat_flutter/src/misc/empty_widget.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -typedef _Builders = Map; - -/// {@template streamQuotedMessage} -/// Widget for the quoted message. -/// {@endtemplate} -class StreamQuotedMessageWidget extends StatelessWidget { - /// {@macro streamQuotedMessage} - const StreamQuotedMessageWidget({ - super.key, - required this.message, - required this.messageTheme, - this.reverse = false, - this.showBorder = false, - this.textLimit = 170, - this.textBuilder, - this.attachmentThumbnailBuilders, - this.padding = const EdgeInsets.all(8), - this.onQuotedMessageClear, - }); - - /// The message - final Message message; - - /// The message theme - final StreamMessageThemeData messageTheme; - - /// If true the widget will be mirrored - final bool reverse; - - /// If true the message will show a grey border - final bool showBorder; - - /// limit of the text message shown - final int textLimit; - - /// Map that defines a thumbnail builder for an attachment type - final _Builders? attachmentThumbnailBuilders; - - /// Padding around the widget - final EdgeInsetsGeometry padding; - - /// Callback for clearing quoted messages. - final VoidCallback? onQuotedMessageClear; - - /// {@macro textBuilder} - final Widget Function(BuildContext, Message)? textBuilder; - - @override - Widget build(BuildContext context) { - final children = [ - Flexible( - child: _QuotedMessage( - message: message, - textLimit: textLimit, - messageTheme: messageTheme, - showBorder: showBorder, - reverse: reverse, - textBuilder: textBuilder, - onQuotedMessageClear: onQuotedMessageClear, - attachmentThumbnailBuilders: attachmentThumbnailBuilders, - ), - ), - const SizedBox(width: 8), - if (message.user != null) - StreamUserAvatar( - size: .sm, - user: message.user!, - showOnlineIndicator: false, - ), - ]; - return Padding( - padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: reverse ? children.reversed.toList() : children, - ), - ); - } -} - -class _QuotedMessage extends StatelessWidget { - const _QuotedMessage({ - required this.message, - required this.textLimit, - required this.messageTheme, - required this.showBorder, - required this.reverse, - this.textBuilder, - this.onQuotedMessageClear, - this.attachmentThumbnailBuilders, - }); - - final Message message; - final int textLimit; - final VoidCallback? onQuotedMessageClear; - final StreamMessageThemeData messageTheme; - final bool showBorder; - final bool reverse; - final Widget Function(BuildContext, Message)? textBuilder; - - final _Builders? attachmentThumbnailBuilders; - - bool get _hasAttachments => message.attachments.isNotEmpty; - - bool get _containsText => message.text?.isNotEmpty == true; - - bool get _containsLinkAttachment => message.attachments.any((it) => it.type == AttachmentType.urlPreview); - - bool get _isGiphy => message.attachments.any((element) => element.type == AttachmentType.giphy); - - bool get _isDeleted => message.isDeleted || message.deletedAt != null; - - bool get _isPoll => message.poll != null; - - @override - Widget build(BuildContext context) { - final isOnlyEmoji = message.text!.isOnlyEmoji; - var msg = _hasAttachments && !_containsText - ? message.copyWith(text: message.attachments.last.title ?? '') - : message; - if (msg.text!.length > textLimit) { - msg = msg.copyWith(text: '${msg.text!.substring(0, textLimit - 3)}...'); - } - - List children; - if (_isDeleted) { - // Show deleted message text - children = [ - Text( - context.translations.messageDeletedLabel, - style: messageTheme.messageTextStyle?.copyWith( - fontStyle: FontStyle.italic, - color: messageTheme.createdAtStyle?.color, - ), - ), - ]; - } else if (_isPoll) { - // Show poll message - children = [ - Flexible( - child: Text( - '📊 ${message.poll?.name}', - style: messageTheme.messageTextStyle?.copyWith(fontSize: 12), - ), - ), - ]; - } else if (message.sharedLocation case final location?) { - // Show shared location message - children = [ - Flexible( - child: Text( - context.translations.locationLabel(isLive: location.isLive), - style: messageTheme.messageTextStyle?.copyWith(fontSize: 12), - ), - ), - ]; - } else { - // Show quoted message - children = [ - if (_hasAttachments) - _ParseAttachments( - message: message, - messageTheme: messageTheme, - attachmentThumbnailBuilders: attachmentThumbnailBuilders, - ), - if (msg.text!.isNotEmpty && !_isGiphy) - Flexible( - child: - textBuilder?.call(context, msg) ?? - StreamMarkdownMessage( - data: msg.replaceMentions().text ?? '', - messageTheme: isOnlyEmoji && _containsText - ? messageTheme.copyWith( - messageTextStyle: messageTheme.messageTextStyle?.copyWith( - fontSize: 32, - ), - ) - : messageTheme.copyWith( - messageTextStyle: messageTheme.messageTextStyle?.copyWith( - fontSize: 12, - ), - ), - ), - ), - ]; - } - - // Add clear button if needed. - if (isDesktopDeviceOrWeb && onQuotedMessageClear != null) { - children.insert( - 0, - ClearInputItemButton(onTap: onQuotedMessageClear), - ); - } - - return Container( - decoration: BoxDecoration( - color: _getBackgroundColor(context), - border: showBorder - ? Border.all( - color: StreamChatTheme.of(context).colorTheme.disabled, - ) - : null, - borderRadius: BorderRadius.only( - topRight: const Radius.circular(12), - topLeft: const Radius.circular(12), - bottomRight: reverse ? const Radius.circular(12) : Radius.zero, - bottomLeft: reverse ? Radius.zero : const Radius.circular(12), - ), - ), - padding: const EdgeInsets.all(8), - child: Row( - spacing: 8, - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: reverse ? MainAxisAlignment.end : MainAxisAlignment.start, - children: reverse ? children.reversed.toList() : children, - ), - ); - } - - Color? _getBackgroundColor(BuildContext context) { - if (_containsLinkAttachment && !_isDeleted) { - return messageTheme.urlAttachmentBackgroundColor; - } - return messageTheme.messageBackgroundColor; - } -} - -class _ParseAttachments extends StatelessWidget { - const _ParseAttachments({ - required this.message, - required this.messageTheme, - this.attachmentThumbnailBuilders, - }); - - final Message message; - final StreamMessageThemeData messageTheme; - final _Builders? attachmentThumbnailBuilders; - - @override - Widget build(BuildContext context) { - final attachment = message.attachments.first; - - var attachmentBuilders = attachmentThumbnailBuilders; - attachmentBuilders ??= _createDefaultAttachmentBuilders(); - - // Build the attachment widget using the builder for the attachment type. - final attachmentWidget = attachmentBuilders[attachment.type]?.call( - context, - attachment, - ); - - // Return empty container if no attachment widget is returned. - if (attachmentWidget == null) return const Empty(); - - final colorTheme = StreamChatTheme.of(context).colorTheme; - - var clipBehavior = Clip.none; - ShapeDecoration? decoration; - if (attachment.type != AttachmentType.file && attachment.type != AttachmentType.voiceRecording) { - clipBehavior = Clip.hardEdge; - decoration = ShapeDecoration( - shape: RoundedRectangleBorder( - side: BorderSide( - color: colorTheme.borders, - strokeAlign: BorderSide.strokeAlignOutside, - ), - borderRadius: BorderRadius.circular(8), - ), - ); - } - - return Container( - key: Key(attachment.id), - clipBehavior: clipBehavior, - decoration: decoration, - constraints: const BoxConstraints.tightFor(width: 36, height: 36), - child: AbsorbPointer(child: attachmentWidget), - ); - } - - _Builders _createDefaultAttachmentBuilders() { - Widget _createMediaThumbnail(BuildContext context, Attachment media) { - return StreamImageAttachmentThumbnail( - image: media, - width: double.infinity, - height: double.infinity, - fit: BoxFit.cover, - ); - } - - Widget _createUrlThumbnail(BuildContext context, Attachment media) { - return StreamImageAttachmentThumbnail( - image: media, - width: double.infinity, - height: double.infinity, - fit: BoxFit.cover, - ); - } - - Widget _createFileThumbnail(BuildContext context, Attachment file) { - Widget thumbnail = StreamFileAttachmentThumbnail( - file: file, - width: double.infinity, - height: double.infinity, - fit: BoxFit.cover, - ); - - final mediaType = file.title?.mediaType; - final isImage = mediaType?.type == AttachmentType.image; - final isVideo = mediaType?.type == AttachmentType.video; - if (isImage || isVideo) { - final colorTheme = StreamChatTheme.of(context).colorTheme; - thumbnail = Container( - clipBehavior: Clip.hardEdge, - decoration: ShapeDecoration( - shape: RoundedRectangleBorder( - side: BorderSide( - color: colorTheme.borders, - strokeAlign: BorderSide.strokeAlignOutside, - ), - borderRadius: BorderRadius.circular(8), - ), - ), - child: thumbnail, - ); - } - - return thumbnail; - } - - return { - AttachmentType.image: _createMediaThumbnail, - AttachmentType.giphy: _createMediaThumbnail, - AttachmentType.video: _createMediaThumbnail, - AttachmentType.urlPreview: _createUrlThumbnail, - AttachmentType.file: _createFileThumbnail, - AttachmentType.voiceRecording: _createFileThumbnail, - }; - } -} diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart index 99700ad989..0f928fcb18 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart @@ -364,7 +364,6 @@ class StreamMessageInputState extends State late final CurvedAnimation _pickerAnimation; late StreamChatThemeData _streamChatTheme; - late StreamMessageInputThemeData _messageInputTheme; bool get _isEditing => !_effectiveController.message.state.isInitial; @@ -495,7 +494,6 @@ class StreamMessageInputState extends State @override void didChangeDependencies() { _streamChatTheme = StreamChatTheme.of(context); - _messageInputTheme = StreamMessageInputTheme.of(context); super.didChangeDependencies(); } @@ -587,7 +585,7 @@ class StreamMessageInputState extends State }; final spacing = context.streamSpacing; - final safeAreaEnabled = widget.enableSafeArea ?? _messageInputTheme.enableSafeArea ?? true; + final safeAreaEnabled = widget.enableSafeArea ?? true; final viewPadding = MediaQuery.paddingOf(context); return Material( @@ -745,13 +743,11 @@ class StreamMessageInputState extends State final allowedTypes = _getAllowedAttachmentPickerTypes(); - final messageInputTheme = StreamMessageInputTheme.of(context); final isWebOrDesktop = switch (CurrentPlatform.type) { PlatformType.android || PlatformType.ios => false, _ => true, }; - final useSystemPicker = - widget.useSystemAttachmentPicker || (messageInputTheme.useSystemAttachmentPicker ?? false) || isWebOrDesktop; + final useSystemPicker = widget.useSystemAttachmentPicker || isWebOrDesktop; final child = useSystemPicker ? systemAttachmentPickerBuilder( @@ -794,7 +790,7 @@ class StreamMessageInputState extends State padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 15), child: Text( context.translations.sendMessagePermissionError, - style: _messageInputTheme.inputTextStyle, + style: context.streamTextInputTheme.style?.textStyle, ), ); } diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_send_button.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_send_button.dart deleted file mode 100644 index 1461251bb7..0000000000 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_send_button.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/message_input/stream_message_input_icon_button.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// A widget that displays a sending button. -class StreamMessageSendButton extends StatelessWidget { - /// Returns a [StreamMessageSendButton] with the given [timeOut], [isIdle], - /// [isCommandEnabled], [isEditEnabled], [idleSendButton], [activeSendButton], - /// [onSendMessage]. - const StreamMessageSendButton({ - super.key, - this.timeOut = 0, - this.isIdle = true, - this.idleSendIcon, - this.activeSendIcon, - required this.onSendMessage, - }); - - /// Time out related to slow mode. - final int timeOut; - - /// If true the button will be disabled. - final bool isIdle; - - /// The icon to display when the button is idle. - final Widget? idleSendIcon; - - /// The icon to display when the button is active. - final Widget? activeSendIcon; - - /// The callback to call when the button is pressed. - final VoidCallback onSendMessage; - - @override - Widget build(BuildContext context) { - final theme = StreamMessageInputTheme.of(context); - - final button = _buildButton(context); - return AnimatedSwitcher( - duration: theme.sendAnimationDuration!, - child: button, - ); - } - - Widget _buildButton(BuildContext context) { - if (timeOut > 0) { - return StreamCountdownButton( - key: const Key('countdown_button'), - count: timeOut, - ); - } - - final idleIcon = switch (idleSendIcon) { - final idleIcon? => idleIcon, - _ => Icon(context.streamIcons.send), - }; - - final activeIcon = switch (activeSendIcon) { - final activeIcon? => activeIcon, - _ => Icon(context.streamIcons.arrowUp), - }; - - final theme = StreamMessageInputTheme.of(context); - final icon = isIdle ? idleIcon : activeIcon; - final onPressed = isIdle ? null : onSendMessage; - return StreamMessageInputIconButton( - key: const Key('send_button'), - icon: icon, - color: theme.sendButtonColor, - disabledColor: theme.sendButtonIdleColor, - onPressed: onPressed, - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart index 3662c9f382..ee6626c64d 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart @@ -325,9 +325,6 @@ class StreamMessageWidgetProps { final void Function(BuildContext context, Message message)? onBouncedErrorMessageActions; /// Called when the edit-message action is selected. - /// - /// When provided, this callback replaces the default behaviour of showing - /// the edit-message bottom sheet via [showEditMessageSheet]. final void Function(Message message)? onEditMessageTap; /// Custom attachment builders for rendering message attachments. diff --git a/packages/stream_chat_flutter/lib/src/misc/markdown_message.dart b/packages/stream_chat_flutter/lib/src/misc/markdown_message.dart index 5977692118..5b908cd866 100644 --- a/packages/stream_chat_flutter/lib/src/misc/markdown_message.dart +++ b/packages/stream_chat_flutter/lib/src/misc/markdown_message.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:stream_chat_flutter/src/ai_assistant/streaming_message_view.dart'; -import 'package:stream_chat_flutter/src/theme/message_theme.dart'; import 'package:stream_chat_flutter/src/utils/device_segmentation.dart'; +import 'package:stream_core_flutter/stream_core_flutter.dart' as core; /// {@template streamMarkdownMessage} /// A widget that displays a markdown message. This widget uses the markdown @@ -36,7 +36,7 @@ class StreamMarkdownMessage extends StatelessWidget { final MarkdownTapLinkCallback? onTapLink; /// The theme to apply to the message text. - final StreamMessageThemeData? messageTheme; + final core.StreamMessageStyle? messageTheme; /// Optional style sheet to customize the markdown output. /// @@ -91,17 +91,13 @@ class StreamMarkdownMessage extends StatelessWidget { MarkdownStyleSheet.fromTheme( themeData.copyWith( textTheme: themeData.textTheme.apply( - bodyColor: messageTheme?.messageTextStyle?.color, - decoration: messageTheme?.messageTextStyle?.decoration, - decorationColor: messageTheme?.messageTextStyle?.decorationColor, - decorationStyle: messageTheme?.messageTextStyle?.decorationStyle, - fontFamily: messageTheme?.messageTextStyle?.fontFamily, + bodyColor: messageTheme?.textColor, ), ), ) .copyWith( - a: messageTheme?.messageLinksStyle, - p: messageTheme?.messageTextStyle, + a: TextStyle(color: messageTheme?.textLinkColor), + p: TextStyle(color: messageTheme?.textColor), ) .merge(styleSheet), ); diff --git a/packages/stream_chat_flutter/lib/src/reactions/desktop_reactions_builder.dart b/packages/stream_chat_flutter/lib/src/reactions/desktop_reactions_builder.dart deleted file mode 100644 index 7a00738cb0..0000000000 --- a/packages/stream_chat_flutter/lib/src/reactions/desktop_reactions_builder.dart +++ /dev/null @@ -1,231 +0,0 @@ -// ignore_for_file: cascade_invocations - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_portal/flutter_portal.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// {@template desktopReactionsBuilder} -/// Builds a list of reactions to a message on desktop & web. -/// -/// Not intended for use outside of [MessageWidgetContent]. -/// {@endtemplate} -class DesktopReactionsBuilder extends StatefulWidget { - /// {@macro desktopReactionsBuilder} - const DesktopReactionsBuilder({ - super.key, - required this.message, - required this.messageTheme, - this.onHover, - this.borderSide, - required this.reverse, - }); - - /// The message to show reactions for. - final Message message; - - /// The theme to use for the reactions. - /// - /// [StreamMessageThemeData] is used because the design spec for desktop - /// 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; - - /// {@macro reverse} - final bool reverse; - - @override - State createState() => _DesktopReactionsBuilderState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - DiagnosticsProperty('message', message), - ); - properties.add( - DiagnosticsProperty( - 'messageTheme', - messageTheme, - ), - ); - properties.add( - DiagnosticsProperty('borderSide', borderSide), - ); - properties.add(DiagnosticsProperty('reverse', reverse)); - } -} - -class _DesktopReactionsBuilderState extends State { - bool _showReactionsPopup = false; - - @override - Widget build(BuildContext context) { - final streamChat = StreamChat.of(context); - final currentUser = streamChat.currentUser!; - final config = StreamChatConfiguration.of(context); - final resolver = config.reactionIconResolver; - final streamChatTheme = StreamChatTheme.of(context); - - final reactionsMap = {}; - widget.message.latestReactions?.forEach((element) { - if (!reactionsMap.containsKey(element.type) || element.user!.id == currentUser.id) { - reactionsMap[element.type] = element; - } - }); - - final reactionsList = reactionsMap.values.toList()..sort((a, b) => a.user!.id == currentUser.id ? 1 : -1); - - return PortalTarget( - visible: _showReactionsPopup, - portalCandidateLabels: const [kPortalMessageListViewLabel], - anchor: Aligned( - target: widget.reverse ? Alignment.topRight : Alignment.topLeft, - follower: widget.reverse ? Alignment.bottomRight : Alignment.bottomLeft, - shiftToWithinBound: const AxisFlag(y: true), - ), - portalFollower: MouseRegion( - onEnter: (_) => _onReactionsHover(true), - onExit: (_) => _onReactionsHover(false), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 336, - maxHeight: 342, - ), - child: StreamUserReactions(message: widget.message), - ), - ), - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => _onReactionsHover(true), - onExit: (_) => _onReactionsHover(false), - child: Padding( - padding: EdgeInsets.symmetric( - vertical: 2, - horizontal: widget.reverse ? 0 : 4, - ), - child: Wrap( - spacing: 4, - runSpacing: 4, - children: [ - ...reactionsList.map((reaction) { - return _BottomReaction( - currentUser: currentUser, - reaction: reaction, - message: widget.message, - borderSide: widget.borderSide, - messageTheme: widget.messageTheme, - resolver: resolver, - streamChatTheme: streamChatTheme, - ); - }).toList(), - ], - ), - ), - ), - ); - } - - void _onReactionsHover(bool isHovering) { - if (widget.onHover != null) { - return widget.onHover!(isHovering); - } - - setState(() => _showReactionsPopup = isHovering); - } -} - -class _BottomReaction extends StatelessWidget { - const _BottomReaction({ - required this.currentUser, - required this.reaction, - required this.message, - required this.borderSide, - required this.messageTheme, - required this.resolver, - required this.streamChatTheme, - }); - - final User currentUser; - final Reaction reaction; - final Message message; - final BorderSide? borderSide; - final StreamMessageThemeData? messageTheme; - final ReactionIconResolver resolver; - final StreamChatThemeData streamChatTheme; - - @override - Widget build(BuildContext context) { - final userId = currentUser.id; - - final backgroundColor = messageTheme?.reactionsBackgroundColor; - - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - if (reaction.userId == userId) { - StreamChannel.of(context).channel.deleteReaction( - message, - reaction, - ); - } else { - StreamChannel.of(context).channel.sendReaction( - message, - Reaction( - type: reaction.type, - emojiCode: resolver.emojiCode(reaction.type), - ), - enforceUnique: StreamChatConfiguration.of(context).enforceUniqueReactions, - ); - } - }, - child: Card( - margin: EdgeInsets.zero, - // Setting elevation as null when background color is transparent. - // This is done to avoid shadow when background color is transparent. - elevation: backgroundColor == Colors.transparent ? 0 : null, - shape: RoundedRectangleBorder( - side: - borderSide ?? - BorderSide( - color: messageTheme?.reactionsBorderColor ?? Colors.transparent, - ), - borderRadius: BorderRadius.circular(10), - ), - color: backgroundColor, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamEmoji( - size: StreamEmojiSize.sm, - emoji: resolver.resolve(reaction.type), - ), - const SizedBox(width: 4), - Text( - '${reaction.score}', - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('reaction', reaction)); - properties.add(DiagnosticsProperty('message', message)); - } -} diff --git a/packages/stream_chat_flutter/lib/src/reactions/user_reactions.dart b/packages/stream_chat_flutter/lib/src/reactions/user_reactions.dart deleted file mode 100644 index f5165d57e6..0000000000 --- a/packages/stream_chat_flutter/lib/src/reactions/user_reactions.dart +++ /dev/null @@ -1,160 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/components/avatar/stream_user_avatar.dart'; -import 'package:stream_chat_flutter/src/misc/empty_widget.dart'; -import 'package:stream_chat_flutter/src/stream_chat_configuration.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'; - -/// {@template streamUserReactions} -/// A widget that displays the reactions of a user to a message. -/// -/// This widget is typically used in a modal or a dedicated section -/// to show all reactions made by users on a specific message. -/// {@endtemplate} -class StreamUserReactions extends StatelessWidget { - /// {@macro streamUserReactions} - const StreamUserReactions({ - super.key, - required this.message, - this.onUserAvatarTap, - }); - - /// Message to display reactions of. - final Message message; - - /// {@macro onUserAvatarTap} - final ValueSetter? onUserAvatarTap; - - @override - Widget build(BuildContext context) { - final theme = StreamChatTheme.of(context); - final textTheme = theme.textTheme; - final colorTheme = theme.colorTheme; - - return Material( - color: colorTheme.barsBg, - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - context.translations.messageReactionsLabel, - style: textTheme.headlineBold, - ), - const SizedBox(height: 16), - Flexible( - child: SingleChildScrollView( - child: Wrap( - spacing: 16, - runSpacing: 16, - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - children: [ - ...?message.latestReactions?.map((reaction) { - return _UserReactionItem( - key: Key('${reaction.userId}-${reaction.type}'), - reaction: reaction, - onTap: onUserAvatarTap, - ); - }), - ], - ), - ), - ), - ], - ), - ), - ); - } -} - -class _UserReactionItem extends StatelessWidget { - const _UserReactionItem({ - super.key, - required this.reaction, - this.onTap, - }); - - final Reaction reaction; - - /// {@macro onUserAvatarTap} - final ValueSetter? onTap; - - @override - Widget build(BuildContext context) { - final reactionUser = reaction.user; - if (reactionUser == null) return const Empty(); - - final currentUser = StreamChatCore.of(context).currentUser; - final isCurrentUserReaction = reactionUser.id == currentUser?.id; - - final theme = StreamChatTheme.of(context); - final messageTheme = theme.getMessageTheme(reverse: isCurrentUserReaction); - - final resolver = StreamChatConfiguration.of(context).reactionIconResolver; - - return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - GestureDetector( - onTap: switch (onTap) { - final onTap? => () => onTap(reactionUser), - _ => null, - }, - child: StreamUserAvatar( - size: .xl, - user: reactionUser, - showOnlineIndicator: false, - ), - ), - PositionedDirectional( - bottom: 8, - end: isCurrentUserReaction ? null : 0, - start: isCurrentUserReaction ? 0 : null, - child: Container( - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - color: messageTheme.reactionsMaskColor, - borderRadius: const BorderRadius.all(Radius.circular(26)), - ), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: messageTheme.reactionsBackgroundColor, - border: Border.all( - color: messageTheme.reactionsBorderColor ?? Colors.transparent, - ), - borderRadius: const BorderRadius.all(Radius.circular(24)), - ), - child: StreamEmoji( - size: StreamEmojiSize.sm, - emoji: resolver.resolve(reaction.type), - ), - ), - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - reactionUser.name.split(' ')[0], - style: theme.textTheme.footnoteBold, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ], - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart deleted file mode 100644 index 728ebd2cfb..0000000000 --- a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart +++ /dev/null @@ -1,295 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -/// {@template messageInputTheme} -/// Overrides the default style of [MessageInput] descendants. -/// -/// See also: -/// -/// * [StreamMessageInputThemeData], which is used to configure this theme. -/// {@endtemplate} -class StreamMessageInputTheme extends InheritedTheme { - /// Creates a [StreamMessageInputTheme]. - /// - /// The [data] parameter must not be null. - const StreamMessageInputTheme({ - super.key, - required this.data, - required super.child, - }); - - /// The configuration of this theme. - final StreamMessageInputThemeData data; - - /// The closest instance of this class that encloses the given context. - /// - /// If there is no enclosing [StreamMessageInputTheme] widget, then - /// [StreamChatThemeData.messageInputTheme] is used. - /// - /// Typical usage is as follows: - /// - /// ```dart - /// final theme = MessageInputTheme.of(context); - /// ``` - static StreamMessageInputThemeData of(BuildContext context) { - final messageInputTheme = context.dependOnInheritedWidgetOfExactType(); - return messageInputTheme?.data ?? StreamChatTheme.of(context).messageInputTheme; - } - - @override - Widget wrap(BuildContext context, Widget child) => StreamMessageInputTheme(data: data, child: child); - - @override - bool updateShouldNotify(StreamMessageInputTheme oldWidget) => data != oldWidget.data; -} - -/// {@template messageInputThemeData} -/// A style that overrides the default appearance of [MessageInput] widgets -/// when used with [StreamMessageInputTheme] -/// or with the overall [StreamChatTheme]'s -/// [StreamChatThemeData.messageInputTheme]. -/// {@endtemplate} -class StreamMessageInputThemeData with Diagnosticable { - /// Creates a [StreamMessageInputThemeData]. - const StreamMessageInputThemeData({ - this.sendAnimationDuration, - this.actionButtonColor, - this.sendButtonColor, - this.actionButtonIdleColor, - this.sendButtonIdleColor, - this.inputBackgroundColor, - this.inputTextStyle, - this.inputDecoration, - this.activeBorderGradient, - this.idleBorderGradient, - this.borderRadius, - this.expandButtonColor, - this.linkHighlightColor, - this.enableSafeArea, - this.elevation, - this.shadow, - this.useSystemAttachmentPicker, - }); - - /// Duration of the [MessageInput] send button animation - final Duration? sendAnimationDuration; - - /// Background color of [MessageInput] send button - final Color? sendButtonColor; - - /// Color of a link - final Color? linkHighlightColor; - - /// Background color of [MessageInput] action buttons - final Color? actionButtonColor; - - /// Background color of [MessageInput] send button - final Color? sendButtonIdleColor; - - /// Background color of [MessageInput] action buttons - final Color? actionButtonIdleColor; - - /// Background color of [MessageInput] expand button - final Color? expandButtonColor; - - /// Background color of [MessageInput] - final Color? inputBackgroundColor; - - /// TextStyle of [MessageInput] - final TextStyle? inputTextStyle; - - /// InputDecoration of [MessageInput] - final InputDecoration? inputDecoration; - - /// Border gradient when the [MessageInput] is not focused - final Gradient? idleBorderGradient; - - /// Border gradient when the [MessageInput] is focused - final Gradient? activeBorderGradient; - - /// Border radius of [MessageInput] - final BorderRadius? borderRadius; - - /// Wrap [MessageInput] with a [SafeArea widget] - final bool? enableSafeArea; - - /// Elevation of the [MessageInput] - final double? elevation; - - /// Shadow for the [MessageInput] widget - final BoxShadow? shadow; - - /// If True, allows you to use the system’s default media picker instead of - /// the custom media picker provided by the library. This can be beneficial - /// for several reasons: - /// - /// 1. Consistency: Provides a consistent user experience by using the - /// familiar system media picker. - /// 2. Permissions: Reduces the need for additional permissions, as the system - /// media picker handles permissions internally. - /// 3. Simplicity: Simplifies the implementation by leveraging the built-in - /// functionality of the system media picker. - final bool? useSystemAttachmentPicker; - - /// Returns a new [StreamMessageInputThemeData] - /// replacing some of its properties - StreamMessageInputThemeData copyWith({ - Duration? sendAnimationDuration, - Color? inputBackgroundColor, - Color? actionButtonColor, - Color? sendButtonColor, - Color? actionButtonIdleColor, - Color? linkHighlightColor, - Color? sendButtonIdleColor, - Color? expandButtonColor, - TextStyle? inputTextStyle, - InputDecoration? inputDecoration, - Gradient? activeBorderGradient, - Gradient? idleBorderGradient, - BorderRadius? borderRadius, - bool? enableSafeArea, - double? elevation, - BoxShadow? shadow, - bool? useSystemAttachmentPicker, - }) { - return StreamMessageInputThemeData( - sendAnimationDuration: sendAnimationDuration ?? this.sendAnimationDuration, - inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor, - actionButtonColor: actionButtonColor ?? this.actionButtonColor, - sendButtonColor: sendButtonColor ?? this.sendButtonColor, - actionButtonIdleColor: actionButtonIdleColor ?? this.actionButtonIdleColor, - linkHighlightColor: linkHighlightColor ?? this.linkHighlightColor, - expandButtonColor: expandButtonColor ?? this.expandButtonColor, - inputTextStyle: inputTextStyle ?? this.inputTextStyle, - sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, - inputDecoration: inputDecoration ?? this.inputDecoration, - activeBorderGradient: activeBorderGradient ?? this.activeBorderGradient, - idleBorderGradient: idleBorderGradient ?? this.idleBorderGradient, - borderRadius: borderRadius ?? this.borderRadius, - enableSafeArea: enableSafeArea ?? this.enableSafeArea, - elevation: elevation ?? this.elevation, - shadow: shadow ?? this.shadow, - useSystemAttachmentPicker: useSystemAttachmentPicker ?? this.useSystemAttachmentPicker, - ); - } - - /// Linearly interpolate from one [StreamMessageInputThemeData] to another. - StreamMessageInputThemeData lerp( - StreamMessageInputThemeData a, - StreamMessageInputThemeData b, - double t, - ) { - return StreamMessageInputThemeData( - actionButtonColor: Color.lerp(a.actionButtonColor, b.actionButtonColor, t), - actionButtonIdleColor: Color.lerp(a.actionButtonIdleColor, b.actionButtonIdleColor, t), - activeBorderGradient: Gradient.lerp(a.activeBorderGradient, b.activeBorderGradient, t), - borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t), - expandButtonColor: Color.lerp(a.expandButtonColor, b.expandButtonColor, t), - linkHighlightColor: Color.lerp(a.linkHighlightColor, b.linkHighlightColor, t), - idleBorderGradient: Gradient.lerp(a.idleBorderGradient, b.idleBorderGradient, t), - inputBackgroundColor: Color.lerp(a.inputBackgroundColor, b.inputBackgroundColor, t), - inputTextStyle: TextStyle.lerp(a.inputTextStyle, b.inputTextStyle, t), - sendButtonColor: Color.lerp(a.sendButtonColor, b.sendButtonColor, t), - sendButtonIdleColor: Color.lerp(a.sendButtonIdleColor, b.sendButtonIdleColor, t), - sendAnimationDuration: a.sendAnimationDuration, - inputDecoration: a.inputDecoration, - enableSafeArea: a.enableSafeArea, - elevation: lerpDouble(a.elevation, b.elevation, t), - shadow: BoxShadow.lerp(a.shadow, b.shadow, t), - useSystemAttachmentPicker: b.useSystemAttachmentPicker, - ); - } - - /// Merges [this] [StreamMessageInputThemeData] with the [other] - StreamMessageInputThemeData merge(StreamMessageInputThemeData? other) { - if (other == null) return this; - return copyWith( - sendAnimationDuration: other.sendAnimationDuration, - inputBackgroundColor: other.inputBackgroundColor, - actionButtonColor: other.actionButtonColor, - actionButtonIdleColor: other.actionButtonIdleColor, - sendButtonColor: other.sendButtonColor, - sendButtonIdleColor: other.sendButtonIdleColor, - inputTextStyle: inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, - inputDecoration: inputDecoration?.merge(other.inputDecoration) ?? other.inputDecoration, - activeBorderGradient: other.activeBorderGradient, - idleBorderGradient: other.idleBorderGradient, - borderRadius: other.borderRadius, - expandButtonColor: other.expandButtonColor, - linkHighlightColor: other.linkHighlightColor, - enableSafeArea: other.enableSafeArea, - elevation: other.elevation, - shadow: other.shadow, - useSystemAttachmentPicker: other.useSystemAttachmentPicker, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is StreamMessageInputThemeData && - runtimeType == other.runtimeType && - sendAnimationDuration == other.sendAnimationDuration && - sendButtonColor == other.sendButtonColor && - actionButtonColor == other.actionButtonColor && - sendButtonIdleColor == other.sendButtonIdleColor && - actionButtonIdleColor == other.actionButtonIdleColor && - expandButtonColor == other.expandButtonColor && - inputBackgroundColor == other.inputBackgroundColor && - inputTextStyle == other.inputTextStyle && - inputDecoration == other.inputDecoration && - idleBorderGradient == other.idleBorderGradient && - activeBorderGradient == other.activeBorderGradient && - borderRadius == other.borderRadius && - linkHighlightColor == other.linkHighlightColor && - enableSafeArea == other.enableSafeArea && - elevation == other.elevation && - shadow == other.shadow && - useSystemAttachmentPicker == other.useSystemAttachmentPicker; - - @override - int get hashCode => - sendAnimationDuration.hashCode ^ - sendButtonColor.hashCode ^ - actionButtonColor.hashCode ^ - sendButtonIdleColor.hashCode ^ - actionButtonIdleColor.hashCode ^ - expandButtonColor.hashCode ^ - inputBackgroundColor.hashCode ^ - inputTextStyle.hashCode ^ - inputDecoration.hashCode ^ - idleBorderGradient.hashCode ^ - activeBorderGradient.hashCode ^ - borderRadius.hashCode ^ - linkHighlightColor.hashCode ^ - elevation.hashCode ^ - shadow.hashCode ^ - enableSafeArea.hashCode ^ - useSystemAttachmentPicker.hashCode; - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('sendAnimationDuration', sendAnimationDuration)) - ..add(ColorProperty('inputBackgroundColor', inputBackgroundColor)) - ..add(ColorProperty('actionButtonColor', actionButtonColor)) - ..add(ColorProperty('actionButtonIdleColor', actionButtonIdleColor)) - ..add(ColorProperty('sendButtonColor', sendButtonColor)) - ..add(ColorProperty('sendButtonIdleColor', sendButtonIdleColor)) - ..add(DiagnosticsProperty('inputTextStyle', inputTextStyle)) - ..add(DiagnosticsProperty('inputDecoration', inputDecoration)) - ..add(DiagnosticsProperty('activeBorderGradient', activeBorderGradient)) - ..add(DiagnosticsProperty('idleBorderGradient', idleBorderGradient)) - ..add(DiagnosticsProperty('borderRadius', borderRadius)) - ..add(ColorProperty('expandButtonColor', expandButtonColor)) - ..add(ColorProperty('linkHighlightColor', linkHighlightColor)) - ..add(DiagnosticsProperty('elevation', elevation)) - ..add(DiagnosticsProperty('shadow', shadow)) - ..add(DiagnosticsProperty('enableSafeArea', enableSafeArea)) - ..add(DiagnosticsProperty('useSystemAttachmentPicker', useSystemAttachmentPicker)); - } -} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart deleted file mode 100644 index 1ad66765e0..0000000000 --- a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart +++ /dev/null @@ -1,345 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; -import 'package:stream_chat_flutter/src/utils/date_formatter.dart'; - -/// {@template message_theme_data} -/// Class for getting message theme -/// {@endtemplate} -// ignore: prefer-match-file-name -class StreamMessageThemeData with Diagnosticable { - /// Creates a [StreamMessageThemeData]. - const StreamMessageThemeData({ - this.repliesStyle, - this.messageTextStyle, - this.messageAuthorStyle, - this.messageLinksStyle, - this.messageDeletedStyle, - this.messageBackgroundColor, - this.messageBackgroundGradient, - this.messageBorderColor, - this.reactionsBackgroundColor, - this.reactionsBorderColor, - this.reactionsMaskColor, - this.avatarTheme, - this.createdAtStyle, - this.createdAtFormatter, - this.urlAttachmentBackgroundColor, - this.urlAttachmentHostStyle, - this.urlAttachmentTitleStyle, - this.urlAttachmentTextStyle, - this.urlAttachmentTitleMaxLine, - this.urlAttachmentTextMaxLine, - }); - - /// Text style for message text - final TextStyle? messageTextStyle; - - /// Text style for message author - final TextStyle? messageAuthorStyle; - - /// Text style for message links - final TextStyle? messageLinksStyle; - - /// Text style for created at text - final TextStyle? createdAtStyle; - - /// Formatter for the created at timestamp. - /// - /// If null, uses the default date formatting. - /// - /// Example: - /// ```dart - /// StreamMessageThemeData( - /// createdAtStyle: TextStyle(...), - /// createdAtFormatter: (context, date) { - /// return Jiffy.parseFromDateTime(date).jm; // "2:30 PM" - /// }, - /// ) - /// ``` - final DateFormatter? createdAtFormatter; - - /// Text style for the text on a deleted message - /// If not set [messageTextStyle] is used with [FontStyle.italic] and - /// [createdAtStyle.color]. - final TextStyle? messageDeletedStyle; - - /// Text style for replies - final TextStyle? repliesStyle; - - /// Color for messageBackgroundColor - final Color? messageBackgroundColor; - - /// Gradient for message background. - /// - /// Note: If this is set, it will override [messageBackgroundColor]. - final Gradient? messageBackgroundGradient; - - /// Color for message border color - final Color? messageBorderColor; - - /// Color for reactions - final Color? reactionsBackgroundColor; - - /// Colors reaction border - final Color? reactionsBorderColor; - - /// Color for reaction mask - final Color? reactionsMaskColor; - - /// Theme of the avatar - final StreamAvatarThemeData? avatarTheme; - - /// Background color for messages with url attachments. - final Color? urlAttachmentBackgroundColor; - - /// Color for url attachment host. - final TextStyle? urlAttachmentHostStyle; - - /// Color for url attachment title. - final TextStyle? urlAttachmentTitleStyle; - - /// Color for url attachment text. - final TextStyle? urlAttachmentTextStyle; - - /// Max number of lines in Url link title. - final int? urlAttachmentTitleMaxLine; - - /// Max number of lines in Url link text. - final int? urlAttachmentTextMaxLine; - - /// Copy with a theme - StreamMessageThemeData copyWith({ - TextStyle? messageTextStyle, - TextStyle? messageAuthorStyle, - TextStyle? messageLinksStyle, - TextStyle? messageDeletedStyle, - TextStyle? createdAtStyle, - DateFormatter? createdAtFormatter, - TextStyle? repliesStyle, - Color? messageBackgroundColor, - Gradient? messageBackgroundGradient, - Color? messageBorderColor, - StreamAvatarThemeData? avatarTheme, - Color? reactionsBackgroundColor, - Color? reactionsBorderColor, - Color? reactionsMaskColor, - Color? urlAttachmentBackgroundColor, - TextStyle? urlAttachmentHostStyle, - TextStyle? urlAttachmentTitleStyle, - TextStyle? urlAttachmentTextStyle, - int? urlAttachmentTitleMaxLine, - int? urlAttachmentTextMaxLine, - }) { - return StreamMessageThemeData( - messageTextStyle: messageTextStyle ?? this.messageTextStyle, - messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle, - messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle, - createdAtStyle: createdAtStyle ?? this.createdAtStyle, - createdAtFormatter: createdAtFormatter ?? this.createdAtFormatter, - messageDeletedStyle: messageDeletedStyle ?? this.messageDeletedStyle, - messageBackgroundColor: messageBackgroundColor ?? this.messageBackgroundColor, - messageBackgroundGradient: messageBackgroundGradient ?? this.messageBackgroundGradient, - messageBorderColor: messageBorderColor ?? this.messageBorderColor, - avatarTheme: avatarTheme ?? this.avatarTheme, - repliesStyle: repliesStyle ?? this.repliesStyle, - reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, - reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, - reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, - urlAttachmentBackgroundColor: urlAttachmentBackgroundColor ?? this.urlAttachmentBackgroundColor, - urlAttachmentHostStyle: urlAttachmentHostStyle ?? this.urlAttachmentHostStyle, - urlAttachmentTitleStyle: urlAttachmentTitleStyle ?? this.urlAttachmentTitleStyle, - urlAttachmentTextStyle: urlAttachmentTextStyle ?? this.urlAttachmentTextStyle, - urlAttachmentTitleMaxLine: urlAttachmentTitleMaxLine ?? this.urlAttachmentTitleMaxLine, - urlAttachmentTextMaxLine: urlAttachmentTextMaxLine ?? this.urlAttachmentTextMaxLine, - ); - } - - /// Linearly interpolate from one [StreamMessageThemeData] to another. - StreamMessageThemeData lerp( - StreamMessageThemeData a, - StreamMessageThemeData b, - double t, - ) { - return StreamMessageThemeData( - avatarTheme: const StreamAvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t), - messageAuthorStyle: TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t), - createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t), - createdAtFormatter: t < 0.5 ? a.createdAtFormatter : b.createdAtFormatter, - messageDeletedStyle: TextStyle.lerp(a.messageDeletedStyle, b.messageDeletedStyle, t), - messageBackgroundColor: Color.lerp(a.messageBackgroundColor, b.messageBackgroundColor, t), - messageBackgroundGradient: t < 0.5 ? a.messageBackgroundGradient : b.messageBackgroundGradient, - messageBorderColor: Color.lerp(a.messageBorderColor, b.messageBorderColor, t), - messageLinksStyle: TextStyle.lerp(a.messageLinksStyle, b.messageLinksStyle, t), - messageTextStyle: TextStyle.lerp(a.messageTextStyle, b.messageTextStyle, t), - reactionsBackgroundColor: Color.lerp( - a.reactionsBackgroundColor, - b.reactionsBackgroundColor, - t, - ), - reactionsBorderColor: Color.lerp(a.messageBorderColor, b.reactionsBorderColor, t), - reactionsMaskColor: Color.lerp(a.reactionsMaskColor, b.reactionsMaskColor, t), - repliesStyle: TextStyle.lerp(a.repliesStyle, b.repliesStyle, t), - urlAttachmentBackgroundColor: Color.lerp( - a.urlAttachmentBackgroundColor, - b.urlAttachmentBackgroundColor, - t, - ), - urlAttachmentHostStyle: TextStyle.lerp(a.urlAttachmentHostStyle, b.urlAttachmentHostStyle, t), - urlAttachmentTextStyle: TextStyle.lerp( - a.urlAttachmentTextStyle, - b.urlAttachmentTextStyle, - t, - ), - urlAttachmentTitleStyle: TextStyle.lerp( - a.urlAttachmentTitleStyle, - b.urlAttachmentTitleStyle, - t, - ), - urlAttachmentTitleMaxLine: lerpDouble( - a.urlAttachmentTitleMaxLine, - b.urlAttachmentTitleMaxLine, - t, - )?.round(), - urlAttachmentTextMaxLine: lerpDouble( - a.urlAttachmentTextMaxLine, - b.urlAttachmentTextMaxLine, - t, - )?.round(), - ); - } - - /// Merge with a theme - StreamMessageThemeData merge(StreamMessageThemeData? other) { - if (other == null) return this; - return copyWith( - messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ?? other.messageTextStyle, - messageAuthorStyle: messageAuthorStyle?.merge(other.messageAuthorStyle) ?? other.messageAuthorStyle, - messageLinksStyle: messageLinksStyle?.merge(other.messageLinksStyle) ?? other.messageLinksStyle, - createdAtStyle: createdAtStyle?.merge(other.createdAtStyle) ?? other.createdAtStyle, - createdAtFormatter: other.createdAtFormatter ?? createdAtFormatter, - messageDeletedStyle: messageDeletedStyle?.merge(other.messageDeletedStyle) ?? other.messageDeletedStyle, - repliesStyle: repliesStyle?.merge(other.repliesStyle) ?? other.repliesStyle, - messageBackgroundColor: other.messageBackgroundColor, - messageBackgroundGradient: other.messageBackgroundGradient, - messageBorderColor: other.messageBorderColor, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - reactionsBackgroundColor: other.reactionsBackgroundColor, - reactionsBorderColor: other.reactionsBorderColor, - reactionsMaskColor: other.reactionsMaskColor, - urlAttachmentBackgroundColor: other.urlAttachmentBackgroundColor, - urlAttachmentHostStyle: other.urlAttachmentHostStyle, - urlAttachmentTitleStyle: other.urlAttachmentTitleStyle, - urlAttachmentTextStyle: other.urlAttachmentTextStyle, - urlAttachmentTitleMaxLine: other.urlAttachmentTitleMaxLine, - urlAttachmentTextMaxLine: other.urlAttachmentTextMaxLine, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is StreamMessageThemeData && - runtimeType == other.runtimeType && - messageTextStyle == other.messageTextStyle && - messageAuthorStyle == other.messageAuthorStyle && - messageLinksStyle == other.messageLinksStyle && - createdAtStyle == other.createdAtStyle && - createdAtFormatter == other.createdAtFormatter && - messageDeletedStyle == other.messageDeletedStyle && - repliesStyle == other.repliesStyle && - messageBackgroundColor == other.messageBackgroundColor && - messageBackgroundGradient == other.messageBackgroundGradient && - messageBorderColor == other.messageBorderColor && - reactionsBackgroundColor == other.reactionsBackgroundColor && - reactionsBorderColor == other.reactionsBorderColor && - reactionsMaskColor == other.reactionsMaskColor && - avatarTheme == other.avatarTheme && - urlAttachmentBackgroundColor == other.urlAttachmentBackgroundColor && - urlAttachmentHostStyle == other.urlAttachmentHostStyle && - urlAttachmentTitleStyle == other.urlAttachmentTitleStyle && - urlAttachmentTextStyle == other.urlAttachmentTextStyle && - urlAttachmentTitleMaxLine == other.urlAttachmentTitleMaxLine && - urlAttachmentTextMaxLine == other.urlAttachmentTextMaxLine; - - @override - int get hashCode => - messageTextStyle.hashCode ^ - messageAuthorStyle.hashCode ^ - messageLinksStyle.hashCode ^ - createdAtStyle.hashCode ^ - createdAtFormatter.hashCode ^ - messageDeletedStyle.hashCode ^ - repliesStyle.hashCode ^ - messageBackgroundColor.hashCode ^ - messageBackgroundGradient.hashCode ^ - messageBorderColor.hashCode ^ - reactionsBackgroundColor.hashCode ^ - reactionsBorderColor.hashCode ^ - reactionsMaskColor.hashCode ^ - avatarTheme.hashCode ^ - urlAttachmentBackgroundColor.hashCode ^ - urlAttachmentHostStyle.hashCode ^ - urlAttachmentTitleStyle.hashCode ^ - urlAttachmentTextStyle.hashCode ^ - urlAttachmentTitleMaxLine.hashCode ^ - urlAttachmentTextMaxLine.hashCode; - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('messageTextStyle', messageTextStyle)) - ..add(DiagnosticsProperty('messageAuthorStyle', messageAuthorStyle)) - ..add(DiagnosticsProperty('messageLinksStyle', messageLinksStyle)) - ..add(DiagnosticsProperty('createdAtStyle', createdAtStyle)) - ..add(DiagnosticsProperty('createdAtFormatter', createdAtFormatter)) - ..add(DiagnosticsProperty('messageDeletedStyle', messageDeletedStyle)) - ..add(DiagnosticsProperty('repliesStyle', repliesStyle)) - ..add(ColorProperty('messageBackgroundColor', messageBackgroundColor)) - ..add(DiagnosticsProperty('messageBackgroundGradient', messageBackgroundGradient)) - ..add(ColorProperty('messageBorderColor', messageBorderColor)) - ..add(DiagnosticsProperty('avatarTheme', avatarTheme)) - ..add(ColorProperty('reactionsBackgroundColor', reactionsBackgroundColor)) - ..add(ColorProperty('reactionsBorderColor', reactionsBorderColor)) - ..add(ColorProperty('reactionsMaskColor', reactionsMaskColor)) - ..add( - ColorProperty( - 'urlAttachmentBackgroundColor', - urlAttachmentBackgroundColor, - ), - ) - ..add( - DiagnosticsProperty( - 'urlAttachmentHostStyle', - urlAttachmentHostStyle, - ), - ) - ..add( - DiagnosticsProperty( - 'urlAttachmentTitleStyle', - urlAttachmentTitleStyle, - ), - ) - ..add( - DiagnosticsProperty( - 'urlAttachmentTextStyle', - urlAttachmentTextStyle, - ), - ) - ..add( - DiagnosticsProperty( - 'urlAttachmentTitleMaxLine', - urlAttachmentTitleMaxLine, - ), - ) - ..add( - DiagnosticsProperty( - 'urlAttachmentTextMaxLine', - urlAttachmentTextMaxLine, - ), - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart index 45dea27c00..8ae19cb526 100644 --- a/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart @@ -45,9 +45,6 @@ class StreamChatThemeData { StreamChannelListHeaderThemeData? channelListHeaderTheme, StreamChannelPreviewThemeData? channelPreviewTheme, StreamChannelHeaderThemeData? channelHeaderTheme, - StreamMessageThemeData? otherMessageTheme, - StreamMessageThemeData? ownMessageTheme, - StreamMessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, PlaceholderUserImage? placeholderUserImage, IconThemeData? primaryIconTheme, @@ -78,9 +75,6 @@ class StreamChatThemeData { channelListHeaderTheme: channelListHeaderTheme, channelPreviewTheme: channelPreviewTheme, channelHeaderTheme: channelHeaderTheme, - otherMessageTheme: otherMessageTheme, - ownMessageTheme: ownMessageTheme, - messageInputTheme: messageInputTheme, defaultUserImage: defaultUserImage, placeholderUserImage: placeholderUserImage, primaryIconTheme: primaryIconTheme, @@ -115,9 +109,6 @@ class StreamChatThemeData { required this.channelListHeaderTheme, required this.channelPreviewTheme, required this.channelHeaderTheme, - required this.otherMessageTheme, - required this.ownMessageTheme, - required this.messageInputTheme, required this.primaryIconTheme, required this.galleryHeaderTheme, required this.galleryFooterTheme, @@ -151,7 +142,6 @@ class StreamChatThemeData { StreamColorTheme colorTheme, StreamTextTheme textTheme, ) { - final accentColor = colorTheme.accentPrimary; final iconTheme = IconThemeData(color: colorTheme.textLowEmphasis); final channelHeaderTheme = StreamChannelHeaderThemeData( avatarTheme: StreamAvatarThemeData( @@ -200,87 +190,6 @@ class StreamChatThemeData { titleStyle: textTheme.headlineBold, ), channelHeaderTheme: channelHeaderTheme, - ownMessageTheme: StreamMessageThemeData( - messageAuthorStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - messageTextStyle: textTheme.body, - messageDeletedStyle: textTheme.body.copyWith( - color: colorTheme.textLowEmphasis, - fontStyle: FontStyle.italic, - ), - createdAtStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - repliesStyle: textTheme.footnoteBold.copyWith(color: accentColor), - messageBackgroundColor: colorTheme.inputBg, - reactionsBackgroundColor: colorTheme.barsBg, - reactionsBorderColor: colorTheme.borders, - reactionsMaskColor: colorTheme.appBg, - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(20), - constraints: const BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - messageLinksStyle: TextStyle(color: accentColor), - urlAttachmentBackgroundColor: colorTheme.linkBg, - urlAttachmentHostStyle: textTheme.bodyBold.copyWith(color: accentColor), - urlAttachmentTitleStyle: textTheme.footnoteBold, - urlAttachmentTextStyle: textTheme.footnote, - urlAttachmentTitleMaxLine: 1, - urlAttachmentTextMaxLine: 3, - ), - otherMessageTheme: StreamMessageThemeData( - reactionsBackgroundColor: colorTheme.borders, - reactionsBorderColor: colorTheme.borders, - reactionsMaskColor: colorTheme.appBg, - messageTextStyle: textTheme.body, - messageDeletedStyle: textTheme.body.copyWith( - color: colorTheme.textLowEmphasis, - fontStyle: FontStyle.italic, - ), - createdAtStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - messageAuthorStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - repliesStyle: textTheme.footnoteBold.copyWith(color: accentColor), - messageLinksStyle: TextStyle(color: accentColor), - messageBackgroundColor: colorTheme.barsBg, - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(20), - constraints: const BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - urlAttachmentBackgroundColor: colorTheme.linkBg, - urlAttachmentHostStyle: textTheme.bodyBold.copyWith(color: accentColor), - urlAttachmentTitleStyle: textTheme.footnoteBold, - urlAttachmentTextStyle: textTheme.footnote, - urlAttachmentTitleMaxLine: 1, - urlAttachmentTextMaxLine: 3, - ), - messageInputTheme: StreamMessageInputThemeData( - borderRadius: BorderRadius.circular(20), - sendAnimationDuration: const Duration(milliseconds: 300), - actionButtonColor: colorTheme.accentPrimary, - actionButtonIdleColor: colorTheme.textLowEmphasis, - expandButtonColor: colorTheme.accentPrimary, - sendButtonColor: colorTheme.accentPrimary, - sendButtonIdleColor: colorTheme.disabled, - inputBackgroundColor: colorTheme.barsBg, - inputTextStyle: textTheme.body, - linkHighlightColor: colorTheme.accentPrimary, - idleBorderGradient: LinearGradient( - colors: [ - colorTheme.borders, - colorTheme.borders, - ], - ), - activeBorderGradient: LinearGradient( - colors: [ - colorTheme.borders, - colorTheme.borders, - ], - ), - useSystemAttachmentPicker: false, - ), galleryHeaderTheme: StreamGalleryHeaderThemeData( closeButtonColor: colorTheme.textHighEmphasis, backgroundColor: channelHeaderTheme.color, @@ -446,15 +355,6 @@ class StreamChatThemeData { /// [StreamChatTheme]. final StreamGalleryFooterThemeData galleryFooterTheme; - /// Theme of the current user messages - final StreamMessageThemeData ownMessageTheme; - - /// Theme of other users messages - final StreamMessageThemeData otherMessageTheme; - - /// Theme dedicated to the [StreamMessageInput] widget - final StreamMessageInputThemeData messageInputTheme; - /// Primary icon theme final IconThemeData primaryIconTheme; @@ -491,15 +391,6 @@ class StreamChatThemeData { /// Theme configuration for the [StreamDraftListTile] widget. final StreamDraftListTileThemeData draftListTileTheme; - /// Returns the theme for the message based on the [reverse] parameter. - /// - /// If [reverse] is true, it returns the [otherMessageTheme], otherwise it - /// returns the [ownMessageTheme]. - StreamMessageThemeData getMessageTheme({bool reverse = false}) { - if (reverse) return ownMessageTheme; - return otherMessageTheme; - } - /// Creates a copy of [StreamChatThemeData] with specified attributes /// overridden. StreamChatThemeData copyWith({ @@ -507,9 +398,6 @@ class StreamChatThemeData { StreamColorTheme? colorTheme, StreamChannelPreviewThemeData? channelPreviewTheme, StreamChannelHeaderThemeData? channelHeaderTheme, - StreamMessageThemeData? ownMessageTheme, - StreamMessageThemeData? otherMessageTheme, - StreamMessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, PlaceholderUserImage? placeholderUserImage, IconThemeData? primaryIconTheme, @@ -534,9 +422,6 @@ class StreamChatThemeData { primaryIconTheme: this.primaryIconTheme.merge(primaryIconTheme), channelPreviewTheme: this.channelPreviewTheme.merge(channelPreviewTheme), channelHeaderTheme: this.channelHeaderTheme.merge(channelHeaderTheme), - ownMessageTheme: this.ownMessageTheme.merge(ownMessageTheme), - otherMessageTheme: this.otherMessageTheme.merge(otherMessageTheme), - messageInputTheme: this.messageInputTheme.merge(messageInputTheme), galleryHeaderTheme: galleryHeaderTheme ?? this.galleryHeaderTheme, galleryFooterTheme: galleryFooterTheme ?? this.galleryFooterTheme, messageListViewTheme: messageListViewTheme ?? this.messageListViewTheme, @@ -562,9 +447,6 @@ class StreamChatThemeData { primaryIconTheme: other.primaryIconTheme, channelPreviewTheme: channelPreviewTheme.merge(other.channelPreviewTheme), channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), - ownMessageTheme: ownMessageTheme.merge(other.ownMessageTheme), - otherMessageTheme: otherMessageTheme.merge(other.otherMessageTheme), - messageInputTheme: messageInputTheme.merge(other.messageInputTheme), galleryHeaderTheme: galleryHeaderTheme.merge(other.galleryHeaderTheme), galleryFooterTheme: galleryFooterTheme.merge(other.galleryFooterTheme), messageListViewTheme: messageListViewTheme.merge(other.messageListViewTheme), diff --git a/packages/stream_chat_flutter/lib/src/theme/themes.dart b/packages/stream_chat_flutter/lib/src/theme/themes.dart index 7bcf5a75e6..643872e953 100644 --- a/packages/stream_chat_flutter/lib/src/theme/themes.dart +++ b/packages/stream_chat_flutter/lib/src/theme/themes.dart @@ -6,9 +6,7 @@ export 'color_theme.dart'; export 'draft_list_tile_theme.dart'; export 'gallery_footer_theme.dart'; export 'gallery_header_theme.dart'; -export 'message_input_theme.dart'; export 'message_list_view_theme.dart'; -export 'message_theme.dart'; export 'poll_comments_dialog_theme.dart'; export 'poll_creator_theme.dart'; export 'poll_interactor_theme.dart'; diff --git a/packages/stream_chat_flutter/lib/src/utils/typedefs.dart b/packages/stream_chat_flutter/lib/src/utils/typedefs.dart index 537ac60440..4756e3f712 100644 --- a/packages/stream_chat_flutter/lib/src/utils/typedefs.dart +++ b/packages/stream_chat_flutter/lib/src/utils/typedefs.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/message_input/attachment_button.dart'; import 'package:stream_chat_flutter/src/message_input/command_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -184,18 +183,6 @@ typedef CommandButtonBuilder = CommandButton commandButton, ); -/// {@template actionButtonBuilder} -/// A widget builder for building a custom action button. -/// -/// [attachmentButton] is the default [AttachmentButton] configuration, -/// use [attachmentButton.copyWith] to easily customize it. -/// {@endtemplate} -typedef AttachmentButtonBuilder = - Widget Function( - BuildContext context, - AttachmentButton attachmentButton, - ); - /// {@template quotedMessageAttachmentThumbnailBuilder} /// A widget builder for building a custom quoted message attachment thumbnail. /// {@endtemplate} diff --git a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart index 1c4bcabdba..64e69f06ef 100644 --- a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart +++ b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart @@ -90,7 +90,6 @@ export 'src/attachment_actions_modal/attachment_actions_modal.dart'; export 'src/autocomplete/stream_autocomplete.dart'; export 'src/avatars/gradient_avatar.dart'; export 'src/bottom_sheets/attachment_modal_sheet.dart'; -export 'src/bottom_sheets/edit_message_sheet.dart'; export 'src/bottom_sheets/error_alert_sheet.dart'; export 'src/bottom_sheets/stream_channel_info_bottom_sheet.dart'; export 'src/channel/channel_header.dart'; @@ -133,10 +132,8 @@ export 'src/message_input/audio_recorder/audio_recorder_state.dart'; export 'src/message_input/audio_recorder/stream_audio_recorder.dart'; export 'src/message_input/countdown_button.dart'; export 'src/message_input/enums.dart'; -export 'src/message_input/quoted_message_widget.dart'; export 'src/message_input/stream_message_composer_attachment_list.dart'; export 'src/message_input/stream_message_input.dart'; -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'; @@ -172,7 +169,6 @@ export 'src/poll/stream_poll_options_dialog.dart'; export 'src/poll/stream_poll_results_dialog.dart'; export 'src/reactions/detail/reaction_detail_sheet.dart'; export 'src/reactions/picker/reaction_picker.dart'; -export 'src/reactions/user_reactions.dart'; export 'src/scroll_view/channel_scroll_view/stream_channel_grid_tile.dart'; export 'src/scroll_view/channel_scroll_view/stream_channel_grid_view.dart'; export 'src/scroll_view/channel_scroll_view/stream_channel_list_item.dart'; diff --git a/packages/stream_chat_flutter/test/src/bottom_sheets/edit_message_sheet_test.dart b/packages/stream_chat_flutter/test/src/bottom_sheets/edit_message_sheet_test.dart deleted file mode 100644 index 3314bba235..0000000000 --- a/packages/stream_chat_flutter/test/src/bottom_sheets/edit_message_sheet_test.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:alchemist/alchemist.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:record/record.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import '../fakes.dart'; -import '../material_app_wrapper.dart'; -import '../mocks.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - final originalRecordPlatform = RecordPlatform.instance; - setUp(() => RecordPlatform.instance = FakeRecordPlatform()); - tearDown(() => RecordPlatform.instance = originalRecordPlatform); - - group('EditMessageSheet tests', () { - testWidgets('appears on tap', (tester) async { - final channel = MockChannel(); - when(channel.getRemainingCooldown).thenReturn(0); - - await tester.pumpWidget( - MaterialApp( - builder: (context, child) => StreamChat( - client: MockClient(), - connectivityStream: Stream.value([ConnectivityResult.wifi]), - child: child, - ), - home: Scaffold( - body: Builder( - builder: (context) { - return Center( - child: ElevatedButton( - child: const Text('Show Modal'), - onPressed: () => showModalBottomSheet( - context: context, - builder: (_) => EditMessageSheet( - channel: channel, - message: Message(id: 'msg123', text: 'Hello World!'), - ), - ), - ), - ); - }, - ), - ), - ), - ); - - final button = find.byType(ElevatedButton); - await tester.tap(button); - await tester.pumpAndSettle(); - expect(find.byType(EditMessageSheet), findsOneWidget); - expect(find.text('Edit Message'), findsOneWidget); - expect(find.byType(StreamMessageInput), findsOneWidget); - }); - - goldenTest( - 'golden test for EditMessageSheet', - fileName: 'edit_message_sheet_0', - constraints: const BoxConstraints.tightFor(width: 300, height: 300), - builder: () { - final channel = MockChannel(); - when(channel.getRemainingCooldown).thenReturn(0); - - return MaterialAppWrapper( - builder: (context, child) => StreamChat( - client: MockClient(), - connectivityStream: Stream.value([ConnectivityResult.wifi]), - child: child, - ), - home: Scaffold( - bottomSheet: EditMessageSheet( - channel: channel, - message: Message(id: 'msg123', text: 'Hello World!'), - ), - ), - ); - }, - ); - }); -} diff --git a/packages/stream_chat_flutter/test/src/message_input/attachment_button_test.dart b/packages/stream_chat_flutter/test/src/message_input/attachment_button_test.dart deleted file mode 100644 index e5c54d2ed7..0000000000 --- a/packages/stream_chat_flutter/test/src/message_input/attachment_button_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:alchemist/alchemist.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_flutter/src/message_input/attachment_button.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -import '../material_app_wrapper.dart'; - -void main() { - testWidgets('AttachmentButton onPressed works', (tester) async { - var count = 0; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: AttachmentButton( - color: Colors.red, - onPressed: () { - count++; - }, - ), - ), - ), - ), - ); - - final button = find.byType(IconButton); - expect(button, findsOneWidget); - expect(find.byType(Icon), findsOneWidget); - await tester.tap(button); - expect(count, 1); - }); - - testWidgets('AttachmentButton should accept icon', (tester) async { - const icon = Icon(Icons.attachment); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: AttachmentButton( - icon: icon, - onPressed: () {}, - ), - ), - ), - ), - ); - - expect(find.byIcon(Icons.attachment), findsOneWidget); - }); - - testWidgets('AttachmentButton should accept color', (tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: AttachmentButton( - color: Colors.red, - onPressed: () {}, - ), - ), - ), - ), - ); - - final buttonFinder = find.byType(AttachmentButton); - expect(buttonFinder, findsOneWidget); - - final button = tester.widget(buttonFinder); - expect(button.color, Colors.red); - }); - - goldenTest( - 'golden test for AttachmentButton', - fileName: 'attachment_button_0', - constraints: const BoxConstraints.tightFor(width: 50, height: 50), - builder: () => MaterialAppWrapper( - home: Scaffold( - body: Center( - child: AttachmentButton( - color: StreamChatThemeData.light().messageInputTheme.actionButtonIdleColor, - onPressed: () {}, - ), - ), - ), - ), - ); -} diff --git a/packages/stream_chat_flutter/test/src/message_input/stream_message_send_button_test.dart b/packages/stream_chat_flutter/test/src/message_input/stream_message_send_button_test.dart deleted file mode 100644 index bcde15940e..0000000000 --- a/packages/stream_chat_flutter/test/src/message_input/stream_message_send_button_test.dart +++ /dev/null @@ -1,195 +0,0 @@ -// ignore_for_file: avoid_redundant_argument_values - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_flutter/src/message_input/stream_message_input_icon_button.dart'; -import 'package:stream_chat_flutter/src/message_input/stream_message_send_button.dart'; -import 'package:stream_chat_flutter/src/theme/message_input_theme.dart'; -import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; - -void main() { - group('StreamMessageSendButton', () { - testWidgets( - 'renders countdown button when timeout > 0', - (tester) async { - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - timeOut: 5, - onSendMessage: () {}, - ), - ), - ); - - expect(find.byKey(const Key('countdown_button')), findsOneWidget); - expect(find.byKey(const Key('send_button')), findsNothing); - }, - ); - - testWidgets( - 'renders idle send button when isIdle is true', - (tester) async { - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - isIdle: true, - onSendMessage: () {}, - ), - ), - ); - - final button = find.byKey(const Key('send_button')); - expect(button, findsOneWidget); - - // Verify the button is disabled - final iconButton = tester.widget(button); - expect(iconButton.onPressed, isNull); - - // Verify default idle icon is shown - expect(find.byIcon(StreamIconData.send), findsOneWidget); - }, - ); - - testWidgets( - 'renders active send button when isIdle is false', - (tester) async { - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - isIdle: false, - onSendMessage: () {}, - ), - ), - ); - - final button = find.byKey(const Key('send_button')); - expect(button, findsOneWidget); - - // Verify the button is enabled - final iconButton = tester.widget(button); - expect(iconButton.onPressed, isNotNull); - - // Verify default active icon is shown - expect(find.byIcon(StreamIconData.arrowUp), findsOneWidget); - }, - ); - - testWidgets( - 'uses custom idle button when provided', - (tester) async { - final customIdleButton = Container(key: const Key('custom_idle')); - - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - isIdle: true, - idleSendIcon: customIdleButton, - onSendMessage: () {}, - ), - ), - ); - - expect(find.byKey(const Key('custom_idle')), findsOneWidget); - expect(find.byType(Icon), findsNothing); - }, - ); - - testWidgets( - 'uses custom active button when provided', - (tester) async { - final customActiveButton = Container(key: const Key('custom_active')); - - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - isIdle: false, - activeSendIcon: customActiveButton, - onSendMessage: () {}, - ), - ), - ); - - expect(find.byKey(const Key('custom_active')), findsOneWidget); - expect(find.byType(Icon), findsNothing); - }, - ); - - testWidgets( - 'calls onSendMessage when active button is pressed', - (tester) async { - var wasPressed = false; - - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageSendButton( - isIdle: false, - onSendMessage: () => wasPressed = true, - ), - ), - ); - - await tester.tap(find.byKey(const Key('send_button'))); - expect(wasPressed, isTrue); - }, - ); - - testWidgets( - 'applies theme colors correctly', - (tester) async { - const theme = StreamMessageInputThemeData( - sendButtonColor: Colors.blue, - sendButtonIdleColor: Colors.grey, - sendAnimationDuration: Duration(milliseconds: 100), - ); - - await tester.pumpWidget( - _wrapWithStreamChatApp( - StreamMessageInputTheme( - data: theme, - child: StreamMessageSendButton( - isIdle: false, - onSendMessage: () {}, - ), - ), - ), - ); - - final iconButton = tester.widget( - find.byKey(const Key('send_button')), - ); - - expect(iconButton.color, Colors.blue); - expect(iconButton.disabledColor, Colors.grey); - }, - ); - }); -} - -Widget _wrapWithStreamChatApp( - Widget widget, { - Brightness? brightness, -}) { - return MaterialApp( - debugShowCheckedModeBanner: false, - home: StreamChatTheme( - data: StreamChatThemeData(brightness: brightness), - child: Builder( - builder: (context) { - final theme = StreamChatTheme.of(context); - return Scaffold( - backgroundColor: theme.colorTheme.appBg, - bottomNavigationBar: Material( - elevation: 10, - color: theme.colorTheme.barsBg, - child: Padding( - padding: const EdgeInsets.all(8), - child: widget, - ), - ), - ); - }, - ), - ), - ); -} diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_dark.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_dark.png index 575be478cb..424f99a3b6 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_dark.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_dark.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_light.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_light.png index aab51b08c1..e546305403 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_light.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_light.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_dark.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_dark.png index cfdd200ee1..45f0d3dc56 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_dark.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_dark.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_light.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_light.png index fac3a83cae..b2cf494cb2 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_light.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_light.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_dark.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_dark.png index 38524bd115..eed7f37405 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_dark.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_dark.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_light.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_light.png index e9ff74d09c..8317aa1877 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_light.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_reversed_with_reactions_light.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_dark.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_dark.png index eb88364db3..1e1492b3ba 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_dark.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_dark.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_light.png b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_light.png index 660f447e36..dafa52856c 100644 Binary files a/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_light.png and b/packages/stream_chat_flutter/test/src/message_modal/goldens/ci/stream_message_actions_modal_with_reactions_light.png differ diff --git a/packages/stream_chat_flutter/test/src/message_modal/message_actions_modal_test.dart b/packages/stream_chat_flutter/test/src/message_modal/message_actions_modal_test.dart index 457cb06ad7..30352e5505 100644 --- a/packages/stream_chat_flutter/test/src/message_modal/message_actions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_modal/message_actions_modal_test.dart @@ -149,8 +149,8 @@ void main() { Widget buildMessageWidget({bool reverse = false}) { return Builder( builder: (context) { - final theme = StreamChatTheme.of(context); - final messageTheme = theme.getMessageTheme(reverse: reverse); + final messageTheme = context.streamMessageTheme.mergeWithDefaults(context); + final messageStyle = reverse ? messageTheme.outgoing! : messageTheme.incoming!; return Container( padding: const EdgeInsets.symmetric( @@ -159,11 +159,11 @@ void main() { ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(14), - color: messageTheme.messageBackgroundColor, + color: messageStyle.backgroundColor, ), child: Text( message.text ?? '', - style: messageTheme.messageTextStyle, + style: TextStyle(color: messageStyle.textColor), ), ); }, diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart deleted file mode 100644 index 96cb7fd979..0000000000 --- a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'package:flutter/material.dart' hide TextTheme; -import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -void main() { - test('MessageInputThemeData copyWith, ==, hashCode basics', () { - expect(const StreamMessageInputThemeData(), const StreamMessageInputThemeData().copyWith()); - expect(const StreamMessageInputThemeData().hashCode, const StreamMessageInputThemeData().copyWith().hashCode); - }); - - group('MessageInputThemeData lerps correctly', () { - test('Lerp completely from light to dark', () { - expect( - const StreamMessageInputThemeData().lerp(_messageInputThemeControl, _messageInputThemeControlDark, 1), - _messageInputThemeControlDark, - ); - }); - - test('Lerp halfway from light to dark', () { - expect( - const StreamMessageInputThemeData().lerp( - _messageInputThemeControl, - _messageInputThemeControlDark, - 0.5, - ), - _messageInputThemeControlMidLerp, - // TODO: Remove skip, once we drop support for flutter v3.24.0 - skip: true, - reason: 'Currently failing in flutter v3.27.0 due to new color alpha', - ); - }); - - test('Lerp completely from dark to light', () { - expect( - const StreamMessageInputThemeData().lerp(_messageInputThemeControlDark, _messageInputThemeControl, 1), - _messageInputThemeControl, - ); - }); - }); - - test('Merging two MessageInputThemeData results in the latter', () { - expect(_messageInputThemeControl.merge(_messageInputThemeControlDark), _messageInputThemeControlDark); - }); -} - -final _messageInputThemeControl = StreamMessageInputThemeData( - borderRadius: BorderRadius.circular(20), - sendAnimationDuration: const Duration(milliseconds: 300), - actionButtonColor: const StreamColorTheme.light().accentPrimary, - actionButtonIdleColor: const StreamColorTheme.light().textLowEmphasis, - expandButtonColor: const StreamColorTheme.light().accentPrimary, - sendButtonColor: const StreamColorTheme.light().accentPrimary, - sendButtonIdleColor: const StreamColorTheme.light().disabled, - inputBackgroundColor: const StreamColorTheme.light().barsBg, - inputTextStyle: const StreamTextTheme.light().body, - idleBorderGradient: LinearGradient( - stops: const [0.0, 1.0], - colors: [ - const StreamColorTheme.light().disabled, - const StreamColorTheme.light().disabled, - ], - ), - activeBorderGradient: LinearGradient( - stops: const [0.0, 1.0], - colors: [ - const StreamColorTheme.light().disabled, - const StreamColorTheme.light().disabled, - ], - ), -); - -final _messageInputThemeControlMidLerp = StreamMessageInputThemeData( - borderRadius: BorderRadius.circular(20), - sendAnimationDuration: const Duration(milliseconds: 300), - inputBackgroundColor: const Color(0xff88898a), - actionButtonColor: const Color(0xff196eff), - actionButtonIdleColor: const Color(0xff7a7a7a), - sendButtonColor: const Color(0xff196eff), - sendButtonIdleColor: const Color(0xff848585), - expandButtonColor: const Color(0xff196eff), - inputTextStyle: const TextStyle( - color: Color(0xff7f7f7f), - fontSize: 14, - fontWeight: FontWeight.w400, - ), - idleBorderGradient: const LinearGradient( - stops: [0.0, 1.0], - colors: [ - Color(0xff848585), - Color(0xff848585), - ], - ), - activeBorderGradient: const LinearGradient( - stops: [0.0, 1.0], - colors: [ - Color(0xff848585), - Color(0xff848585), - ], - ), -); - -final _messageInputThemeControlDark = StreamMessageInputThemeData( - borderRadius: BorderRadius.circular(20), - sendAnimationDuration: const Duration(milliseconds: 300), - actionButtonColor: const StreamColorTheme.dark().accentPrimary, - actionButtonIdleColor: const StreamColorTheme.dark().textLowEmphasis, - expandButtonColor: const StreamColorTheme.dark().accentPrimary, - sendButtonColor: const StreamColorTheme.dark().accentPrimary, - sendButtonIdleColor: const StreamColorTheme.dark().disabled, - inputBackgroundColor: const StreamColorTheme.dark().barsBg, - inputTextStyle: const StreamTextTheme.dark().body, - idleBorderGradient: LinearGradient( - stops: const [0.0, 1.0], - colors: [ - const StreamColorTheme.dark().disabled, - const StreamColorTheme.dark().disabled, - ], - ), - activeBorderGradient: LinearGradient( - stops: const [0.0, 1.0], - colors: [ - const StreamColorTheme.dark().disabled, - const StreamColorTheme.dark().disabled, - ], - ), -); diff --git a/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart deleted file mode 100644 index d8759b2be3..0000000000 --- a/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:flutter/material.dart' hide TextTheme; -import 'package:flutter_test/flutter_test.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; - -String _dummyFormatter(BuildContext context, DateTime date) => 'formatted'; - -void main() { - test('MessageThemeData copyWith, ==, hashCode basics', () { - expect(const StreamMessageThemeData(), const StreamMessageThemeData().copyWith()); - expect(const StreamMessageThemeData().hashCode, const StreamMessageThemeData().copyWith().hashCode); - }); - - group('MessageThemeData lerps', () { - test('''Light MessageThemeData lerps completely to dark MessageThemeData''', () { - expect( - const StreamMessageThemeData().lerp(_messageThemeControl, _messageThemeControlDark, 1), - _messageThemeControlDark, - ); - }); - - test('''Dark MessageThemeData lerps completely to light MessageThemeData''', () { - expect( - const StreamMessageThemeData().lerp(_messageThemeControlDark, _messageThemeControl, 1), - _messageThemeControl, - ); - }); - }); - - test('Merging dark and light themes results in a dark theme', () { - expect(_messageThemeControl.merge(_messageThemeControlDark), _messageThemeControlDark); - }); -} - -final _messageThemeControl = StreamMessageThemeData( - messageAuthorStyle: const StreamTextTheme.light().footnote.copyWith( - color: const StreamColorTheme.light().textLowEmphasis, - ), - messageTextStyle: const StreamTextTheme.light().body, - createdAtStyle: const StreamTextTheme.light().footnote.copyWith( - color: const StreamColorTheme.light().textLowEmphasis, - ), - createdAtFormatter: _dummyFormatter, - repliesStyle: const StreamTextTheme.light().footnoteBold.copyWith( - color: const StreamColorTheme.light().accentPrimary, - ), - messageBackgroundColor: const StreamColorTheme.light().disabled, - reactionsBackgroundColor: const StreamColorTheme.light().barsBg, - reactionsBorderColor: const StreamColorTheme.light().borders, - reactionsMaskColor: const StreamColorTheme.light().appBg, - messageBorderColor: const StreamColorTheme.light().disabled, - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(20), - constraints: const BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - messageLinksStyle: TextStyle( - color: const StreamColorTheme.light().accentPrimary, - ), - urlAttachmentBackgroundColor: const StreamColorTheme.light().linkBg, -); - -final _messageThemeControlDark = StreamMessageThemeData( - messageAuthorStyle: const StreamTextTheme.dark().footnote.copyWith( - color: const StreamColorTheme.dark().textLowEmphasis, - ), - messageTextStyle: const StreamTextTheme.dark().body, - createdAtStyle: const StreamTextTheme.dark().footnote.copyWith( - color: const StreamColorTheme.dark().textLowEmphasis, - ), - createdAtFormatter: _dummyFormatter, - repliesStyle: const StreamTextTheme.dark().footnoteBold.copyWith( - color: const StreamColorTheme.dark().accentPrimary, - ), - messageBackgroundColor: const StreamColorTheme.dark().disabled, - reactionsBackgroundColor: const StreamColorTheme.dark().barsBg, - reactionsBorderColor: const StreamColorTheme.dark().borders, - reactionsMaskColor: const StreamColorTheme.dark().appBg, - messageBorderColor: const StreamColorTheme.dark().disabled, - avatarTheme: StreamAvatarThemeData( - borderRadius: BorderRadius.circular(20), - constraints: const BoxConstraints.tightFor( - height: 32, - width: 32, - ), - ), - messageLinksStyle: TextStyle( - color: const StreamColorTheme.dark().accentPrimary, - ), - urlAttachmentBackgroundColor: const StreamColorTheme.dark().linkBg, -); diff --git a/sample_app/lib/pages/channel_file_display_screen.dart b/sample_app/lib/pages/channel_file_display_screen.dart index 215778e9dc..ee11f065dd 100644 --- a/sample_app/lib/pages/channel_file_display_screen.dart +++ b/sample_app/lib/pages/channel_file_display_screen.dart @@ -5,11 +5,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; class ChannelFileDisplayScreen extends StatefulWidget { - const ChannelFileDisplayScreen({ - super.key, - required this.messageTheme, - }); - final StreamMessageThemeData messageTheme; + const ChannelFileDisplayScreen({super.key}); @override State createState() => _ChannelFileDisplayScreenState(); diff --git a/sample_app/lib/pages/channel_media_display_screen.dart b/sample_app/lib/pages/channel_media_display_screen.dart index 805dc45e65..9a82291b29 100644 --- a/sample_app/lib/pages/channel_media_display_screen.dart +++ b/sample_app/lib/pages/channel_media_display_screen.dart @@ -7,11 +7,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:video_player/video_player.dart'; class ChannelMediaDisplayScreen extends StatefulWidget { - const ChannelMediaDisplayScreen({ - super.key, - required this.messageTheme, - }); - final StreamMessageThemeData messageTheme; + const ChannelMediaDisplayScreen({super.key}); @override State createState() => _ChannelMediaDisplayScreenState(); diff --git a/sample_app/lib/pages/chat_info_screen.dart b/sample_app/lib/pages/chat_info_screen.dart index 8281ab7607..095bd6b065 100644 --- a/sample_app/lib/pages/chat_info_screen.dart +++ b/sample_app/lib/pages/chat_info_screen.dart @@ -11,15 +11,12 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ChatInfoScreen extends StatefulWidget { const ChatInfoScreen({ super.key, - required this.messageTheme, this.user, }); /// User in consideration final User? user; - final StreamMessageThemeData messageTheme; - @override State createState() => _ChatInfoScreenState(); } @@ -207,9 +204,7 @@ class _ChatInfoScreenState extends State { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: ChannelMediaDisplayScreen( - messageTheme: widget.messageTheme, - ), + child: const ChannelMediaDisplayScreen(), ), ), ); @@ -239,9 +234,7 @@ class _ChatInfoScreenState extends State { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: ChannelFileDisplayScreen( - messageTheme: widget.messageTheme, - ), + child: const ChannelFileDisplayScreen(), ), ), ); diff --git a/sample_app/lib/pages/group_info_screen.dart b/sample_app/lib/pages/group_info_screen.dart index eef631162f..1d4688597d 100644 --- a/sample_app/lib/pages/group_info_screen.dart +++ b/sample_app/lib/pages/group_info_screen.dart @@ -13,11 +13,7 @@ import 'package:sample_app/routes/routes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class GroupInfoScreen extends StatefulWidget { - const GroupInfoScreen({ - super.key, - required this.messageTheme, - }); - final StreamMessageThemeData messageTheme; + const GroupInfoScreen({super.key}); @override State createState() => _GroupInfoScreenState(); @@ -493,9 +489,7 @@ class _GroupInfoScreenState extends State { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: ChannelMediaDisplayScreen( - messageTheme: widget.messageTheme, - ), + child: const ChannelMediaDisplayScreen(), ), ), ); @@ -514,9 +508,7 @@ class _GroupInfoScreenState extends State { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: ChannelFileDisplayScreen( - messageTheme: widget.messageTheme, - ), + child: const ChannelFileDisplayScreen(), ), ), ); diff --git a/sample_app/lib/routes/app_routes.dart b/sample_app/lib/routes/app_routes.dart index ef0f41dce5..d3b8fd6a7f 100644 --- a/sample_app/lib/routes/app_routes.dart +++ b/sample_app/lib/routes/app_routes.dart @@ -58,7 +58,6 @@ final appRoutes = [ channel: channel!, child: ChatInfoScreen( user: state.extra as User?, - messageTheme: StreamChatTheme.of(context).ownMessageTheme, ), ); }, @@ -70,9 +69,7 @@ final appRoutes = [ final channel = StreamChat.of(context).client.state.channels[state.pathParameters['cid']]; return StreamChannel( channel: channel!, - child: GroupInfoScreen( - messageTheme: StreamChatTheme.of(context).ownMessageTheme, - ), + child: const GroupInfoScreen(), ); }, ), diff --git a/sample_app/lib/widgets/channel_list.dart b/sample_app/lib/widgets/channel_list.dart index 8eb24eb3ec..c41884bca9 100644 --- a/sample_app/lib/widgets/channel_list.dart +++ b/sample_app/lib/widgets/channel_list.dart @@ -151,15 +151,12 @@ class _ChannelListDefault extends StatelessWidget { channel: channel, child: isOneToOne ? ChatInfoScreen( - messageTheme: chatTheme.ownMessageTheme, user: channel.state!.members .where((m) => m.userId != channel.client.state.currentUser!.id) .first .user, ) - : GroupInfoScreen( - messageTheme: chatTheme.ownMessageTheme, - ), + : const GroupInfoScreen(), ); }, ),