Merge pull request #1002 from GetStream/refactor/deprecate-v3

refactor(ui, core): deprecate v3
This commit is contained in:
Salvatore Giordano
2022-03-17 10:46:25 +01:00
committed by GitHub
138 changed files with 3979 additions and 1510 deletions
@@ -15,6 +15,7 @@ on:
jobs: jobs:
analyze: analyze:
timeout-minutes: 15 timeout-minutes: 15
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "Git Checkout" - name: "Git Checkout"
@@ -45,6 +46,7 @@ jobs:
format: format:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
timeout-minutes: 15 timeout-minutes: 15
steps: steps:
- name: "Git Checkout" - name: "Git Checkout"
@@ -73,6 +75,7 @@ jobs:
test: test:
runs-on: macos-latest runs-on: macos-latest
if: github.event.pull_request.draft == false
timeout-minutes: 20 timeout-minutes: 20
steps: steps:
- name: "Git Checkout" - name: "Git Checkout"
@@ -123,3 +126,12 @@ jobs:
with: with:
path: packages/stream_chat_flutter/coverage/lcov.info path: packages/stream_chat_flutter/coverage/lcov.info
min_coverage: 67 min_coverage: 67
draft-build:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == true
timeout-minutes: 1
steps:
- name: Run a one-line script
run: echo Draft PR, you are good.
+6
View File
@@ -1,3 +1,9 @@
## 3.5.1
🐞 Fixed
- `channel.unreadCount` was being set as using global unread count on a very specific case.
- The reconnection logic for the WebSocket connection is now more robust.
## 3.5.0 ## 3.5.0
✅ Added ✅ Added
@@ -1926,7 +1926,6 @@ class ChannelClientState {
readList.add(Read( readList.add(Read(
user: event.user!, user: event.user!,
lastRead: event.createdAt, lastRead: event.createdAt,
unreadMessages: event.totalUnreadCount ?? 0,
)); ));
_channelState = _channelState.copyWith(read: readList); _channelState = _channelState.copyWith(read: readList);
} }
+11 -3
View File
@@ -190,8 +190,12 @@ class WebSocket with TimerHelper {
_connectionStatus = ConnectionStatus.connecting; _connectionStatus = ConnectionStatus.connecting;
connectionCompleter = Completer<Event>(); connectionCompleter = Completer<Event>();
final uri = await _buildUri(); try {
_initWebSocketChannel(uri); final uri = await _buildUri();
_initWebSocketChannel(uri);
} catch (e, stk) {
_onConnectionError(e, stk);
}
return connectionCompleter!.future; return connectionCompleter!.future;
} }
@@ -216,7 +220,11 @@ class WebSocket with TimerHelper {
Duration(milliseconds: delay), Duration(milliseconds: delay),
() async { () async {
final uri = await _buildUri(refreshToken: refreshToken); final uri = await _buildUri(refreshToken: refreshToken);
_initWebSocketChannel(uri); try {
_initWebSocketChannel(uri);
} catch (e, stk) {
_onConnectionError(e, stk);
}
}, },
); );
} }
+1 -1
View File
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
/// Current package version /// Current package version
/// Used in [StreamChatClient] to build the `x-stream-client` header /// Used in [StreamChatClient] to build the `x-stream-client` header
// ignore: constant_identifier_names // ignore: constant_identifier_names
const PACKAGE_VERSION = '3.5.0'; const PACKAGE_VERSION = '3.5.1';
+2 -2
View File
@@ -1,7 +1,7 @@
name: stream_chat name: stream_chat
homepage: https://getstream.io/ homepage: https://getstream.io/
description: The official Dart client for Stream Chat, a service for building chat applications. description: The official Dart client for Stream Chat, a service for building chat applications.
version: 3.5.0 version: 3.5.1
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -30,5 +30,5 @@ dev_dependencies:
dart_code_metrics: ^4.4.0 dart_code_metrics: ^4.4.0
freezed: ^1.0.0 freezed: ^1.0.0
json_serializable: ^6.0.1 json_serializable: ^6.0.1
mocktail: ^0.2.0 mocktail: ^0.3.0
test: ^1.17.12 test: ^1.17.12
+3 -2
View File
@@ -1,4 +1,4 @@
## Upcoming ## 3.5.1
🛑️ Breaking Changes 🛑️ Breaking Changes
@@ -7,7 +7,8 @@
🐞 Fixed 🐞 Fixed
- Mentions overlay now doesn't overflow when not enough height available - Mentions overlay now doesn't overflow when there is not enough height available
- Updated `stream_chat_flutter_core` dependency to [`3.5.1`](https://pub.dev/packages/stream_chat_flutter_core/changelog).
## 3.5.0 ## 3.5.0
@@ -87,7 +87,7 @@ class MyApp extends StatelessWidget {
/// A list of messages sent in the current channel. /// A list of messages sent in the current channel.
/// ///
/// This is implemented using [MessageListView], a widget that provides query /// This is implemented using [StreamMessageListView], a widget that provides query
/// functionalities fetching the messages from the api and showing them in a /// functionalities fetching the messages from the api and showing them in a
/// listView. /// listView.
class ChannelPage extends StatelessWidget { class ChannelPage extends StatelessWidget {
@@ -98,13 +98,13 @@ class ChannelPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: const <Widget>[ children: const <Widget>[
Expanded( Expanded(
child: MessageListView(), child: StreamMessageListView(),
), ),
MessageInput(attachmentLimit: 3), StreamMessageInput(attachmentLimit: 3),
], ],
), ),
); );
@@ -125,15 +125,15 @@ class ChannelPage extends StatelessWidget {
Widget build(BuildContext context) => Navigator( Widget build(BuildContext context) => Navigator(
onGenerateRoute: (settings) => MaterialPageRoute( onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => Scaffold( builder: (context) => Scaffold(
appBar: const ChannelHeader( appBar: const StreamChannelHeader(
showBackButton: false, showBackButton: false,
), ),
body: Column( body: Column(
children: const <Widget>[ children: const <Widget>[
Expanded( Expanded(
child: MessageListView(), child: StreamMessageListView(),
), ),
MessageInput(), StreamMessageInput(),
], ],
), ),
), ),
@@ -27,7 +27,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// - We make [StreamChat] the root Widget of our application /// - We make [StreamChat] the root Widget of our application
/// ///
/// - We create a single [ChannelPage] widget under [StreamChat] with three /// - We create a single [ChannelPage] widget under [StreamChat] with three
/// widgets: [ChannelHeader], [MessageListView] and [MessageInput] /// widgets: [StreamChannelHeader], [StreamMessageListView] and [StreamMessageInput]
/// ///
/// If you now run the simulator you will see a single channel UI. /// If you now run the simulator you will see a single channel UI.
void main() async { void main() async {
@@ -91,13 +91,13 @@ class ChannelPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: const <Widget>[ children: const <Widget>[
Expanded( Expanded(
child: MessageListView(), child: StreamMessageListView(),
), ),
MessageInput(), StreamMessageInput(),
], ],
), ),
); );
@@ -25,7 +25,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// The [ChannelListPage] widget retrieves the list of channels based on a /// The [ChannelListPage] widget retrieves the list of channels based on a
/// custom query and ordering. In this case we are showing the list of /// custom query and ordering. In this case we are showing the list of
/// channels in which the current user is a member and we order them based /// channels in which the current user is a member and we order them based
/// on the time they had a new message. [ChannelListView] handles pagination /// on the time they had a new message. [StreamChannelListView] handles pagination
/// and updates automatically when new channels are created or when a new /// and updates automatically when new channels are created or when a new
/// message is added to a channel. /// message is added to a channel.
void main() async { void main() async {
@@ -118,13 +118,13 @@ class ChannelPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: const <Widget>[ children: const <Widget>[
Expanded( Expanded(
child: MessageListView(), child: StreamMessageListView(),
), ),
MessageInput(), StreamMessageInput(),
], ],
), ),
); );
@@ -15,8 +15,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// We start by changing how channel previews are shown in the channel list /// We start by changing how channel previews are shown in the channel list
/// and include the number of unread messages for each. /// and include the number of unread messages for each.
/// ///
/// We're passing a custom widget to [ChannelListView.channelPreviewBuilder]; /// We're passing a custom widget to [StreamChannelListView.channelPreviewBuilder];
/// this will override the default [ChannelPreview] and allows you to create /// this will override the default [StreamChannelPreview] and allows you to create
/// one yourself. /// one yourself.
/// ///
/// There are a couple interesting things we do in this widget: /// There are a couple interesting things we do in this widget:
@@ -134,7 +134,7 @@ class _ChannelListPageState extends State<ChannelListPage> {
channel: channel, channel: channel,
), ),
title: StreamChannelName( title: StreamChannelName(
textStyle: ChannelPreviewTheme.of(context).titleStyle!.copyWith( textStyle: StreamChannelPreviewTheme.of(context).titleStyle!.copyWith(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
.textHighEmphasis .textHighEmphasis
@@ -162,13 +162,13 @@ class ChannelPage extends StatelessWidget {
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: const <Widget>[ children: const <Widget>[
Expanded( Expanded(
child: MessageListView(), child: StreamMessageListView(),
), ),
MessageInput(), StreamMessageInput(),
], ],
), ),
); );
@@ -8,8 +8,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// to create sub-conversations inside the same channel. /// to create sub-conversations inside the same channel.
/// ///
/// Using threaded conversations is very simple and mostly a matter of /// Using threaded conversations is very simple and mostly a matter of
/// plugging the [MessageListView] to another widget that renders the widget. /// plugging the [StreamMessageListView] to another widget that renders the widget.
/// To make this simple, such a widget only needs to build [MessageListView] /// To make this simple, such a widget only needs to build [StreamMessageListView]
/// with the parent attribute set to the threads root message. /// with the parent attribute set to the threads root message.
/// ///
/// Now we can open threads and create new ones as well. If you long-press a /// Now we can open threads and create new ones as well. If you long-press a
@@ -98,17 +98,17 @@ class ChannelPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: MessageListView( child: StreamMessageListView(
threadBuilder: (_, parentMessage) => ThreadPage( threadBuilder: (_, parentMessage) => ThreadPage(
parent: parentMessage, parent: parentMessage,
), ),
), ),
), ),
const MessageInput(), const StreamMessageInput(),
], ],
), ),
); );
@@ -126,17 +126,17 @@ class ThreadPage extends StatelessWidget {
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: ThreadHeader( appBar: StreamThreadHeader(
parent: parent!, parent: parent!,
), ),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: MessageListView( child: StreamMessageListView(
parentMessage: parent, parentMessage: parent,
), ),
), ),
MessageInput( StreamMessageInput(
messageInputController: MessageInputController( messageInputController: MessageInputController(
message: Message(parentId: parent!.id), message: Message(parentId: parent!.id),
), ),
@@ -8,7 +8,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// the SDK supports easily. /// the SDK supports easily.
/// ///
/// Replacing the built-in message component with your own is done by passing /// Replacing the built-in message component with your own is done by passing
/// it as a builder function to the [MessageListView] widget. /// it as a builder function to the [StreamMessageListView] widget.
/// ///
/// The message builder function will get the usual [BuildContext] argument /// The message builder function will get the usual [BuildContext] argument
/// as well as the [Message] object and its position inside the list. /// as well as the [Message] object and its position inside the list.
@@ -106,15 +106,15 @@ class ChannelPage extends StatelessWidget {
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: MessageListView( child: StreamMessageListView(
messageBuilder: _messageBuilder, messageBuilder: _messageBuilder,
), ),
), ),
const MessageInput(), const StreamMessageInput(),
], ],
), ),
); );
@@ -124,7 +124,7 @@ class ChannelPage extends StatelessWidget {
BuildContext context, BuildContext context,
MessageDetails details, MessageDetails details,
List<Message> messages, List<Message> messages,
MessageWidget _, StreamMessageWidget _,
) { ) {
final message = details.message; final message = details.message;
final isCurrentUser = final isCurrentUser =
@@ -58,24 +58,24 @@ class MyApp extends StatelessWidget {
final defaultTheme = StreamChatThemeData.fromTheme(themeData); final defaultTheme = StreamChatThemeData.fromTheme(themeData);
final colorTheme = defaultTheme.colorTheme; final colorTheme = defaultTheme.colorTheme;
final customTheme = defaultTheme.merge(StreamChatThemeData( final customTheme = defaultTheme.merge(StreamChatThemeData(
channelPreviewTheme: ChannelPreviewThemeData( channelPreviewTheme: StreamChannelPreviewThemeData(
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
messageListViewTheme: const MessageListViewThemeData( messageListViewTheme: const StreamMessageListViewThemeData(
backgroundColor: Colors.grey, backgroundColor: Colors.grey,
backgroundImage: DecorationImage( backgroundImage: DecorationImage(
image: AssetImage('assets/background_doodle.png'), image: AssetImage('assets/background_doodle.png'),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
otherMessageTheme: MessageThemeData( otherMessageTheme: StreamMessageThemeData(
messageBackgroundColor: colorTheme.textHighEmphasis, messageBackgroundColor: colorTheme.textHighEmphasis,
messageTextStyle: TextStyle( messageTextStyle: TextStyle(
color: colorTheme.barsBg, color: colorTheme.barsBg,
), ),
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
@@ -137,17 +137,17 @@ class ChannelPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(), appBar: const StreamChannelHeader(),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: MessageListView( child: StreamMessageListView(
threadBuilder: (_, parentMessage) => ThreadPage( threadBuilder: (_, parentMessage) => ThreadPage(
parent: parentMessage, parent: parentMessage,
), ),
), ),
), ),
const MessageInput(), const StreamMessageInput(),
], ],
), ),
); );
@@ -165,17 +165,17 @@ class ThreadPage extends StatelessWidget {
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: ThreadHeader( appBar: StreamThreadHeader(
parent: parent!, parent: parent!,
), ),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: MessageListView( child: StreamMessageListView(
parentMessage: parent, parentMessage: parent,
), ),
), ),
MessageInput( StreamMessageInput(
messageInputController: MessageInputController( messageInputController: MessageInputController(
message: Message(parentId: parent!.id), message: Message(parentId: parent!.id),
), ),
@@ -1,17 +1,23 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro attachment_title}
@Deprecated("Use 'StreamAttachmentTitle' instead")
typedef AttachmentTitle = StreamAttachmentTitle;
/// {@template attachment_title}
/// Title for attachments /// Title for attachments
class AttachmentTitle extends StatelessWidget { /// {@endtemplate}
class StreamAttachmentTitle extends StatelessWidget {
/// Supply attachment and theme for constructing title /// Supply attachment and theme for constructing title
const AttachmentTitle({ const StreamAttachmentTitle({
Key? key, Key? key,
required this.attachment, required this.attachment,
required this.messageTheme, required this.messageTheme,
}) : super(key: key); }) : super(key: key);
/// Theme to apply to text /// Theme to apply to text
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Attachment data to display /// Attachment data to display
final Attachment attachment; final Attachment attachment;
@@ -9,10 +9,16 @@ typedef InProgressBuilder = Widget Function(BuildContext, int, int);
/// Widget to build on failure /// Widget to build on failure
typedef FailedBuilder = Widget Function(BuildContext, String); typedef FailedBuilder = Widget Function(BuildContext, String);
/// {@macro attachment_upload_state_builder}
@Deprecated("Use 'StreamAttachmentsUploadStateBuilder' instead")
typedef AttachmentUploadStateBuilder = StreamAttachmentUploadStateBuilder;
/// {@template attachment_upload_state_builder}
/// Widget to display attachment upload state /// Widget to display attachment upload state
class AttachmentUploadStateBuilder extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating an [AttachmentUploadStateBuilder] widget class StreamAttachmentUploadStateBuilder extends StatelessWidget {
const AttachmentUploadStateBuilder({ /// Constructor for creating an [StreamAttachmentUploadStateBuilder] widget
const StreamAttachmentUploadStateBuilder({
Key? key, Key? key,
required this.message, required this.message,
required this.attachment, required this.attachment,
@@ -137,7 +143,7 @@ class _PreparingState extends StatelessWidget {
), ),
Align( Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: UploadProgressIndicator( child: StreamUploadProgressIndicator(
uploaded: 0, uploaded: 0,
total: double.maxFinite.toInt(), total: double.maxFinite.toInt(),
), ),
@@ -177,7 +183,7 @@ class _InProgressState extends StatelessWidget {
), ),
Align( Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: UploadProgressIndicator( child: StreamUploadProgressIndicator(
uploaded: sent, uploaded: sent,
total: total, total: total,
), ),
@@ -28,10 +28,16 @@ extension AttachmentSourceX on AttachmentSource {
} }
} }
/// {@macro attachment_widget}
@Deprecated("Use 'StreamAttachmentWidget' instead")
typedef AttachmentWidget = StreamAttachmentWidget;
/// {@template attachment_widget}
/// Abstract class for deriving attachment types /// Abstract class for deriving attachment types
abstract class AttachmentWidget extends StatelessWidget { /// {@endtemplate}
abstract class StreamAttachmentWidget extends StatelessWidget {
/// Constructor for creating attachment widget /// Constructor for creating attachment widget
const AttachmentWidget({ const StreamAttachmentWidget({
Key? key, Key? key,
required this.message, required this.message,
required this.attachment, required this.attachment,
@@ -10,10 +10,16 @@ import 'package:stream_chat_flutter/src/utils.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// {@macro file_attachment}
@Deprecated("Use 'StreamFileAttachment' instead")
typedef FileAttachment = StreamFileAttachment;
/// {@template file_attachment}
/// Widget for displaying file attachments /// Widget for displaying file attachments
class FileAttachment extends AttachmentWidget { /// {@endtemplate}
class StreamFileAttachment extends StreamAttachmentWidget {
/// Constructor for creating a widget when attachment is of type 'file' /// Constructor for creating a widget when attachment is of type 'file'
const FileAttachment({ const StreamFileAttachment({
Key? key, Key? key,
required Message message, required Message message,
required Attachment attachment, required Attachment attachment,
@@ -157,7 +163,7 @@ class FileAttachment extends AttachmentWidget {
type: MaterialType.transparency, type: MaterialType.transparency,
shape: _getDefaultShape(context), shape: _getDefaultShape(context),
child: source.when( child: source.when(
local: () => VideoThumbnailImage( local: () => StreamVideoThumbnailImage(
fit: BoxFit.cover, fit: BoxFit.cover,
video: attachment.file!.path!, video: attachment.file!.path!,
placeholderBuilder: (_) => const Center( placeholderBuilder: (_) => const Center(
@@ -168,7 +174,7 @@ class FileAttachment extends AttachmentWidget {
), ),
), ),
), ),
network: () => VideoThumbnailImage( network: () => StreamVideoThumbnailImage(
fit: BoxFit.cover, fit: BoxFit.cover,
video: attachment.assetUrl!, video: attachment.assetUrl!,
placeholderBuilder: (_) => const Center( placeholderBuilder: (_) => const Center(
@@ -278,7 +284,7 @@ class FileAttachment extends AttachmentWidget {
); );
return attachment.uploadState.when( return attachment.uploadState.when(
preparing: () => Text(fileSize(size), style: textStyle), preparing: () => Text(fileSize(size), style: textStyle),
inProgress: (sent, total) => UploadProgressIndicator( inProgress: (sent, total) => StreamUploadProgressIndicator(
uploaded: sent, uploaded: sent,
total: total, total: total,
showBackground: false, showBackground: false,
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro giphy_attachment}
@Deprecated("Use 'StreamGiphyAttachment' instead")
typedef GiphyAttachment = StreamGiphyAttachment;
/// {@template giphy_attachment}
/// Widget for showing a GIF attachment /// Widget for showing a GIF attachment
class GiphyAttachment extends AttachmentWidget { /// {@endtemplate}
/// Constructor for creating a [GiphyAttachment] widget class StreamGiphyAttachment extends StreamAttachmentWidget {
const GiphyAttachment({ /// Constructor for creating a [StreamGiphyAttachment] widget
const StreamGiphyAttachment({
Key? key, Key? key,
required Message message, required Message message,
required Attachment attachment, required Attachment attachment,
@@ -228,7 +234,7 @@ class GiphyAttachment extends AttachmentWidget {
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: VisibleFootnote(), child: StreamVisibleFootnote(),
), ),
), ),
], ],
@@ -243,7 +249,7 @@ class GiphyAttachment extends AttachmentWidget {
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
return StreamChannel( return StreamChannel(
channel: channel, channel: channel,
child: FullScreenMedia( child: StreamFullScreenMedia(
mediaAttachments: message.attachments, mediaAttachments: message.attachments,
startIndex: message.attachments.indexOf(attachment), startIndex: message.attachments.indexOf(attachment),
userName: message.user?.name, userName: message.user?.name,
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_title.dart';
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro image_attachment}
@Deprecated("use 'StreamImageAttachment' instead")
typedef ImageAttachment = StreamImageAttachment;
/// {@template image_attachment}
/// Widget for showing an image attachment /// Widget for showing an image attachment
class ImageAttachment extends AttachmentWidget { /// {@endtemplate}
/// Constructor for creating a [ImageAttachment] widget class StreamImageAttachment extends StreamAttachmentWidget {
const ImageAttachment({ /// Constructor for creating a [StreamImageAttachment] widget
const StreamImageAttachment({
Key? key, Key? key,
required Message message, required Message message,
required Attachment attachment, required Attachment attachment,
@@ -25,8 +31,8 @@ class ImageAttachment extends AttachmentWidget {
size: size, size: size,
); );
/// [MessageThemeData] for showing image title /// [StreamMessageThemeData] for showing image title
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Flag for showing title /// Flag for showing title
final bool showTitle; final bool showTitle;
@@ -137,7 +143,7 @@ class ImageAttachment extends AttachmentWidget {
StreamChannel.of(context).channel; StreamChannel.of(context).channel;
return StreamChannel( return StreamChannel(
channel: channel, channel: channel,
child: FullScreenMedia( child: StreamFullScreenMedia(
mediaAttachments: message.attachments, mediaAttachments: message.attachments,
startIndex: startIndex:
message.attachments.indexOf(attachment), message.attachments.indexOf(attachment),
@@ -155,7 +161,7 @@ class ImageAttachment extends AttachmentWidget {
), ),
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: AttachmentUploadStateBuilder( child: StreamAttachmentUploadStateBuilder(
message: message, message: message,
attachment: attachment, attachment: attachment,
), ),
@@ -166,7 +172,7 @@ class ImageAttachment extends AttachmentWidget {
if (showTitle && attachment.title != null) if (showTitle && attachment.title != null)
Material( Material(
color: messageTheme.messageBackgroundColor, color: messageTheme.messageBackgroundColor,
child: AttachmentTitle( child: StreamAttachmentTitle(
messageTheme: messageTheme, messageTheme: messageTheme,
attachment: attachment, attachment: attachment,
), ),
@@ -2,10 +2,16 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro url_attachment}
@Deprecated("Use 'StreamUrlAttachment' instead")
typedef UrlAttachment = StreamUrlAttachment;
/// {@template url_attachment}
/// Widget to display URL attachment /// Widget to display URL attachment
class UrlAttachment extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [UrlAttachment] class StreamUrlAttachment extends StatelessWidget {
const UrlAttachment({ /// Constructor for creating a [StreamUrlAttachment]
const StreamUrlAttachment({
Key? key, Key? key,
required this.urlAttachment, required this.urlAttachment,
required this.hostDisplayName, required this.hostDisplayName,
@@ -25,8 +31,8 @@ class UrlAttachment extends StatelessWidget {
/// Padding for text /// Padding for text
final EdgeInsets textPadding; final EdgeInsets textPadding;
/// [MessageThemeData] for showing image title /// [StreamMessageThemeData] for showing image title
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -4,10 +4,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro video_attachment}
@Deprecated("Use 'StreamVideoAttachment' instead")
typedef VideoAttachment = StreamVideoAttachment;
/// {@template video_attachment}
/// Widget for showing a video attachment /// Widget for showing a video attachment
class VideoAttachment extends AttachmentWidget { /// {@endtemplate}
/// Constructor for creating a [VideoAttachment] widget class StreamVideoAttachment extends StreamAttachmentWidget {
const VideoAttachment({ /// Constructor for creating a [StreamVideoAttachment] widget
const StreamVideoAttachment({
Key? key, Key? key,
required Message message, required Message message,
required Attachment attachment, required Attachment attachment,
@@ -23,8 +29,8 @@ class VideoAttachment extends AttachmentWidget {
size: size, size: size,
); );
/// [MessageThemeData] for showing title /// [StreamMessageThemeData] for showing title
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Callback when show message is tapped /// Callback when show message is tapped
final ShowMessageCallback? onShowMessage; final ShowMessageCallback? onShowMessage;
@@ -43,7 +49,7 @@ class VideoAttachment extends AttachmentWidget {
} }
return _buildVideoAttachment( return _buildVideoAttachment(
context, context,
VideoThumbnailImage( StreamVideoThumbnailImage(
video: attachment.file!.path!, video: attachment.file!.path!,
height: size?.height, height: size?.height,
width: size?.width, width: size?.width,
@@ -58,7 +64,7 @@ class VideoAttachment extends AttachmentWidget {
} }
return _buildVideoAttachment( return _buildVideoAttachment(
context, context,
VideoThumbnailImage( StreamVideoThumbnailImage(
video: attachment.assetUrl!, video: attachment.assetUrl!,
height: size?.height, height: size?.height,
width: size?.width, width: size?.width,
@@ -84,7 +90,7 @@ class VideoAttachment extends AttachmentWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (_) => StreamChannel( builder: (_) => StreamChannel(
channel: channel, channel: channel,
child: FullScreenMedia( child: StreamFullScreenMedia(
mediaAttachments: message.attachments, mediaAttachments: message.attachments,
startIndex: startIndex:
message.attachments.indexOf(attachment), message.attachments.indexOf(attachment),
@@ -111,7 +117,7 @@ class VideoAttachment extends AttachmentWidget {
), ),
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: AttachmentUploadStateBuilder( child: StreamAttachmentUploadStateBuilder(
message: message, message: message,
attachment: attachment, attachment: attachment,
), ),
@@ -123,7 +129,7 @@ class VideoAttachment extends AttachmentWidget {
if (attachment.title != null) if (attachment.title != null)
Material( Material(
color: messageTheme.messageBackgroundColor, color: messageTheme.messageBackgroundColor,
child: AttachmentTitle( child: StreamAttachmentTitle(
messageTheme: messageTheme, messageTheme: messageTheme,
attachment: attachment, attachment: attachment,
), ),
@@ -58,7 +58,7 @@ class AttachmentActionsModal extends StatelessWidget {
/// List of custom actions /// List of custom actions
final List<AttachmentAction> customActions; final List<AttachmentAction> customActions;
/// Creates a copy of [MessageWidget] with specified attributes overridden. /// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
AttachmentActionsModal copyWith({ AttachmentActionsModal copyWith({
Key? key, Key? key,
int? currentIndex, int? currentIndex,
@@ -50,7 +50,7 @@ class StreamBackButton extends StatelessWidget {
Positioned( Positioned(
top: 7, top: 7,
right: 7, right: 7,
child: UnreadIndicator( child: StreamUnreadIndicator(
cid: cid, cid: cid,
), ),
), ),
@@ -152,7 +152,7 @@ class ChannelAvatar extends StatelessWidget {
return BetterStreamBuilder<User>( return BetterStreamBuilder<User>(
stream: streamChat.client.state.currentUserStream.map((it) => it!), stream: streamChat.client.state.currentUserStream.map((it) => it!),
initialData: currentUser, initialData: currentUser,
builder: (context, user) => UserAvatar( builder: (context, user) => StreamUserAvatar(
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
user: user, user: user,
constraints: constraints ?? previewTheme?.constraints, constraints: constraints ?? previewTheme?.constraints,
@@ -175,7 +175,7 @@ class ChannelAvatar extends StatelessWidget {
), ),
), ),
initialData: member, initialData: member,
builder: (context, member) => UserAvatar( builder: (context, member) => StreamUserAvatar(
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
user: member.user!, user: member.user!,
constraints: constraints ?? previewTheme?.constraints, constraints: constraints ?? previewTheme?.constraints,
@@ -188,7 +188,7 @@ class ChannelAvatar extends StatelessWidget {
} }
// Group conversation // Group conversation
return GroupAvatar( return StreamGroupAvatar(
members: otherMembers, members: otherMembers,
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
constraints: constraints ?? previewTheme?.constraints, constraints: constraints ?? previewTheme?.constraints,
@@ -4,10 +4,7 @@ import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Bottom Sheet with options /// Bottom Sheet with options
@Deprecated( @Deprecated("Use 'StreamChannelInfoBottomSheet' instead")
"'ChannelBottomSheet' is deprecated and shouldn't be used. "
"Please use 'StreamChannelBottomSheet' instead.",
)
class ChannelBottomSheet extends StatefulWidget { class ChannelBottomSheet extends StatefulWidget {
/// Constructor for creating bottom sheet /// Constructor for creating bottom sheet
const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key); const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key);
@@ -24,7 +21,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
bool _showActions = true; bool _showActions = true;
late StreamChannelState _streamChannelState; late StreamChannelState _streamChannelState;
late ChannelPreviewThemeData _channelPreviewThemeData; late StreamChannelPreviewThemeData _channelPreviewThemeData;
late StreamChatThemeData _streamChatThemeData; late StreamChatThemeData _streamChatThemeData;
late StreamChatState _streamChatState; late StreamChatState _streamChatState;
@@ -58,7 +55,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: ChannelName( child: StreamChannelName(
channel: channel,
textStyle: _streamChatThemeData.textTheme.headlineBold, textStyle: _streamChatThemeData.textTheme.headlineBold,
), ),
), ),
@@ -67,7 +65,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
height: 5, height: 5,
), ),
Center( Center(
child: ChannelInfo( child: StreamChannelInfo(
showTypingIndicator: false, showTypingIndicator: false,
channel: _streamChannelState.channel, channel: _streamChannelState.channel,
textStyle: _channelPreviewThemeData.subtitleStyle, textStyle: _channelPreviewThemeData.subtitleStyle,
@@ -79,7 +77,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
if (channel.isDistinct && channel.memberCount == 2) if (channel.isDistinct && channel.memberCount == 2)
Column( Column(
children: [ children: [
UserAvatar( StreamUserAvatar(
user: members user: members
.firstWhere( .firstWhere(
(e) => e.user?.id != userAsMember.user?.id, (e) => e.user?.id != userAsMember.user?.id,
@@ -122,7 +120,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column( child: Column(
children: [ children: [
UserAvatar( StreamUserAvatar(
user: members[index].user!, user: members[index].user!,
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 64, height: 64,
@@ -150,7 +148,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
const SizedBox( const SizedBox(
height: 24, height: 24,
), ),
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.user( child: StreamSvgIcon.user(
@@ -163,7 +161,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
if (!channel.isDistinct && if (!channel.isDistinct &&
channel.ownCapabilities channel.ownCapabilities
.contains(PermissionType.leaveChannel)) .contains(PermissionType.leaveChannel))
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.userRemove( child: StreamSvgIcon.userRemove(
@@ -184,7 +182,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
if (isOwner && if (isOwner &&
channel.ownCapabilities channel.ownCapabilities
.contains(PermissionType.deleteChannel)) .contains(PermissionType.deleteChannel))
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.delete( child: StreamSvgIcon.delete(
@@ -203,7 +201,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
}); });
}, },
), ),
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.closeSmall( child: StreamSvgIcon.closeSmall(
@@ -224,7 +222,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
void didChangeDependencies() { void didChangeDependencies() {
_streamChannelState = StreamChannel.of(context); _streamChannelState = StreamChannel.of(context);
_streamChatThemeData = StreamChatTheme.of(context); _streamChatThemeData = StreamChatTheme.of(context);
_channelPreviewThemeData = ChannelPreviewTheme.of(context); _channelPreviewThemeData = StreamChannelPreviewTheme.of(context);
_streamChatState = StreamChat.of(context); _streamChatState = StreamChat.of(context);
super.didChangeDependencies(); super.didChangeDependencies();
} }
@@ -4,6 +4,11 @@ import 'package:stream_chat_flutter/src/channel_info.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
///{@macro template_name}
@Deprecated("Use 'StreamChannelHeader' instead")
typedef ChannelHeader = StreamChannelHeader;
/// {@template channel_header}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_header.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_header_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_header_paint.png)
/// ///
@@ -49,9 +54,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// The widget components render the ui based on the first ancestor of type /// The widget components render the ui based on the first ancestor of type
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { /// {@endtemplate}
class StreamChannelHeader extends StatelessWidget
implements PreferredSizeWidget {
/// Creates a channel header /// Creates a channel header
const ChannelHeader({ const StreamChannelHeader({
Key? key, Key? key,
this.showBackButton = true, this.showBackButton = true,
this.onBackPressed, this.onBackPressed,
@@ -96,16 +103,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
final Widget? leading; final Widget? leading;
/// AppBar actions /// AppBar actions
/// By default it shows the [ChannelAvatar] /// By default it shows the [StreamChannelAvatar]
final List<Widget>? actions; final List<Widget>? actions;
/// The background color for this [ChannelHeader]. /// The background color for this [StreamChannelHeader].
final Color? backgroundColor; final Color? backgroundColor;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
final channelHeaderTheme = ChannelHeaderTheme.of(context); final channelHeaderTheme = StreamChannelHeaderTheme.of(context);
final leadingWidget = leading ?? final leadingWidget = leading ??
(showBackButton (showBackButton
@@ -115,7 +122,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
) )
: const SizedBox()); : const SizedBox());
return ConnectionStatusBuilder( return StreamConnectionStatusBuilder(
statusBuilder: (context, status) { statusBuilder: (context, status) {
var statusString = ''; var statusString = '';
var showStatus = true; var showStatus = true;
@@ -135,7 +142,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
return InfoTile( return StreamInfoTile(
showMessage: showConnectionStateTile && showStatus, showMessage: showConnectionStateTile && showStatus,
message: statusString, message: statusString,
child: AppBar( child: AppBar(
@@ -152,7 +159,8 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
Padding( Padding(
padding: const EdgeInsets.only(right: 10), padding: const EdgeInsets.only(right: 10),
child: Center( child: Center(
child: ChannelAvatar( child: StreamChannelAvatar(
channel: channel,
borderRadius: borderRadius:
channelHeaderTheme.avatarTheme?.borderRadius, channelHeaderTheme.avatarTheme?.borderRadius,
constraints: constraints:
@@ -172,12 +180,13 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
title ?? title ??
ChannelName( StreamChannelName(
channel: channel,
textStyle: channelHeaderTheme.titleStyle, textStyle: channelHeaderTheme.titleStyle,
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
subtitle ?? subtitle ??
ChannelInfo( StreamChannelInfo(
showTypingIndicator: showTypingIndicator, showTypingIndicator: showTypingIndicator,
channel: channel, channel: channel,
textStyle: channelHeaderTheme.subtitleStyle, textStyle: channelHeaderTheme.subtitleStyle,
@@ -3,10 +3,16 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro channel_info}
@Deprecated("Use 'StreamChannelInfo' instead")
typedef ChannelInfo = StreamChannelInfo;
/// {@template channel_info}
/// Widget which shows channel info /// Widget which shows channel info
class ChannelInfo extends StatelessWidget { /// {@endtemplate}
/// Constructor which creates a [ChannelInfo] widget class StreamChannelInfo extends StatelessWidget {
const ChannelInfo({ /// Constructor which creates a [StreamChannelInfo] widget
const StreamChannelInfo({
Key? key, Key? key,
required this.channel, required this.channel,
this.textStyle, this.textStyle,
@@ -32,7 +38,7 @@ class ChannelInfo extends StatelessWidget {
return BetterStreamBuilder<List<Member>>( return BetterStreamBuilder<List<Member>>(
stream: channel.state!.membersStream, stream: channel.state!.membersStream,
initialData: channel.state!.members, initialData: channel.state!.members,
builder: (context, data) => ConnectionStatusBuilder( builder: (context, data) => StreamConnectionStatusBuilder(
statusBuilder: (context, status) { statusBuilder: (context, status) {
switch (status) { switch (status) {
case ConnectionStatus.connected: case ConnectionStatus.connected:
@@ -66,7 +72,7 @@ class ChannelInfo extends StatelessWidget {
} }
alternativeWidget = Text( alternativeWidget = Text(
text, text,
style: ChannelHeaderTheme.of(context).subtitleStyle, style: StreamChannelHeaderTheme.of(context).subtitleStyle,
); );
} else { } else {
final userId = StreamChat.of(context).currentUser?.id; final userId = StreamChat.of(context).currentUser?.id;
@@ -95,7 +101,7 @@ class ChannelInfo extends StatelessWidget {
} }
return Align( return Align(
child: TypingIndicator( child: StreamTypingIndicator(
parentId: parentId, parentId: parentId,
style: textStyle, style: textStyle,
alternativeWidget: alternativeWidget, alternativeWidget: alternativeWidget,
@@ -11,7 +11,11 @@ typedef TitleBuilder = Widget Function(
StreamChatClient client, StreamChatClient client,
); );
/// /// {@macro channel_list_header}
@Deprecated("Use 'StreamChannelListHeader' instead")
typedef ChannelListHeader = StreamChannelListHeader;
/// {@template channel_list_header}
/// It shows the current [StreamChatClient] status. /// It shows the current [StreamChatClient] status.
/// ///
/// ```dart /// ```dart
@@ -43,11 +47,13 @@ typedef TitleBuilder = Widget Function(
/// if you don't have it in the widget tree. /// if you don't have it in the widget tree.
/// ///
/// The widget components render the ui based on the first ancestor of type /// The widget components render the ui based on the first ancestor of type
/// [StreamChatTheme] and on its [ChannelListHeaderThemeData] property. /// [StreamChatTheme] and on its [StreamChannelListHeaderThemeData] property.
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// {@endtemplate}
class StreamChannelListHeader extends StatelessWidget
implements PreferredSizeWidget {
/// Instantiates a ChannelListHeader /// Instantiates a ChannelListHeader
const ChannelListHeader({ const StreamChannelListHeader({
Key? key, Key? key,
this.client, this.client,
this.titleBuilder, this.titleBuilder,
@@ -91,14 +97,14 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
/// By default it shows the new chat button /// By default it shows the new chat button
final List<Widget>? actions; final List<Widget>? actions;
/// The background color for this [ChannelListHeader]. /// The background color for this [StreamChannelListHeader].
final Color? backgroundColor; final Color? backgroundColor;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final _client = client ?? StreamChat.of(context).client; final _client = client ?? StreamChat.of(context).client;
final user = _client.state.currentUser; final user = _client.state.currentUser;
return ConnectionStatusBuilder( return StreamConnectionStatusBuilder(
statusBuilder: (context, status) { statusBuilder: (context, status) {
var statusString = ''; var statusString = '';
var showStatus = true; var showStatus = true;
@@ -117,9 +123,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
} }
final chatThemeData = StreamChatTheme.of(context); final chatThemeData = StreamChatTheme.of(context);
final channelListHeaderThemeData = ChannelListHeaderTheme.of(context); final channelListHeaderThemeData =
StreamChannelListHeaderTheme.of(context);
final theme = Theme.of(context); final theme = Theme.of(context);
return InfoTile( return StreamInfoTile(
showMessage: showConnectionStateTile && showStatus, showMessage: showConnectionStateTile && showStatus,
message: statusString, message: statusString,
child: AppBar( child: AppBar(
@@ -135,7 +142,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
leading: leading ?? leading: leading ??
Center( Center(
child: user != null child: user != null
? UserAvatar( ? StreamUserAvatar(
user: user, user: user,
showOnlineStatus: false, showOnlineStatus: false,
onTap: onUserAvatarTap ?? onTap: onUserAvatarTap ??
@@ -156,7 +163,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
[ [
StreamNeumorphicButton( StreamNeumorphicButton(
child: IconButton( child: IconButton(
icon: ConnectionStatusBuilder( icon: StreamConnectionStatusBuilder(
statusBuilder: (context, status) { statusBuilder: (context, status) {
Color? color; Color? color;
switch (status) { switch (status) {
@@ -234,10 +241,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
context.translations.searchingForNetworkText, context.translations.searchingForNetworkText,
style: ChannelListHeaderTheme.of(context).titleStyle?.copyWith( style:
fontSize: 16, StreamChannelListHeaderTheme.of(context).titleStyle?.copyWith(
fontWeight: FontWeight.bold, fontSize: 16,
), fontWeight: FontWeight.bold,
),
), ),
], ],
); );
@@ -247,7 +255,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
StreamChatClient client, StreamChatClient client,
) { ) {
final chatThemeData = StreamChatTheme.of(context); final chatThemeData = StreamChatTheme.of(context);
final channelListHeaderTheme = ChannelListHeaderTheme.of(context); final channelListHeaderTheme = StreamChannelListHeaderTheme.of(context);
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
@@ -11,7 +10,7 @@ typedef ChannelTapCallback = void Function(Channel, Widget?);
/// Callback called when tapping on a channel /// Callback called when tapping on a channel
typedef ChannelInfoCallback = void Function(Channel); typedef ChannelInfoCallback = void Function(Channel);
/// Builder used to create a custom [ChannelPreview] from a [Channel] /// Builder used to create a custom [StreamChannelPreview] from a [Channel]
typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel);
/// Callback for when 'View Info' is tapped /// Callback for when 'View Info' is tapped
@@ -52,10 +51,7 @@ typedef ViewInfoCallback = void Function(Channel);
/// The widget components render the ui based on the first ancestor of /// The widget components render the ui based on the first ancestor of
/// type [StreamChatTheme]. /// type [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
@Deprecated( @Deprecated("Use 'StreamChannelListView' instead")
"'ChannelListView' is deprecated and shouldn't be used. "
"Please use 'StreamChannelListView' instead.",
)
class ChannelListView extends StatefulWidget { class ChannelListView extends StatefulWidget {
/// Instantiate a new ChannelListView /// Instantiate a new ChannelListView
ChannelListView({ ChannelListView({
@@ -248,7 +244,8 @@ class _ChannelListViewState extends State<ChannelListView> {
child: child, child: child,
); );
final backgroundColor = ChannelListViewTheme.of(context).backgroundColor; final backgroundColor =
StreamChannelListViewTheme.of(context).backgroundColor;
if (backgroundColor != null) { if (backgroundColor != null) {
return ColoredBox( return ColoredBox(
@@ -550,7 +547,8 @@ class _ChannelListViewState extends State<ChannelListView> {
context: context, context: context,
builder: (context) => StreamChannel( builder: (context) => StreamChannel(
channel: channel, channel: channel,
child: ChannelBottomSheet( child: StreamChannelInfoBottomSheet(
channel: channel,
onViewInfoTap: () { onViewInfoTap: () {
widget.onViewInfoTap?.call(channel); widget.onViewInfoTap?.call(channel);
}, },
@@ -639,7 +637,7 @@ class _ChannelListViewState extends State<ChannelListView> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ChannelAvatar( StreamChannelAvatar(
channel: channel, channel: channel,
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
selected: selected, selected: selected,
@@ -654,8 +652,9 @@ class _ChannelListViewState extends State<ChannelListView> {
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: StreamChannel( child: StreamChannel(
channel: channel, channel: channel,
child: const ChannelName( child: StreamChannelName(
textStyle: TextStyle( channel: channel,
textStyle: const TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@@ -6,10 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// ///
/// The widget uses a [StreamBuilder] to render the channel information /// The widget uses a [StreamBuilder] to render the channel information
/// image as soon as it updates. /// image as soon as it updates.
@Deprecated( @Deprecated("Use 'StreamChannelName' instead")
"'ChannelName' is deprecated and shouldn't be used. "
"Please use 'StreamChannelName' instead.",
)
class ChannelName extends StatelessWidget { class ChannelName extends StatelessWidget {
/// Instantiate a new ChannelName /// Instantiate a new ChannelName
const ChannelName({ const ChannelName({
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@template channel_preview}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_preview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_preview.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_preview_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/channel_preview_paint.png)
/// ///
@@ -13,11 +14,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// image as soon as it updates. /// image as soon as it updates.
/// ///
/// Usually you don't use this widget as it's the default channel preview /// Usually you don't use this widget as it's the default channel preview
/// used by [ChannelListView]. /// used by [StreamChannelListView].
/// ///
/// The widget renders the ui based on the first ancestor of type /// The widget renders the ui based on the first ancestor of type
/// [StreamChatTheme]. /// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
/// {@endtemplate}
@Deprecated("Use 'StreamChannelListTile' instead")
class ChannelPreview extends StatelessWidget { class ChannelPreview extends StatelessWidget {
/// Constructor for creating [ChannelPreview] /// Constructor for creating [ChannelPreview]
const ChannelPreview({ const ChannelPreview({
@@ -52,7 +55,7 @@ class ChannelPreview extends StatelessWidget {
final Widget? subtitle; final Widget? subtitle;
/// Widget rendering the leading element, by default /// Widget rendering the leading element, by default
/// it shows the [ChannelAvatar] /// it shows the [StreamChannelAvatar]
final Widget? leading; final Widget? leading;
/// Widget rendering the trailing element, /// Widget rendering the trailing element,
@@ -60,7 +63,7 @@ class ChannelPreview extends StatelessWidget {
final Widget? trailing; final Widget? trailing;
/// Widget rendering the sending indicator, /// Widget rendering the sending indicator,
/// by default it uses the [SendingIndicator] widget /// by default it uses the [StreamSendingIndicator] widget
final Widget? sendingIndicator; final Widget? sendingIndicator;
@override @override
@@ -80,13 +83,18 @@ class ChannelPreview extends StatelessWidget {
), ),
onTap: () => onTap?.call(channel), onTap: () => onTap?.call(channel),
onLongPress: () => onLongPress?.call(channel), onLongPress: () => onLongPress?.call(channel),
leading: leading ?? ChannelAvatar(onTap: onImageTap), leading: leading ??
StreamChannelAvatar(
channel: channel,
onTap: onImageTap,
),
title: Row( title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: title ?? child: title ??
ChannelName( StreamChannelName(
channel: channel,
textStyle: channelPreviewTheme.titleStyle, textStyle: channelPreviewTheme.titleStyle,
), ),
), ),
@@ -100,7 +108,7 @@ class ChannelPreview extends StatelessWidget {
e.user!.id == channel.client.state.currentUser?.id)) { e.user!.id == channel.client.state.currentUser?.id)) {
return const SizedBox(); return const SizedBox();
} }
return UnreadIndicator( return StreamUnreadIndicator(
cid: channel.cid, cid: channel.cid,
); );
}, },
@@ -136,7 +144,7 @@ class ChannelPreview extends StatelessWidget {
))); )));
final isMessageRead = readList.length >= final isMessageRead = readList.length >=
(channel.memberCount ?? 0) - 1; (channel.memberCount ?? 0) - 1;
return SendingIndicator( return StreamSendingIndicator(
message: lastMessage!, message: lastMessage!,
size: channelPreviewTheme.indicatorIconSize, size: channelPreviewTheme.indicatorIconSize,
isMessageRead: isMessageRead, isMessageRead: isMessageRead,
@@ -204,7 +212,7 @@ class ChannelPreview extends StatelessWidget {
], ],
); );
} }
return TypingIndicator( return StreamTypingIndicator(
channel: channel, channel: channel,
alternativeWidget: _buildLastMessage(context), alternativeWidget: _buildLastMessage(context),
style: channelPreviewTheme.subtitleStyle, style: channelPreviewTheme.subtitleStyle,
@@ -2,10 +2,17 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro commands_overlay}
@Deprecated("Use 'StreamCommandsOverlay' instead")
typedef CommandsOverlay = StreamCommandsOverlay;
/// {@template commands_overlay}
/// Overlay for displaying commands that can be used /// Overlay for displaying commands that can be used
class CommandsOverlay extends StatelessWidget { /// to interact with the channel.
/// Constructor for creating a [CommandsOverlay] /// {@endtemplate}
const CommandsOverlay({ class StreamCommandsOverlay extends StatelessWidget {
/// Constructor for creating a [StreamCommandsOverlay]
const StreamCommandsOverlay({
required this.text, required this.text,
required this.onCommandResult, required this.onCommandResult,
required this.size, required this.size,
@@ -1,14 +1,20 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro connection_status_builder}
@Deprecated("Use 'StreamConnectionStatusBuilder' instead")
typedef ConnectionStatusBuilder = StreamConnectionStatusBuilder;
/// {@template connection_status_builder}
/// Widget that builds itself based on the latest snapshot of interaction with /// Widget that builds itself based on the latest snapshot of interaction with
/// a [Stream] of type [ConnectionStatus]. /// a [Stream] of type [ConnectionStatus].
/// ///
/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream] /// The widget will use the closest [StreamChatClient.wsConnectionStatusStream]
/// in case no stream is provided. /// in case no stream is provided.
class ConnectionStatusBuilder extends StatelessWidget { /// {@endtemplate}
class StreamConnectionStatusBuilder extends StatelessWidget {
/// Creates a new ConnectionStatusBuilder /// Creates a new ConnectionStatusBuilder
const ConnectionStatusBuilder({ const StreamConnectionStatusBuilder({
Key? key, Key? key,
required this.statusBuilder, required this.statusBuilder,
this.connectionStatusStream, this.connectionStatusStream,
@@ -3,10 +3,16 @@ import 'package:jiffy/jiffy.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro date_divider}
@Deprecated("Use 'StreamDateDivider' instead")
typedef DateDivider = StreamDateDivider;
/// {@template date_divider}
/// It shows a date divider depending on the date difference /// It shows a date divider depending on the date difference
class DateDivider extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [DateDivider] class StreamDateDivider extends StatelessWidget {
const DateDivider({ /// Constructor for creating a [StreamDateDivider]
const StreamDateDivider({
Key? key, Key? key,
required this.dateTime, required this.dateTime,
this.uppercase = false, this.uppercase = false,
@@ -3,10 +3,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/theme/themes.dart';
/// Widget to display deleted message /// {@macro deleted_message}
class DeletedMessage extends StatelessWidget { @Deprecated("Use 'StreamDeletedMessage' instead")
/// Constructor to create [DeletedMessage] typedef DeletedMessage = StreamDeletedMessage;
const DeletedMessage({
/// {@template deleted_message}
/// Widget to display deleted message.
/// {@endtemplate}
class StreamDeletedMessage extends StatelessWidget {
/// Constructor to create [StreamDeletedMessage]
const StreamDeletedMessage({
Key? key, Key? key,
required this.messageTheme, required this.messageTheme,
this.borderRadiusGeometry, this.borderRadiusGeometry,
@@ -16,7 +22,7 @@ class DeletedMessage extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
/// The theme of the message /// The theme of the message
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// The border radius of the message text /// The border radius of the message text
final BorderRadiusGeometry? borderRadiusGeometry; final BorderRadiusGeometry? borderRadiusGeometry;
@@ -4,10 +4,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:substring_highlight/substring_highlight.dart'; import 'package:substring_highlight/substring_highlight.dart';
/// {@macro emoji_overlay}
@Deprecated("Use 'StreamEmojiOverlay' instead")
typedef EmojiOverlay = StreamEmojiOverlay;
/// {@template emoji_overlay}
/// Overlay for displaying emoji that can be used /// Overlay for displaying emoji that can be used
class EmojiOverlay extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [EmojiOverlay] class StreamEmojiOverlay extends StatelessWidget {
const EmojiOverlay({ /// Constructor for creating a [StreamEmojiOverlay]
const StreamEmojiOverlay({
required this.query, required this.query,
required this.onEmojiResult, required this.onEmojiResult,
required this.size, required this.size,
@@ -225,3 +225,50 @@ extension UserListX on List<User> {
return entries.map((e) => e.key).toList(growable: false); return entries.map((e) => e.key).toList(growable: false);
} }
} }
/// Extensions on Message
extension MessageX on Message {
/// It replaces the user mentions with the actual user names.
Message replaceMentions({bool linkify = true}) {
var messageTextToRender = text;
for (final user in mentionedUsers.toSet()) {
final userId = user.id;
final userName = user.name;
if (linkify) {
messageTextToRender = messageTextToRender?.replaceAll(
'@$userId',
'[@$userName](@${userName.replaceAll(' ', '')})',
);
} else {
messageTextToRender = messageTextToRender?.replaceAll(
'@$userId',
'@$userName',
);
}
}
return copyWith(text: messageTextToRender);
}
/// It returns the message with the translated text if available locally
Message translate(String language) =>
copyWith(text: i18n?['${language}_text'] ?? text);
/// It returns the message replacing the mentioned user names with
/// the respective user ids
Message replaceMentionsWithId() {
if (mentionedUsers.isEmpty) return this;
var messageTextToSend = text;
if (messageTextToSend == null) return this;
for (final user in mentionedUsers.toSet()) {
final userName = user.name;
messageTextToSend = messageTextToSend!.replaceAll(
'@$userName',
'@${user.id}',
);
}
return copyWith(text: messageTextToSend);
}
}
@@ -21,10 +21,16 @@ enum ReturnActionType {
/// Callback when show message is tapped /// Callback when show message is tapped
typedef ShowMessageCallback = void Function(Message message, Channel channel); typedef ShowMessageCallback = void Function(Message message, Channel channel);
/// {@macro full_screen_media}
@Deprecated("Use 'StreamFullScreenMedia' instead")
typedef FullScreenMedia = StreamFullScreenMedia;
/// {@template full_screen_media}
/// A full screen image widget /// A full screen image widget
class FullScreenMedia extends StatefulWidget { /// {@endtemplate}
class StreamFullScreenMedia extends StatefulWidget {
/// Instantiate a new FullScreenImage /// Instantiate a new FullScreenImage
const FullScreenMedia({ const StreamFullScreenMedia({
Key? key, Key? key,
required this.mediaAttachments, required this.mediaAttachments,
required this.message, required this.message,
@@ -60,10 +66,10 @@ class FullScreenMedia extends StatefulWidget {
final bool autoplayVideos; final bool autoplayVideos;
@override @override
_FullScreenMediaState createState() => _FullScreenMediaState(); _StreamFullScreenMediaState createState() => _StreamFullScreenMediaState();
} }
class _FullScreenMediaState extends State<FullScreenMedia> class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final AnimationController _animationController; late final AnimationController _animationController;
late final PageController _pageController; late final PageController _pageController;
@@ -172,7 +178,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
), ),
backgroundDecoration: BoxDecoration( backgroundDecoration: BoxDecoration(
color: ColorTween( color: ColorTween(
begin: ChannelHeaderTheme.of(context).color, begin: StreamChannelHeaderTheme.of(context).color,
end: Colors.black, end: Colors.black,
).lerp(_curvedAnimation.value), ).lerp(_curvedAnimation.value),
), ),
@@ -221,7 +227,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
builder: (context, value, child) => Column( builder: (context, value, child) => Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
GalleryHeader( StreamGalleryHeader(
userName: widget.userName, userName: widget.userName,
sentAt: context.translations.sentAtText( sentAt: context.translations.sentAtText(
date: widget.message.createdAt, date: widget.message.createdAt,
@@ -242,7 +248,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
widget.attachmentActionsModalBuilder, widget.attachmentActionsModalBuilder,
), ),
if (!widget.message.isEphemeral) if (!widget.message.isEphemeral)
GalleryFooter( StreamGalleryFooter(
currentPage: value, currentPage: value,
totalPages: widget.mediaAttachments.length, totalPages: widget.mediaAttachments.length,
mediaAttachments: widget.mediaAttachments, mediaAttachments: widget.mediaAttachments,
@@ -9,10 +9,17 @@ import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro gallery_footer}
@Deprecated("Use 'StreamGalleryFooter' instead")
typedef GalleryFooter = StreamGalleryFooter;
/// {@template gallery_footer}
/// Footer widget for media display /// Footer widget for media display
class GalleryFooter extends StatefulWidget implements PreferredSizeWidget { /// {@endtemplate}
class StreamGalleryFooter extends StatefulWidget
implements PreferredSizeWidget {
/// Creates a channel header /// Creates a channel header
const GalleryFooter({ const StreamGalleryFooter({
Key? key, Key? key,
required this.message, required this.message,
this.onBackPressed, this.onBackPressed,
@@ -51,22 +58,22 @@ class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
/// Callback when media is selected /// Callback when media is selected
final ValueChanged<int>? mediaSelectedCallBack; final ValueChanged<int>? mediaSelectedCallBack;
/// The background color of this [GalleryFooter]. /// The background color of this [StreamGalleryFooter].
final Color? backgroundColor; final Color? backgroundColor;
@override @override
_GalleryFooterState createState() => _GalleryFooterState(); _StreamGalleryFooterState createState() => _StreamGalleryFooterState();
@override @override
final Size preferredSize; final Size preferredSize;
} }
class _GalleryFooterState extends State<GalleryFooter> { class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const showShareButton = !kIsWeb; const showShareButton = !kIsWeb;
final mediaQueryData = MediaQuery.of(context); final mediaQueryData = MediaQuery.of(context);
final galleryFooterThemeData = GalleryFooterTheme.of(context); final galleryFooterThemeData = StreamGalleryFooterTheme.of(context);
return SizedBox.fromSize( return SizedBox.fromSize(
size: Size( size: Size(
mediaQueryData.size.width, mediaQueryData.size.width,
@@ -149,7 +156,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
void _showPhotosModal(context) { void _showPhotosModal(context) {
final chatThemeData = StreamChatTheme.of(context); final chatThemeData = StreamChatTheme.of(context);
final galleryFooterThemeData = GalleryFooterTheme.of(context); final galleryFooterThemeData = StreamGalleryFooterTheme.of(context);
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
barrierColor: galleryFooterThemeData.bottomSheetBarrierColor, barrierColor: galleryFooterThemeData.bottomSheetBarrierColor,
@@ -222,7 +229,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
onTap: () => widget.mediaSelectedCallBack!(index), onTap: () => widget.mediaSelectedCallBack!(index),
child: FittedBox( child: FittedBox(
fit: BoxFit.cover, fit: BoxFit.cover,
child: VideoThumbnailImage( child: StreamVideoThumbnailImage(
video: (attachment.file?.path ?? video: (attachment.file?.path ??
attachment.assetUrl)!, attachment.assetUrl)!,
), ),
@@ -264,7 +271,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
), ),
], ],
), ),
child: UserAvatar( child: StreamUserAvatar(
user: widget.message.user!, user: widget.message.user!,
constraints: constraints:
BoxConstraints.tight(const Size(24, 24)), BoxConstraints.tight(const Size(24, 24)),
@@ -15,10 +15,17 @@ typedef AttachmentActionsBuilder = Widget Function(
AttachmentActionsModal defaultActionsModal, AttachmentActionsModal defaultActionsModal,
); );
/// {@macro gallery_header}
@Deprecated("Use 'StreamGalleryHeader' instead")
typedef GalleryHeader = StreamGalleryHeader;
/// {@template gallery_header}
/// Header/AppBar widget for media display screen /// Header/AppBar widget for media display screen
class GalleryHeader extends StatelessWidget implements PreferredSizeWidget { /// {@endtemplate}
class StreamGalleryHeader extends StatelessWidget
implements PreferredSizeWidget {
/// Creates a channel header /// Creates a channel header
const GalleryHeader({ const StreamGalleryHeader({
Key? key, Key? key,
required this.message, required this.message,
this.currentIndex = 0, this.currentIndex = 0,
@@ -62,7 +69,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
/// Stores the current index of media shown /// Stores the current index of media shown
final int currentIndex; final int currentIndex;
/// The background color of this [GalleryHeader]. /// The background color of this [StreamGalleryHeader].
final Color? backgroundColor; final Color? backgroundColor;
/// Widget builder for attachment actions modal /// Widget builder for attachment actions modal
@@ -72,7 +79,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final galleryHeaderThemeData = GalleryHeaderTheme.of(context); final galleryHeaderThemeData = StreamGalleryHeaderTheme.of(context);
final theme = Theme.of(context); final theme = Theme.of(context);
return AppBar( return AppBar(
toolbarTextStyle: theme.textTheme.bodyText2, toolbarTextStyle: theme.textTheme.bodyText2,
@@ -3,10 +3,16 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// {@macro gradient_avatar}
@Deprecated("Use 'StreamGradientAvatar' instead")
typedef GradientAvatar = StreamGradientAvatar;
/// {@template gradient_avatar}
/// Fallback user avatar with a polygon gradient overlayed with text /// Fallback user avatar with a polygon gradient overlayed with text
class GradientAvatar extends StatefulWidget { /// {@endtemplate}
/// Constructor for [GradientAvatar] class StreamGradientAvatar extends StatefulWidget {
const GradientAvatar({ /// Constructor for [StreamGradientAvatar]
const StreamGradientAvatar({
Key? key, Key? key,
required this.name, required this.name,
required this.userId, required this.userId,
@@ -19,10 +25,10 @@ class GradientAvatar extends StatefulWidget {
final String userId; final String userId;
@override @override
_GradientAvatarState createState() => _GradientAvatarState(); _StreamGradientAvatarState createState() => _StreamGradientAvatarState();
} }
class _GradientAvatarState extends State<GradientAvatar> { class _StreamGradientAvatarState extends State<StreamGradientAvatar> {
@override @override
Widget build(BuildContext context) => Center( Widget build(BuildContext context) => Center(
child: RepaintBoundary( child: RepaintBoundary(
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro group_avatar}
@Deprecated("Use 'StreamGroupAvatar' instead")
typedef GroupAvatar = StreamGroupAvatar;
/// {@template group_avatar}
/// Widget for constructing a group of images /// Widget for constructing a group of images
class GroupAvatar extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [GroupAvatar] class StreamGroupAvatar extends StatelessWidget {
const GroupAvatar({ /// Constructor for creating a [StreamGroupAvatar]
const StreamGroupAvatar({
Key? key, Key? key,
this.channel, this.channel,
required this.members, required this.members,
@@ -84,7 +90,7 @@ class GroupAvatar extends StatelessWidget {
), ),
), ),
initialData: member, initialData: member,
builder: (context, member) => UserAvatar( builder: (context, member) => StreamUserAvatar(
showOnlineStatus: false, showOnlineStatus: false,
user: member.user!, user: member.user!,
borderRadius: BorderRadius.zero, borderRadius: BorderRadius.zero,
@@ -122,7 +128,8 @@ class GroupAvatar extends StatelessWidget {
), ),
), ),
initialData: member, initialData: member,
builder: (context, member) => UserAvatar( builder: (context, member) =>
StreamUserAvatar(
showOnlineStatus: false, showOnlineStatus: false,
user: member.user!, user: member.user!,
borderRadius: BorderRadius.zero, borderRadius: BorderRadius.zero,
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro image_group}
@Deprecated("Use 'StreamImageGroup' instead")
typedef ImageGroup = StreamImageGroup;
/// {@template image_group}
/// Widget for constructing a group of images in message /// Widget for constructing a group of images in message
class ImageGroup extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating [ImageGroup] widget class StreamImageGroup extends StatelessWidget {
const ImageGroup({ /// Constructor for creating [StreamImageGroup] widget
const StreamImageGroup({
Key? key, Key? key,
required this.images, required this.images,
required this.message, required this.message,
@@ -27,8 +33,8 @@ class ImageGroup extends StatelessWidget {
/// Message which images are attached to /// Message which images are attached to
final Message message; final Message message;
/// [MessageThemeData] to apply to message /// [StreamMessageThemeData] to apply to message
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Size of iamges /// Size of iamges
final Size size; final Size size;
@@ -129,7 +135,7 @@ class ImageGroup extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => StreamChannel( builder: (context) => StreamChannel(
channel: channel, channel: channel,
child: FullScreenMedia( child: StreamFullScreenMedia(
mediaAttachments: images, mediaAttachments: images,
startIndex: index, startIndex: index,
userName: message.user?.name, userName: message.user?.name,
@@ -142,7 +148,7 @@ class ImageGroup extends StatelessWidget {
if (res != null) onReturnAction?.call(res); if (res != null) onReturnAction?.call(res);
} }
Widget _buildImage(BuildContext context, int index) => ImageAttachment( Widget _buildImage(BuildContext context, int index) => StreamImageAttachment(
attachment: images[index], attachment: images[index],
size: size, size: size,
message: message, message: message,
@@ -2,10 +2,16 @@ import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_portal/flutter_portal.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro info_tile}
@Deprecated("Use 'StreamInfoTile' instead")
typedef InfoTile = StreamInfoTile;
/// {@template info_tile}
/// Tile to display a message, used in stream chat to display connection status /// Tile to display a message, used in stream chat to display connection status
class InfoTile extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating an [InfoTile] widget class StreamInfoTile extends StatelessWidget {
const InfoTile({ /// Constructor for creating an [StreamInfoTile] widget
const StreamInfoTile({
Key? key, Key? key,
required this.message, required this.message,
required this.child, required this.child,
@@ -59,7 +59,7 @@ abstract class Translations {
/// The error shown when loading messages fails /// The error shown when loading messages fails
String get loadingMessagesError; String get loadingMessagesError;
/// The text for showing the result count in [MessageSearchListView] /// The text for showing the result count in [StreamMessageSearchListView]
String resultCountText(int count); String resultCountText(int count);
/// The text for showing the message is deleted /// The text for showing the message is deleted
@@ -74,20 +74,20 @@ abstract class Translations {
/// The text for showing there are no chats /// The text for showing there are no chats
String get emptyChatMessagesText; String get emptyChatMessagesText;
/// The text for showing the thread separator in case [MessageListView] /// The text for showing the thread separator in case [StreamMessageListView]
/// contains a parent message /// contains a parent message
String threadSeparatorText(int replyCount); String threadSeparatorText(int replyCount);
/// The label for "connected" in [ConnectionStatusBuilder] /// The label for "connected" in [StreamConnectionStatusBuilder]
String get connectedLabel; String get connectedLabel;
/// The label for "disconnected" in [ConnectionStatusBuilder] /// The label for "disconnected" in [StreamConnectionStatusBuilder]
String get disconnectedLabel; String get disconnectedLabel;
/// The label for "reconnecting" in [ConnectionStatusBuilder] /// The label for "reconnecting" in [StreamConnectionStatusBuilder]
String get reconnectingLabel; String get reconnectingLabel;
/// The label for also send as direct message "checkbox"" in [MessageInput] /// The label for also send as direct message "checkbox"" in [StreamMessageInput]
String get alsoSendAsDirectMessageLabel; String get alsoSendAsDirectMessageLabel;
/// The label for search Gif /// The label for search Gif
@@ -97,24 +97,24 @@ abstract class Translations {
String get sendMessagePermissionError; String get sendMessagePermissionError;
/// The label for add a comment or send in case of /// The label for add a comment or send in case of
/// attachments inside [MessageInput] /// attachments inside [StreamMessageInput]
String get addACommentOrSendLabel; String get addACommentOrSendLabel;
/// The label for write a message in [MessageInput] /// The label for write a message in [StreamMessageInput]
String get writeAMessageLabel; String get writeAMessageLabel;
/// The label for slow mode enabled in [MessageInput] /// The label for slow mode enabled in [StreamMessageInput]
String get slowModeOnLabel; String get slowModeOnLabel;
/// The label for instant commands in [MessageInput] /// The label for instant commands in [StreamMessageInput]
String get instantCommandsLabel; String get instantCommandsLabel;
/// The error shown in case the fi"le is too large even after compression /// The error shown in case the fi"le is too large even after compression
/// while uploading via [MessageInput] /// while uploading via [StreamMessageInput]
String fileTooLargeAfterCompressionError(double limitInMB); String fileTooLargeAfterCompressionError(double limitInMB);
/// The error shown in case the file is too large /// The error shown in case the file is too large
/// while uploading via [MessageInput] /// while uploading via [StreamMessageInput]
String fileTooLargeError(double limitInMB); String fileTooLargeError(double limitInMB);
/// The text for showing the query while searching for emojis /// The text for showing the query while searching for emojis
@@ -7,21 +7,16 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
extension on Duration { /// {@macro media_list_view}
String format() { @Deprecated("Use 'StreamMediaListView' instead")
final s = '$this'.split('.')[0].padLeft(8, '0'); typedef MediaListView = StreamMediaListView;
if (s.startsWith('00:')) {
return s.replaceFirst('00:', '');
}
return s;
}
}
/// {@template media_list_view}
/// Constructs a list of media /// Constructs a list of media
class MediaListView extends StatefulWidget { /// {@endtemplate}
/// Constructor for creating a [MediaListView] widget class StreamMediaListView extends StatefulWidget {
const MediaListView({ /// Constructor for creating a [StreamMediaListView] widget
const StreamMediaListView({
Key? key, Key? key,
this.selectedIds = const [], this.selectedIds = const [],
this.onSelect, this.onSelect,
@@ -34,10 +29,10 @@ class MediaListView extends StatefulWidget {
final void Function(AssetEntity media)? onSelect; final void Function(AssetEntity media)? onSelect;
@override @override
_MediaListViewState createState() => _MediaListViewState(); _StreamMediaListViewState createState() => _StreamMediaListViewState();
} }
class _MediaListViewState extends State<MediaListView> { class _StreamMediaListViewState extends State<StreamMediaListView> {
final _media = <AssetEntity>[]; final _media = <AssetEntity>[];
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
int _currentPage = 0; int _currentPage = 0;
@@ -158,7 +153,10 @@ class _MediaListViewState extends State<MediaListView> {
)) ))
.firstOrNull; .firstOrNull;
final media = await assetList?.getAssetListPaged(_currentPage, 50); final media = await assetList?.getAssetListPaged(
page: _currentPage,
size: 50,
);
if (media?.isNotEmpty == true) { if (media?.isNotEmpty == true) {
setState(() { setState(() {
@@ -197,7 +195,7 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
DecoderCallback decode, DecoderCallback decode,
) async { ) async {
assert(key == this, 'Checks MediaThumbnailProvider'); assert(key == this, 'Checks MediaThumbnailProvider');
final bytes = await media.thumbData; final bytes = await media.thumbnailData;
return decode(bytes!); return decode(bytes!);
} }
@@ -219,3 +217,14 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
@override @override
String toString() => '$runtimeType("${media.id}")'; String toString() => '$runtimeType("${media.id}")';
} }
extension on Duration {
String format() {
final s = '$this'.split('.')[0].padLeft(8, '0');
if (s.startsWith('00:')) {
return s.replaceFirst('00:', '');
}
return s;
}
}
@@ -1,101 +0,0 @@
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// This widget is used for showing user tiles for mentions
/// Use [title], [subtitle], [leading], [trailing] for
/// substituting widgets in respective positions
@Deprecated('Use `UserMentionTile` instead. Will be removed in future release')
class MentionTile extends StatelessWidget {
/// Constructor for creating a [MentionTile] widget
const MentionTile(
this.member, {
Key? key,
this.title,
this.subtitle,
this.leading,
this.trailing,
}) : super(key: key);
/// Member to display in the tile
final Member member;
/// Widget to display as title
final Widget? title;
/// Widget to display below [title]
final Widget? subtitle;
/// Widget at the start of the tile
final Widget? leading;
/// Widget at the end of tile
final Widget? trailing;
@override
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return SizedBox(
height: 56,
child: Row(
children: [
const SizedBox(
width: 16,
),
leading ??
UserAvatar(
constraints: BoxConstraints.tight(
const Size(
40,
40,
),
),
user: member.user!,
),
const SizedBox(
width: 8,
),
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title ??
Text(
member.user!.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: chatThemeData.textTheme.bodyBold,
),
const SizedBox(
height: 2,
),
subtitle ??
Text(
'@${member.userId}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: chatThemeData.textTheme.footnoteBold.copyWith(
color: chatThemeData.colorTheme.textLowEmphasis,
),
),
],
),
),
),
trailing ??
Padding(
padding: const EdgeInsets.only(
right: 18,
left: 8,
),
child: StreamSvgIcon.mentions(
color: chatThemeData.colorTheme.accentPrimary,
),
),
],
),
);
}
}
@@ -1,10 +1,16 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro message_action}
@Deprecated("Use 'StreamMessageActions' instead")
typedef MessageAction = StreamMessageAction;
/// {@template message_action}
/// Class describing a message action /// Class describing a message action
class MessageAction { /// {@endtemplate}
/// returns a new instance of a [MessageAction] class StreamMessageAction {
MessageAction({ /// returns a new instance of a [StreamMessageAction]
StreamMessageAction({
this.leading, this.leading,
this.title, this.title,
this.onTap, this.onTap,
@@ -3,10 +3,16 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro message_actions_modal}
@Deprecated("Use 'StreamMessageActionsModal' instead")
typedef MessageActionsModal = StreamMessageActionsModal;
/// {@template message_actions_modal}
/// Constructs a modal with actions for a message /// Constructs a modal with actions for a message
class MessageActionsModal extends StatefulWidget { /// {@endtemplate}
/// Constructor for creating a [MessageActionsModal] widget class StreamMessageActionsModal extends StatefulWidget {
const MessageActionsModal({ /// Constructor for creating a [StreamMessageActionsModal] widget
const StreamMessageActionsModal({
Key? key, Key? key,
required this.message, required this.message,
required this.messageWidget, required this.messageWidget,
@@ -43,8 +49,8 @@ class MessageActionsModal extends StatefulWidget {
/// Message in focus for actions /// Message in focus for actions
final Message message; final Message message;
/// [MessageThemeData] for message /// [StreamMessageThemeData] for message
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Flag for showing reactions /// Flag for showing reactions
final bool? showReactions; final bool? showReactions;
@@ -80,13 +86,14 @@ class MessageActionsModal extends StatefulWidget {
final bool reverse; final bool reverse;
/// List of custom actions /// List of custom actions
final List<MessageAction> customActions; final List<StreamMessageAction> customActions;
@override @override
_MessageActionsModalState createState() => _MessageActionsModalState(); _StreamMessageActionsModalState createState() =>
_StreamMessageActionsModalState();
} }
class _MessageActionsModalState extends State<MessageActionsModal> { class _StreamMessageActionsModalState extends State<StreamMessageActionsModal> {
bool _showActions = true; bool _showActions = true;
late List<String> _userPermissions; late List<String> _userPermissions;
late bool _isMyMessage; late bool _isMyMessage;
@@ -159,7 +166,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
: -(1.2 - divFactor)), : -(1.2 - divFactor)),
0, 0,
), ),
child: ReactionPicker( child: StreamReactionPicker(
message: widget.message, message: widget.message,
), ),
), ),
@@ -268,7 +275,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
InkWell _buildCustomAction( InkWell _buildCustomAction(
BuildContext context, BuildContext context,
MessageAction messageAction, StreamMessageAction messageAction,
) => ) =>
InkWell( InkWell(
onTap: () { onTap: () {
@@ -589,7 +596,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
elevation: 2, elevation: 2,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
isScrollControlled: true, isScrollControlled: true,
backgroundColor: MessageInputTheme.of(context).inputBackgroundColor, backgroundColor: StreamMessageInputTheme.of(context).inputBackgroundColor,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topLeft: Radius.circular(16),
@@ -631,7 +638,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
if (widget.editMessageInputBuilder != null) if (widget.editMessageInputBuilder != null)
widget.editMessageInputBuilder!(context, widget.message) widget.editMessageInputBuilder!(context, widget.message)
else else
MessageInput( StreamMessageInput(
messageInputController: MessageInputController( messageInputController: MessageInputController(
message: widget.message, message: widget.message,
), ),
File diff suppressed because it is too large Load Diff
@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Button for showing visual component of slow mode. /// Button for showing visual component of slow mode.
class CountdownButton extends StatelessWidget { class StreamCountdownButton extends StatelessWidget {
/// Constructor for creating [CountdownButton]. /// Constructor for creating [StreamCountdownButton].
const CountdownButton({ const StreamCountdownButton({
Key? key, Key? key,
required this.count, required this.count,
}) : super(key: key); }) : super(key: key);
@@ -18,17 +18,13 @@ import 'package:stream_chat_flutter/src/message_input/tld.dart';
import 'package:stream_chat_flutter/src/multi_overlay.dart'; import 'package:stream_chat_flutter/src/multi_overlay.dart';
import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
import 'package:stream_chat_flutter/src/user_mentions_overlay.dart'; import 'package:stream_chat_flutter/src/user_mentions_overlay.dart';
import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:video_compress/video_compress.dart';
export 'package:video_compress/video_compress.dart' show VideoQuality;
/// A function that returns true if the message is valid and can be sent. /// A function that returns true if the message is valid and can be sent.
typedef MessageValidator = bool Function(Message message); typedef MessageValidator = bool Function(Message message);
/// A callback that can be passed to [MessageInput.onError]. /// A callback that can be passed to [StreamMessageInput.onError].
/// ///
/// This callback should not throw. /// This callback should not throw.
/// ///
@@ -38,7 +34,7 @@ typedef ErrorListener = void Function(
StackTrace? stackTrace, StackTrace? stackTrace,
); );
/// A callback that can be passed to [MessageInput.onAttachmentLimitExceed]. /// A callback that can be passed to [StreamMessageInput.onAttachmentLimitExceed].
/// ///
/// This callback should not throw. /// This callback should not throw.
/// ///
@@ -63,7 +59,7 @@ typedef MentionTileBuilder = Widget Function(
/// Builder function for building a user mention tile. /// Builder function for building a user mention tile.
/// ///
/// Use [UserMentionTile] for the default implementation. /// Use [StreamUserMentionTile] for the default implementation.
typedef UserMentionTileBuilder = Widget Function( typedef UserMentionTileBuilder = Widget Function(
BuildContext context, BuildContext context,
User user, User user,
@@ -92,7 +88,7 @@ typedef AttachmentsPickerBuilder = Widget Function(
StreamAttachmentPicker defaultPicker, StreamAttachmentPicker defaultPicker,
); );
/// Location for actions on the [MessageInput]. /// Location for actions on the [StreamMessageInput].
enum ActionsLocation { enum ActionsLocation {
/// Align to left /// Align to left
left, left,
@@ -173,14 +169,14 @@ const _kDefaultMaxAttachmentSize = 20971520; // 20MB in Bytes
/// } /// }
/// ``` /// ```
/// ///
/// You usually put this widget in the same page of a [MessageListView] /// You usually put this widget in the same page of a [StreamMessageListView]
/// as the bottom widget. /// as the bottom widget.
/// ///
/// The widget renders the ui based on the first ancestor of /// The widget renders the ui based on the first ancestor of
/// type [StreamChatTheme]. Modify it to change the widget appearance. /// type [StreamChatTheme]. Modify it to change the widget appearance.
class MessageInput extends StatefulWidget { class StreamMessageInput extends StatefulWidget {
/// Instantiate a new MessageInput /// Instantiate a new MessageInput
const MessageInput({ const StreamMessageInput({
Key? key, Key? key,
this.onMessageSent, this.onMessageSent,
this.preMessageSending, this.preMessageSending,
@@ -202,8 +198,6 @@ class MessageInput extends StatefulWidget {
this.mentionsTileBuilder, this.mentionsTileBuilder,
this.userMentionsTileBuilder, this.userMentionsTileBuilder,
this.maxAttachmentSize = _kDefaultMaxAttachmentSize, this.maxAttachmentSize = _kDefaultMaxAttachmentSize,
this.compressedVideoQuality = VideoQuality.DefaultQuality,
this.compressedVideoFrameRate = 30,
this.onError, this.onError,
this.attachmentLimit = 10, this.attachmentLimit = 10,
this.onAttachmentLimitExceed, this.onAttachmentLimitExceed,
@@ -224,12 +218,6 @@ class MessageInput extends StatefulWidget {
/// List of options for showing overlays. /// List of options for showing overlays.
final List<OverlayOptions> customOverlays; final List<OverlayOptions> customOverlays;
/// Video quality to use when compressing the videos.
final VideoQuality compressedVideoQuality;
/// Frame rate to use when compressing the videos.
final int compressedVideoFrameRate;
/// Max attachment size in bytes: /// Max attachment size in bytes:
/// - Defaults to 20 MB /// - Defaults to 20 MB
/// - Do not set it if you're using our default CDN /// - Do not set it if you're using our default CDN
@@ -325,7 +313,7 @@ class MessageInput extends StatefulWidget {
/// Builder for creating send button /// Builder for creating send button
final MessageRelatedBuilder? sendButtonBuilder; final MessageRelatedBuilder? sendButtonBuilder;
/// Defines if the [MessageInput] loses focuses after a message is sent. /// Defines if the [StreamMessageInput] loses focuses after a message is sent.
/// The default behaviour keeps focus until a command is enabled. /// The default behaviour keeps focus until a command is enabled.
final bool? shouldKeepFocusAfterMessage; final bool? shouldKeepFocusAfterMessage;
@@ -335,25 +323,25 @@ class MessageInput extends StatefulWidget {
/// Restoration ID to save and restore the state of the MessageInput. /// Restoration ID to save and restore the state of the MessageInput.
final String? restorationId; final String? restorationId;
/// Wrap [MessageInput] with a [SafeArea widget] /// Wrap [StreamMessageInput] with a [SafeArea widget]
final bool? enableSafeArea; final bool? enableSafeArea;
/// Elevation of the [MessageInput] /// Elevation of the [StreamMessageInput]
final double? elevation; final double? elevation;
/// Shadow for the [MessageInput] widget /// Shadow for the [StreamMessageInput] widget
final BoxShadow? shadow; final BoxShadow? shadow;
static bool _defaultValidator(Message message) => static bool _defaultValidator(Message message) =>
message.text?.isNotEmpty == true || message.attachments.isNotEmpty; message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
@override @override
MessageInputState createState() => MessageInputState(); StreamMessageInputState createState() => StreamMessageInputState();
} }
/// State of [MessageInput] /// State of [StreamMessageInput]
class MessageInputState extends State<MessageInput> class StreamMessageInputState extends State<StreamMessageInput>
with RestorationMixin<MessageInput> { with RestorationMixin<StreamMessageInput> {
final _imagePicker = ImagePicker(); final _imagePicker = ImagePicker();
late FocusNode _focusNode = widget.focusNode ?? FocusNode(); late FocusNode _focusNode = widget.focusNode ?? FocusNode();
late final _isInternalFocusNode = widget.focusNode == null; late final _isInternalFocusNode = widget.focusNode == null;
@@ -367,7 +355,7 @@ class MessageInputState extends State<MessageInput>
bool _openFilePickerSection = false; bool _openFilePickerSection = false;
late StreamChatThemeData _streamChatTheme; late StreamChatThemeData _streamChatTheme;
late MessageInputThemeData _messageInputTheme; late StreamMessageInputThemeData _messageInputTheme;
bool get _hasQuotedMessage => bool get _hasQuotedMessage =>
_effectiveController.value.quotedMessage != null; _effectiveController.value.quotedMessage != null;
@@ -410,7 +398,7 @@ class MessageInputState extends State<MessageInput>
} }
@override @override
void didUpdateWidget(covariant MessageInput oldWidget) { void didUpdateWidget(covariant StreamMessageInput oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.messageInputController == null && if (widget.messageInputController == null &&
oldWidget.messageInputController != null) { oldWidget.messageInputController != null) {
@@ -596,7 +584,7 @@ class MessageInputState extends State<MessageInput>
child: child, child: child,
); );
} }
return MultiOverlay( return StreamMultiOverlay(
childAnchor: Alignment.topCenter, childAnchor: Alignment.topCenter,
overlayAnchor: Alignment.bottomCenter, overlayAnchor: Alignment.bottomCenter,
overlayOptions: [ overlayOptions: [
@@ -1109,7 +1097,7 @@ class MessageInputState extends State<MessageInput>
if (renderObject == null) { if (renderObject == null) {
return const Offstage(); return const Offstage();
} }
return CommandsOverlay( return StreamCommandsOverlay(
channel: StreamChannel.of(context).channel, channel: StreamChannel.of(context).channel,
size: Size(renderObject.size.width - 16, 400), size: Size(renderObject.size.width - 16, 400),
text: text, text: text,
@@ -1126,8 +1114,6 @@ class MessageInputState extends State<MessageInput>
attachmentLimit: widget.attachmentLimit, attachmentLimit: widget.attachmentLimit,
onAttachmentLimitExceeded: widget.onAttachmentLimitExceed, onAttachmentLimitExceeded: widget.onAttachmentLimitExceed,
maxAttachmentSize: widget.maxAttachmentSize, maxAttachmentSize: widget.maxAttachmentSize,
compressedVideoQuality: widget.compressedVideoQuality,
compressedVideoFrameRate: widget.compressedVideoFrameRate,
onError: _showErrorAlert, onError: _showErrorAlert,
); );
@@ -1170,7 +1156,7 @@ class MessageInputState extends State<MessageInput>
} }
return LayoutBuilder( return LayoutBuilder(
builder: (context, snapshot) => UserMentionsOverlay( builder: (context, snapshot) => StreamUserMentionsOverlay(
query: query, query: query,
mentionAllAppUsers: widget.mentionAllAppUsers, mentionAllAppUsers: widget.mentionAllAppUsers,
client: StreamChat.of(context).client, client: StreamChat.of(context).client,
@@ -1185,10 +1171,10 @@ class MessageInputState extends State<MessageInput>
splits[splits.length - 1] = user.name; splits[splits.length - 1] = user.name;
final rejoin = splits.join('@'); final rejoin = splits.join('@');
_effectiveController.text = rejoin + _effectiveController.text =
_effectiveController.text.substring( '$rejoin${_effectiveController.text.substring(
_effectiveController.selectionStart, _effectiveController.selectionStart,
); )}';
_onChangedDebounced.cancel(); _onChangedDebounced.cancel();
setState(() => _showMentionsOverlay = false); setState(() => _showMentionsOverlay = false);
@@ -1210,7 +1196,7 @@ class MessageInputState extends State<MessageInput>
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
final renderObject = context.findRenderObject() as RenderBox; final renderObject = context.findRenderObject() as RenderBox;
return EmojiOverlay( return StreamEmojiOverlay(
size: Size(renderObject.size.width - 16, 200), size: Size(renderObject.size.width - 16, 200),
query: query, query: query,
onEmojiResult: (emoji) { onEmojiResult: (emoji) {
@@ -1241,7 +1227,7 @@ class MessageInputState extends State<MessageInput>
if (!_hasQuotedMessage) return const Offstage(); if (!_hasQuotedMessage) return const Offstage();
final containsUrl = _effectiveController.value.quotedMessage!.attachments final containsUrl = _effectiveController.value.quotedMessage!.attachments
.any((element) => element.titleLink != null); .any((element) => element.titleLink != null);
return QuotedMessageWidget( return StreamQuotedMessageWidget(
reverse: true, reverse: true,
showBorder: !containsUrl, showBorder: !containsUrl,
message: _effectiveController.value.quotedMessage!, message: _effectiveController.value.quotedMessage!,
@@ -1275,7 +1261,7 @@ class MessageInputState extends State<MessageInput>
.map<Widget>( .map<Widget>(
(e) => ClipRRect( (e) => ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
child: FileAttachment( child: StreamFileAttachment(
message: Message(), // dummy message message: Message(), // dummy message
attachment: e, attachment: e,
size: Size( size: Size(
@@ -1397,7 +1383,7 @@ class MessageInputState extends State<MessageInput>
case 'video': case 'video':
return Stack( return Stack(
children: [ children: [
VideoThumbnailImage( StreamVideoThumbnailImage(
height: 104, height: 104,
width: 104, width: 104,
video: (attachment.file?.path ?? attachment.assetUrl)!, video: (attachment.file?.path ?? attachment.assetUrl)!,
@@ -1639,33 +1625,11 @@ class MessageInputState extends State<MessageInput>
); );
if (file.size! > widget.maxAttachmentSize) { if (file.size! > widget.maxAttachmentSize) {
if (attachmentType == 'video' && file.path != null) { return _showErrorAlert(
final mediaInfo = await (VideoService.compressVideo( context.translations.fileTooLargeError(
file.path!,
frameRate: widget.compressedVideoFrameRate,
quality: widget.compressedVideoQuality,
) as FutureOr<MediaInfo>);
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
_showErrorAlert(
context.translations.fileTooLargeAfterCompressionError(
widget.maxAttachmentSize / (1024 * 1024),
),
);
return;
}
file = AttachmentFile(
name: file.name,
size: mediaInfo.filesize,
bytes: await mediaInfo.file!.readAsBytes(),
path: mediaInfo.path,
);
} else {
_showErrorAlert(context.translations.fileTooLargeError(
widget.maxAttachmentSize / (1024 * 1024), widget.maxAttachmentSize / (1024 * 1024),
)); ),
return; );
}
} }
_addAttachments([ _addAttachments([
@@ -1715,6 +1679,8 @@ class MessageInputState extends State<MessageInput>
await streamChannel.reloadChannel(); await streamChannel.reloadChannel();
} }
message = message.replaceMentionsWithId();
try { try {
Future sendingFuture; Future sendingFuture;
if (_isEditing) { if (_isEditing) {
@@ -1831,7 +1797,7 @@ class MessageInputState extends State<MessageInput>
@override @override
void didChangeDependencies() { void didChangeDependencies() {
_streamChatTheme = StreamChatTheme.of(context); _streamChatTheme = StreamChatTheme.of(context);
_messageInputTheme = MessageInputTheme.of(context); _messageInputTheme = StreamMessageInputTheme.of(context);
super.didChangeDependencies(); super.didChangeDependencies();
} }
@@ -5,9 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart';
import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:video_compress/video_compress.dart';
/// Callback for when a file has to be picked. /// Callback for when a file has to be picked.
typedef FilePickerCallback = void Function( typedef FilePickerCallback = void Function(
@@ -34,8 +32,6 @@ class StreamAttachmentPicker extends StatefulWidget {
this.attachmentLimit = 10, this.attachmentLimit = 10,
this.onAttachmentLimitExceeded, this.onAttachmentLimitExceeded,
this.maxAttachmentSize = 20971520, this.maxAttachmentSize = 20971520,
this.compressedVideoQuality = VideoQuality.DefaultQuality,
this.compressedVideoFrameRate = 30,
this.onError, this.onError,
this.allowedAttachmentTypes = const [ this.allowedAttachmentTypes = const [
DefaultAttachmentTypes.image, DefaultAttachmentTypes.image,
@@ -66,12 +62,6 @@ class StreamAttachmentPicker extends StatefulWidget {
/// Callback for when file is picked. /// Callback for when file is picked.
final FilePickerCallback onFilePicked; final FilePickerCallback onFilePicked;
/// Video quality to use when compressing the videos.
final VideoQuality compressedVideoQuality;
/// Frame rate to use when compressing the videos.
final int compressedVideoFrameRate;
/// Max attachment size in bytes: /// Max attachment size in bytes:
/// - Defaults to 20 MB /// - Defaults to 20 MB
/// - Do not set it if you're using our default CDN /// - Do not set it if you're using our default CDN
@@ -94,8 +84,6 @@ class StreamAttachmentPicker extends StatefulWidget {
int? attachmentLimit, int? attachmentLimit,
AttachmentLimitExceedListener? onAttachmentLimitExceeded, AttachmentLimitExceedListener? onAttachmentLimitExceeded,
int? maxAttachmentSize, int? maxAttachmentSize,
VideoQuality? compressedVideoQuality,
int? compressedVideoFrameRate,
ValueChanged<bool>? onChangeInputState, ValueChanged<bool>? onChangeInputState,
ValueChanged<String>? onError, ValueChanged<String>? onError,
List<DefaultAttachmentTypes>? allowedAttachmentTypes, List<DefaultAttachmentTypes>? allowedAttachmentTypes,
@@ -112,10 +100,6 @@ class StreamAttachmentPicker extends StatefulWidget {
onAttachmentLimitExceeded: onAttachmentLimitExceeded:
onAttachmentLimitExceeded ?? this.onAttachmentLimitExceeded, onAttachmentLimitExceeded ?? this.onAttachmentLimitExceeded,
maxAttachmentSize: maxAttachmentSize ?? this.maxAttachmentSize, maxAttachmentSize: maxAttachmentSize ?? this.maxAttachmentSize,
compressedVideoQuality:
compressedVideoQuality ?? this.compressedVideoQuality,
compressedVideoFrameRate:
compressedVideoFrameRate ?? this.compressedVideoFrameRate,
onError: onError ?? this.onError, onError: onError ?? this.onError,
allowedAttachmentTypes: allowedAttachmentTypes:
allowedAttachmentTypes ?? this.allowedAttachmentTypes, allowedAttachmentTypes ?? this.allowedAttachmentTypes,
@@ -375,33 +359,11 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
); );
if (file.size! > widget.maxAttachmentSize) { if (file.size! > widget.maxAttachmentSize) {
if (medium.type == AssetType.video && file.path != null) { return widget.onError?.call(
final mediaInfo = await (VideoService.compressVideo( context.translations.fileTooLargeError(
file.path!,
frameRate: widget.compressedVideoFrameRate,
quality: widget.compressedVideoQuality,
) as FutureOr<MediaInfo>);
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
widget.onError?.call(
context.translations.fileTooLargeAfterCompressionError(
widget.maxAttachmentSize / (1024 * 1024),
),
);
return;
}
file = AttachmentFile(
name: file.name,
size: mediaInfo.filesize,
bytes: await mediaInfo.file?.readAsBytes(),
path: mediaInfo.path,
);
} else {
widget.onError?.call(context.translations.fileTooLargeError(
widget.maxAttachmentSize / (1024 * 1024), widget.maxAttachmentSize / (1024 * 1024),
)); ),
return; );
}
} }
setState(() { setState(() {
@@ -507,7 +469,7 @@ class _PickerWidgetState extends State<_PickerWidget> {
), ),
); );
} }
return MediaListView( return StreamMediaListView(
selectedIds: widget.selectedMedias, selectedIds: widget.selectedMedias,
onSelect: widget.onMediaSelected, onSelect: widget.onMediaSelected,
); );
@@ -44,7 +44,7 @@ class StreamMessageSendButton extends StatelessWidget {
late Widget sendButton; late Widget sendButton;
if (timeOut > 0) { if (timeOut > 0) {
sendButton = CountdownButton(count: timeOut); sendButton = StreamCountdownButton(count: timeOut);
} else if (isIdle) { } else if (isIdle) {
sendButton = idleSendButton ?? _buildIdleSendButton(context); sendButton = idleSendButton ?? _buildIdleSendButton(context);
} else { } else {
@@ -63,7 +63,7 @@ class StreamMessageSendButton extends StatelessWidget {
} }
Widget _buildIdleSendButton(BuildContext context) { Widget _buildIdleSendButton(BuildContext context) {
final _messageInputTheme = MessageInputTheme.of(context); final _messageInputTheme = StreamMessageInputTheme.of(context);
return Padding( return Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
@@ -75,7 +75,7 @@ class StreamMessageSendButton extends StatelessWidget {
} }
Widget _buildSendButton(BuildContext context) { Widget _buildSendButton(BuildContext context) {
final _messageInputTheme = MessageInputTheme.of(context); final _messageInputTheme = StreamMessageInputTheme.of(context);
return Padding( return Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
@@ -11,22 +11,22 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:visibility_detector/visibility_detector.dart'; import 'package:visibility_detector/visibility_detector.dart';
/// Widget builder for message /// Widget builder for message
/// [defaultMessageWidget] is the default [MessageWidget] configuration /// [defaultMessageWidget] is the default [StreamMessageWidget] configuration
/// Use [defaultMessageWidget.copyWith] to easily customize it /// Use [defaultMessageWidget.copyWith] to easily customize it
typedef MessageBuilder = Widget Function( typedef MessageBuilder = Widget Function(
BuildContext, BuildContext,
MessageDetails, MessageDetails,
List<Message>, List<Message>,
MessageWidget defaultMessageWidget, StreamMessageWidget defaultMessageWidget,
); );
/// Widget builder for parent message /// Widget builder for parent message
/// [defaultMessageWidget] is the default [MessageWidget] configuration /// [defaultMessageWidget] is the default [StreamMessageWidget] configuration
/// Use [defaultMessageWidget.copyWith] to easily customize it /// Use [defaultMessageWidget.copyWith] to easily customize it
typedef ParentMessageBuilder = Widget Function( typedef ParentMessageBuilder = Widget Function(
BuildContext, BuildContext,
Message?, Message?,
MessageWidget defaultMessageWidget, StreamMessageWidget defaultMessageWidget,
); );
/// Widget builder for system message /// Widget builder for system message
@@ -123,6 +123,11 @@ class MessageDetails {
final int index; final int index;
} }
/// {@macro message_list_view}
@Deprecated("Use 'StreamMessageListView' instead")
typedef MessageListView = StreamMessageListView;
/// {@template message_list_view}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_listview.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_listview.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_listview_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_listview_paint.png)
/// ///
@@ -165,9 +170,10 @@ class MessageDetails {
/// The widget components render the ui based on the first /// The widget components render the ui based on the first
/// ancestor of type [StreamChatTheme]. /// ancestor of type [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageListView extends StatefulWidget { /// {@endtemplate}
class StreamMessageListView extends StatefulWidget {
/// Instantiate a new MessageListView /// Instantiate a new MessageListView
const MessageListView({ const StreamMessageListView({
Key? key, Key? key,
this.showScrollToBottom = true, this.showScrollToBottom = true,
this.messageBuilder, this.messageBuilder,
@@ -330,10 +336,10 @@ class MessageListView extends StatefulWidget {
final SpacingWidgetBuilder? spacingWidgetBuilder; final SpacingWidgetBuilder? spacingWidgetBuilder;
@override @override
_MessageListViewState createState() => _MessageListViewState(); _StreamMessageListViewState createState() => _StreamMessageListViewState();
} }
class _MessageListViewState extends State<MessageListView> { class _StreamMessageListViewState extends State<StreamMessageListView> {
ItemScrollController? _scrollController; ItemScrollController? _scrollController;
void Function(Message)? _onThreadTap; void Function(Message)? _onThreadTap;
final ValueNotifier<bool> _showScrollToBottom = ValueNotifier(false); final ValueNotifier<bool> _showScrollToBottom = ValueNotifier(false);
@@ -461,7 +467,7 @@ class _MessageListViewState extends State<MessageListView> {
final child = Stack( final child = Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
ConnectionStatusBuilder( StreamConnectionStatusBuilder(
statusBuilder: (context, status) { statusBuilder: (context, status) {
var statusString = ''; var statusString = '';
var showStatus = true; var showStatus = true;
@@ -478,7 +484,7 @@ class _MessageListViewState extends State<MessageListView> {
break; break;
} }
return InfoTile( return StreamInfoTile(
showMessage: widget.showConnectionStateTile && showStatus, showMessage: widget.showConnectionStateTile && showStatus,
tileAnchor: Alignment.topCenter, tileAnchor: Alignment.topCenter,
childAnchor: Alignment.topCenter, childAnchor: Alignment.topCenter,
@@ -592,7 +598,7 @@ class _MessageListViewState extends State<MessageListView> {
) )
: Padding( : Padding(
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
child: DateDivider( child: StreamDateDivider(
dateTime: nextMessage.createdAt.toLocal(), dateTime: nextMessage.createdAt.toLocal(),
), ),
); );
@@ -730,8 +736,10 @@ class _MessageListViewState extends State<MessageListView> {
], ],
); );
final backgroundColor = MessageListViewTheme.of(context).backgroundColor; final backgroundColor =
final backgroundImage = MessageListViewTheme.of(context).backgroundImage; StreamMessageListViewTheme.of(context).backgroundColor;
final backgroundImage =
StreamMessageListViewTheme.of(context).backgroundImage;
if (backgroundColor != null || backgroundImage != null) { if (backgroundColor != null || backgroundImage != null) {
return Container( return Container(
@@ -761,7 +769,7 @@ class _MessageListViewState extends State<MessageListView> {
child: Text( child: Text(
context.translations.threadSeparatorText(replyCount), context.translations.threadSeparatorText(replyCount),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: ChannelHeaderTheme.of(context).subtitleStyle, style: StreamChannelHeaderTheme.of(context).subtitleStyle,
), ),
), ),
); );
@@ -815,7 +823,7 @@ class _MessageListViewState extends State<MessageListView> {
final message = messages[index - 2]; final message = messages[index - 2];
return widget.dateDividerBuilder != null return widget.dateDividerBuilder != null
? widget.dateDividerBuilder!(message.createdAt.toLocal()) ? widget.dateDividerBuilder!(message.createdAt.toLocal())
: DateDivider(dateTime: message.createdAt.toLocal()); : StreamDateDivider(dateTime: message.createdAt.toLocal());
}, },
), ),
); );
@@ -976,7 +984,7 @@ class _MessageListViewState extends State<MessageListView> {
final currentUserMember = final currentUserMember =
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
final defaultMessageWidget = MessageWidget( final defaultMessageWidget = StreamMessageWidget(
showReplyMessage: false, showReplyMessage: false,
showResendMessage: false, showResendMessage: false,
showThreadReplyMessage: false, showThreadReplyMessage: false,
@@ -1040,7 +1048,7 @@ class _MessageListViewState extends State<MessageListView> {
if ((message.type == 'system' || message.type == 'error') && if ((message.type == 'system' || message.type == 'error') &&
message.text?.isNotEmpty == true) { message.text?.isNotEmpty == true) {
return widget.systemMessageBuilder?.call(context, message) ?? return widget.systemMessageBuilder?.call(context, message) ??
SystemMessage( StreamSystemMessage(
message: message, message: message,
onMessageTap: (message) { onMessageTap: (message) {
if (widget.onSystemMessageTap != null) { if (widget.onSystemMessageTap != null) {
@@ -1110,7 +1118,7 @@ class _MessageListViewState extends State<MessageListView> {
final currentUserMember = final currentUserMember =
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
Widget messageWidget = MessageWidget( Widget messageWidget = StreamMessageWidget(
message: message, message: message,
reverse: isMyMessage, reverse: isMyMessage,
showReactions: !message.isDeleted, showReactions: !message.isDeleted,
@@ -1226,7 +1234,7 @@ class _MessageListViewState extends State<MessageListView> {
index, index,
), ),
messages, messages,
messageWidget as MessageWidget, messageWidget as StreamMessageWidget,
); );
} }
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro message_reactions_modal}
@Deprecated("Use 'StreamMessageReactionsModal' instead")
typedef MessageReactionsModal = StreamMessageReactionsModal;
/// {@template message_reactions_modal}
/// Modal widget for displaying message reactions /// Modal widget for displaying message reactions
class MessageReactionsModal extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [MessageReactionsModal] reactions class StreamMessageReactionsModal extends StatelessWidget {
const MessageReactionsModal({ /// Constructor for creating a [StreamMessageReactionsModal] reactions
const StreamMessageReactionsModal({
Key? key, Key? key,
required this.message, required this.message,
required this.messageWidget, required this.messageWidget,
@@ -24,8 +30,8 @@ class MessageReactionsModal extends StatelessWidget {
/// Message to display reactions of /// Message to display reactions of
final Message message; final Message message;
/// [MessageThemeData] to apply to [message] /// [StreamMessageThemeData] to apply to [message]
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// Flag to reverse message /// Flag to reverse message
final bool reverse; final bool reverse;
@@ -88,7 +94,7 @@ class MessageReactionsModal extends StatelessWidget {
: -(1.2 - divFactor)), : -(1.2 - divFactor)),
0, 0,
), ),
child: ReactionPicker( child: StreamReactionPicker(
message: message, message: message,
), ),
), ),
@@ -200,7 +206,7 @@ class MessageReactionsModal extends StatelessWidget {
Stack( Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
UserAvatar( StreamUserAvatar(
onTap: onUserAvatarTap, onTap: onUserAvatarTap,
user: reaction.user!, user: reaction.user!,
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
@@ -220,7 +226,7 @@ class MessageReactionsModal extends StatelessWidget {
child: Align( child: Align(
alignment: alignment:
reverse ? Alignment.centerRight : Alignment.centerLeft, reverse ? Alignment.centerRight : Alignment.centerLeft,
child: ReactionBubble( child: StreamReactionBubble(
reactions: [reaction], reactions: [reaction],
flipTail: !reverse, flipTail: !reverse,
borderColor: borderColor:
@@ -2,17 +2,23 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro message_search_item}
@Deprecated("Use 'StreamMessageSearchItem' instead")
typedef MessageSearchItem = StreamMessageSearchItem;
/// {@template message_search_item}
/// It shows the current [Message] preview. /// It shows the current [Message] preview.
/// ///
/// Usually you don't use this widget as it's the default item used by /// Usually you don't use this widget as it's the default item used by
/// [MessageSearchListView]. /// [StreamMessageSearchListView].
/// ///
/// The widget renders the ui based on the first ancestor of type /// The widget renders the ui based on the first ancestor of type
/// [StreamChatTheme]. /// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageSearchItem extends StatelessWidget { /// {@endtemplate}
class StreamMessageSearchItem extends StatelessWidget {
/// Instantiate a new MessageSearchItem /// Instantiate a new MessageSearchItem
const MessageSearchItem({ const StreamMessageSearchItem({
Key? key, Key? key,
required this.getMessageResponse, required this.getMessageResponse,
this.onTap, this.onTap,
@@ -25,7 +31,7 @@ class MessageSearchItem extends StatelessWidget {
/// Function called when tapping this widget /// Function called when tapping this widget
final VoidCallback? onTap; final VoidCallback? onTap;
/// If true the [MessageSearchItem] will show the current online Status /// If true the [StreamMessageSearchItem] will show the current online Status
final bool showOnlineStatus; final bool showOnlineStatus;
@override @override
@@ -34,10 +40,10 @@ class MessageSearchItem extends StatelessWidget {
final channel = getMessageResponse.channel; final channel = getMessageResponse.channel;
final channelName = channel?.extraData['name']; final channelName = channel?.extraData['name'];
final user = message.user!; final user = message.user!;
final channelPreviewTheme = ChannelPreviewTheme.of(context); final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
return ListTile( return ListTile(
onTap: onTap, onTap: onTap,
leading: UserAvatar( leading: StreamUserAvatar(
user: user, user: user,
showOnlineStatus: showOnlineStatus, showOnlineStatus: showOnlineStatus,
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
@@ -120,7 +126,7 @@ class MessageSearchItem extends StatelessWidget {
text = parts.join(' '); text = parts.join(' ');
} }
final channelPreviewTheme = ChannelPreviewTheme.of(context); final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
return Text.rich( return Text.rich(
_getDisplayText( _getDisplayText(
text!, text!,
@@ -11,13 +11,17 @@ typedef MessageSearchItemBuilder = Widget Function(
GetMessageResponse, GetMessageResponse,
); );
/// Builder used when [MessageSearchListView] is empty /// Builder used when [StreamMessageSearchListView] is empty
typedef EmptyMessageSearchBuilder = Widget Function( typedef EmptyMessageSearchBuilder = Widget Function(
BuildContext context, BuildContext context,
String searchQuery, String searchQuery,
); );
/// /// {@macro message_search_list_view}
@Deprecated("Use 'StreamMessageSearchListView' instead")
typedef MessageSearchListView = StreamMessageSearchListView;
/// {@template message_search_list_view}
/// It shows the list of searched messages. /// It shows the list of searched messages.
/// ///
/// ```dart /// ```dart
@@ -47,9 +51,10 @@ typedef EmptyMessageSearchBuilder = Widget Function(
/// The widget components render the ui based on the first ancestor of type /// The widget components render the ui based on the first ancestor of type
/// [StreamChatTheme]. /// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageSearchListView extends StatefulWidget { /// {@endtemplate}
class StreamMessageSearchListView extends StatefulWidget {
/// Instantiate a new MessageSearchListView /// Instantiate a new MessageSearchListView
const MessageSearchListView({ const StreamMessageSearchListView({
Key? key, Key? key,
required this.filters, required this.filters,
this.messageQuery, this.messageQuery,
@@ -96,7 +101,7 @@ class MessageSearchListView extends StatefulWidget {
/// Builder used to create a custom item preview /// Builder used to create a custom item preview
final MessageSearchItemBuilder? itemBuilder; final MessageSearchItemBuilder? itemBuilder;
/// Function called when tapping on a [MessageSearchItem] /// Function called when tapping on a [StreamMessageSearchItem]
final MessageSearchItemTapCallback? onItemTap; final MessageSearchItemTapCallback? onItemTap;
/// Builder used to create a custom item separator /// Builder used to create a custom item separator
@@ -130,10 +135,12 @@ class MessageSearchListView extends StatefulWidget {
final MessageSearchListController? messageSearchListController; final MessageSearchListController? messageSearchListController;
@override @override
_MessageSearchListViewState createState() => _MessageSearchListViewState(); _StreamMessageSearchListViewState createState() =>
_StreamMessageSearchListViewState();
} }
class _MessageSearchListViewState extends State<MessageSearchListView> { class _StreamMessageSearchListViewState
extends State<StreamMessageSearchListView> {
late final _defaultController = MessageSearchListController(); late final _defaultController = MessageSearchListController();
MessageSearchListController get _messageSearchListController => MessageSearchListController get _messageSearchListController =>
@@ -168,7 +175,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
if (error is Error) { if (error is Error) {
print(error.stackTrace); print(error.stackTrace);
} }
return InfoTile( return StreamInfoTile(
showMessage: widget.showErrorTile, showMessage: widget.showErrorTile,
tileAnchor: Alignment.topCenter, tileAnchor: Alignment.topCenter,
childAnchor: Alignment.topCenter, childAnchor: Alignment.topCenter,
@@ -195,7 +202,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
); );
final backgroundColor = final backgroundColor =
MessageSearchListViewTheme.of(context).backgroundColor; StreamMessageSearchListViewTheme.of(context).backgroundColor;
if (backgroundColor != null) { if (backgroundColor != null) {
return ColoredBox( return ColoredBox(
@@ -219,7 +226,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
if (widget.itemBuilder != null) { if (widget.itemBuilder != null) {
return widget.itemBuilder!(context, getMessageResponse); return widget.itemBuilder!(context, getMessageResponse);
} }
return MessageSearchItem( return StreamMessageSearchItem(
getMessageResponse: getMessageResponse, getMessageResponse: getMessageResponse,
onTap: () => widget.onItemTap!(getMessageResponse), onTap: () => widget.onItemTap!(getMessageResponse),
); );
@@ -1,12 +1,19 @@
import 'package:collection/collection.dart' show IterableExtension; import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro message_text}
@Deprecated("Use 'StreamMessageText' instead")
typedef MessageText = StreamMessageText;
/// {@template message_text}
/// Text widget to display in message /// Text widget to display in message
class MessageText extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [MessageText] widget class StreamMessageText extends StatelessWidget {
const MessageText({ /// Constructor for creating a [StreamMessageText] widget
const StreamMessageText({
Key? key, Key? key,
required this.message, required this.message,
required this.messageTheme, required this.messageTheme,
@@ -23,8 +30,8 @@ class MessageText extends StatelessWidget {
/// Callback for when link is tapped /// Callback for when link is tapped
final void Function(String)? onLinkTap; final void Function(String)? onLinkTap;
/// [MessageThemeData] whose text theme is to be applied /// [StreamMessageThemeData] whose text theme is to be applied
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -34,13 +41,14 @@ class MessageText extends StatelessWidget {
stream: streamChat.currentUserStream.map((it) => it!.language ?? 'en'), stream: streamChat.currentUserStream.map((it) => it!.language ?? 'en'),
initialData: streamChat.currentUser!.language ?? 'en', initialData: streamChat.currentUser!.language ?? 'en',
builder: (context, language) { builder: (context, language) {
final translatedText = final messageText = message
message.i18n?['${language}_text'] ?? message.text; .translate(language)
final messageText = .replaceMentions()
_replaceMentions(translatedText ?? '').replaceAll('\n', '\n\n'); .text
?.replaceAll('\n', '\n\n');
final themeData = Theme.of(context); final themeData = Theme.of(context);
return MarkdownBody( return MarkdownBody(
data: messageText, data: messageText ?? '',
onTapLink: ( onTapLink: (
String link, String link,
String? href, String? href,
@@ -80,17 +88,4 @@ class MessageText extends StatelessWidget {
}, },
); );
} }
String _replaceMentions(String text) {
var messageTextToRender = text;
for (final user in message.mentionedUsers.toSet()) {
final userId = user.id;
final userName = user.name;
messageTextToRender = messageTextToRender.replaceAll(
'@$userId',
'[@$userName](@${userName.replaceAll(' ', '')})',
);
}
return messageTextToRender;
}
} }
@@ -32,20 +32,26 @@ enum DisplayWidget {
show, show,
} }
/// {@macro message_widget}
@Deprecated("Use 'StreamMessageWidget' instead")
typedef MessageWidget = StreamMessageWidget;
/// {@template message_widget}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_widget.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_widget.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_widget_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/message_widget_paint.png)
/// ///
/// It shows a message with reactions, replies and user avatar. /// It shows a message with reactions, replies and user avatar.
/// ///
/// Usually you don't use this widget as it's the default message widget used by /// Usually you don't use this widget as it's the default message widget used by
/// [MessageListView]. /// [StreamMessageListView].
/// ///
/// The widget components render the ui based on the first ancestor of type /// The widget components render the ui based on the first ancestor of type
/// [StreamChatTheme]. /// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class MessageWidget extends StatefulWidget { /// {@endtemplate}
/// class StreamMessageWidget extends StatefulWidget {
MessageWidget({ /// Creates a new instance of the message widget.
StreamMessageWidget({
Key? key, Key? key,
required this.message, required this.message,
required this.messageTheme, required this.messageTheme,
@@ -121,7 +127,7 @@ class MessageWidget extends StatefulWidget {
context, context,
Material( Material(
color: messageTheme.messageBackgroundColor, color: messageTheme.messageBackgroundColor,
child: ImageGroup( child: StreamImageGroup(
size: Size( size: Size(
mediaQueryData.size.width * 0.8, mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3, mediaQueryData.size.height * 0.3,
@@ -142,7 +148,7 @@ class MessageWidget extends StatefulWidget {
return wrapAttachmentWidget( return wrapAttachmentWidget(
context, context,
ImageAttachment( StreamImageAttachment(
attachment: attachments[0], attachment: attachments[0],
message: message, message: message,
messageTheme: messageTheme, messageTheme: messageTheme,
@@ -172,7 +178,7 @@ class MessageWidget extends StatefulWidget {
Column( Column(
children: attachments.map((attachment) { children: attachments.map((attachment) {
final mediaQueryData = MediaQuery.of(context); final mediaQueryData = MediaQuery.of(context);
return VideoAttachment( return StreamVideoAttachment(
attachment: attachment, attachment: attachment,
messageTheme: messageTheme, messageTheme: messageTheme,
size: Size( size: Size(
@@ -204,7 +210,7 @@ class MessageWidget extends StatefulWidget {
Column( Column(
children: attachments.map((attachment) { children: attachments.map((attachment) {
final mediaQueryData = MediaQuery.of(context); final mediaQueryData = MediaQuery.of(context);
return GiphyAttachment( return StreamGiphyAttachment(
attachment: attachment, attachment: attachment,
message: message, message: message,
size: Size( size: Size(
@@ -240,7 +246,7 @@ class MessageWidget extends StatefulWidget {
final mediaQueryData = MediaQuery.of(context); final mediaQueryData = MediaQuery.of(context);
return wrapAttachmentWidget( return wrapAttachmentWidget(
context, context,
FileAttachment( StreamFileAttachment(
message: message, message: message,
attachment: attachment, attachment: attachment,
size: Size( size: Size(
@@ -300,7 +306,7 @@ class MessageWidget extends StatefulWidget {
final Message message; final Message message;
/// The message theme /// The message theme
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// If true the widget will be mirrored /// If true the widget will be mirrored
final bool reverse; final bool reverse;
@@ -356,7 +362,7 @@ class MessageWidget extends StatefulWidget {
/// The function called when tapping on a link /// The function called when tapping on a link
final void Function(String)? onLinkTap; final void Function(String)? onLinkTap;
/// Used in [MessageReactionsModal] and [MessageActionsModal] /// Used in [StreamMessageReactionsModal] and [StreamMessageActionsModal]
final bool showReactionPickerIndicator; final bool showReactionPickerIndicator;
/// List of users who read /// List of users who read
@@ -417,13 +423,13 @@ class MessageWidget extends StatefulWidget {
final void Function(Message)? onMessageTap; final void Function(Message)? onMessageTap;
/// List of custom actions shown on message long tap /// List of custom actions shown on message long tap
final List<MessageAction> customActions; final List<StreamMessageAction> customActions;
/// Customize onTap on attachment /// Customize onTap on attachment
final void Function(Message message, Attachment attachment)? onAttachmentTap; final void Function(Message message, Attachment attachment)? onAttachmentTap;
/// Creates a copy of [MessageWidget] with specified attributes overridden. /// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
MessageWidget copyWith({ StreamMessageWidget copyWith({
Key? key, Key? key,
void Function(User)? onMentionTap, void Function(User)? onMentionTap,
void Function(Message)? onThreadTap, void Function(Message)? onThreadTap,
@@ -435,7 +441,7 @@ class MessageWidget extends StatefulWidget {
Widget Function(BuildContext, Message)? deletedBottomRowBuilder, Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
void Function(BuildContext, Message)? onMessageActions, void Function(BuildContext, Message)? onMessageActions,
Message? message, Message? message,
MessageThemeData? messageTheme, StreamMessageThemeData? messageTheme,
bool? reverse, bool? reverse,
ShapeBorder? shape, ShapeBorder? shape,
ShapeBorder? attachmentShape, ShapeBorder? attachmentShape,
@@ -473,11 +479,11 @@ class MessageWidget extends StatefulWidget {
bool? translateUserAvatar, bool? translateUserAvatar,
OnQuotedMessageTap? onQuotedMessageTap, OnQuotedMessageTap? onQuotedMessageTap,
void Function(Message)? onMessageTap, void Function(Message)? onMessageTap,
List<MessageAction>? customActions, List<StreamMessageAction>? customActions,
void Function(Message message, Attachment attachment)? onAttachmentTap, void Function(Message message, Attachment attachment)? onAttachmentTap,
Widget Function(BuildContext, User)? userAvatarBuilder, Widget Function(BuildContext, User)? userAvatarBuilder,
}) => }) =>
MessageWidget( StreamMessageWidget(
key: key ?? this.key, key: key ?? this.key,
onMentionTap: onMentionTap ?? this.onMentionTap, onMentionTap: onMentionTap ?? this.onMentionTap,
onThreadTap: onThreadTap ?? this.onThreadTap, onThreadTap: onThreadTap ?? this.onThreadTap,
@@ -539,11 +545,11 @@ class MessageWidget extends StatefulWidget {
); );
@override @override
_MessageWidgetState createState() => _MessageWidgetState(); _StreamMessageWidgetState createState() => _StreamMessageWidgetState();
} }
class _MessageWidgetState extends State<MessageWidget> class _StreamMessageWidgetState extends State<StreamMessageWidget>
with AutomaticKeepAliveClientMixin<MessageWidget> { with AutomaticKeepAliveClientMixin<StreamMessageWidget> {
bool get showThreadReplyIndicator => widget.showThreadReplyIndicator; bool get showThreadReplyIndicator => widget.showThreadReplyIndicator;
bool get showSendingIndicator => widget.showSendingIndicator; bool get showSendingIndicator => widget.showSendingIndicator;
@@ -717,7 +723,7 @@ class _MessageWidgetState extends State<MessageWidget>
? 0 ? 0
: 4.0, : 4.0,
), ),
child: DeletedMessage( child: StreamDeletedMessage(
borderRadiusGeometry: widget borderRadiusGeometry: widget
.borderRadiusGeometry, .borderRadiusGeometry,
borderSide: borderSide:
@@ -854,7 +860,7 @@ class _MessageWidgetState extends State<MessageWidget>
? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId) ? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId)
: null; : null;
final chatThemeData = _streamChatTheme; final chatThemeData = _streamChatTheme;
return QuotedMessageWidget( return StreamQuotedMessageWidget(
onTap: onTap, onTap: onTap,
message: widget.message.quotedMessage!, message: widget.message.quotedMessage!,
messageTheme: isMyMessage messageTheme: isMyMessage
@@ -1008,7 +1014,7 @@ class _MessageWidgetState extends State<MessageWidget>
getWebsiteName(hostName.toLowerCase()) ?? getWebsiteName(hostName.toLowerCase()) ??
hostName.capitalize(); hostName.capitalize();
return UrlAttachment( return StreamUrlAttachment(
urlAttachment: urlAttachment, urlAttachment: urlAttachment,
hostDisplayName: hostDisplayName, hostDisplayName: hostDisplayName,
textPadding: widget.textPadding, textPadding: widget.textPadding,
@@ -1041,7 +1047,7 @@ class _MessageWidgetState extends State<MessageWidget>
child: _shouldShowReactions child: _shouldShowReactions
? GestureDetector( ? GestureDetector(
onTap: () => _showMessageReactionsModalBottomSheet(context), onTap: () => _showMessageReactionsModalBottomSheet(context),
child: ReactionBubble( child: StreamReactionBubble(
key: ValueKey('${widget.message.id}.reactions'), key: ValueKey('${widget.message.id}.reactions'),
reverse: widget.reverse, reverse: widget.reverse,
flipTail: widget.reverse, flipTail: widget.reverse,
@@ -1072,7 +1078,7 @@ class _MessageWidgetState extends State<MessageWidget>
barrierColor: _streamChatTheme.colorTheme.overlay, barrierColor: _streamChatTheme.colorTheme.overlay,
builder: (context) => StreamChannel( builder: (context) => StreamChannel(
channel: channel, channel: channel,
child: MessageActionsModal( child: StreamMessageActionsModal(
messageWidget: widget.copyWith( messageWidget: widget.copyWith(
key: const Key('MessageWidget'), key: const Key('MessageWidget'),
message: widget.message.copyWith( message: widget.message.copyWith(
@@ -1129,7 +1135,7 @@ class _MessageWidgetState extends State<MessageWidget>
barrierColor: _streamChatTheme.colorTheme.overlay, barrierColor: _streamChatTheme.colorTheme.overlay,
builder: (context) => StreamChannel( builder: (context) => StreamChannel(
channel: channel, channel: channel,
child: MessageReactionsModal( child: StreamMessageReactionsModal(
messageWidget: widget.copyWith( messageWidget: widget.copyWith(
key: const Key('MessageWidget'), key: const Key('MessageWidget'),
message: widget.message.copyWith( message: widget.message.copyWith(
@@ -1246,7 +1252,7 @@ class _MessageWidgetState extends State<MessageWidget>
final channel = StreamChannel.of(context).channel; final channel = StreamChannel.of(context).channel;
if (!channel.ownCapabilities.contains(PermissionType.readEvents)) { if (!channel.ownCapabilities.contains(PermissionType.readEvents)) {
return SendingIndicator( return StreamSendingIndicator(
message: message, message: message,
size: style!.fontSize, size: style!.fontSize,
); );
@@ -1261,7 +1267,7 @@ class _MessageWidgetState extends State<MessageWidget>
(it.lastRead.isAfter(message.createdAt) || (it.lastRead.isAfter(message.createdAt) ||
it.lastRead.isAtSameMomentAs(message.createdAt))); it.lastRead.isAtSameMomentAs(message.createdAt)));
final isMessageRead = readList.length >= (channel.memberCount ?? 0) - 1; final isMessageRead = readList.length >= (channel.memberCount ?? 0) - 1;
Widget child = SendingIndicator( Widget child = StreamSendingIndicator(
message: message, message: message,
isMessageRead: isMessageRead, isMessageRead: isMessageRead,
size: style!.fontSize, size: style!.fontSize,
@@ -1295,7 +1301,7 @@ class _MessageWidgetState extends State<MessageWidget>
: 0, : 0,
), ),
child: widget.userAvatarBuilder?.call(context, widget.message.user!) ?? child: widget.userAvatarBuilder?.call(context, widget.message.user!) ??
UserAvatar( StreamUserAvatar(
user: widget.message.user!, user: widget.message.user!,
onTap: widget.onUserAvatarTap, onTap: widget.onUserAvatarTap,
constraints: widget.messageTheme.avatarTheme!.constraints, constraints: widget.messageTheme.avatarTheme!.constraints,
@@ -1313,7 +1319,7 @@ class _MessageWidgetState extends State<MessageWidget>
padding: isOnlyEmoji ? EdgeInsets.zero : widget.textPadding, padding: isOnlyEmoji ? EdgeInsets.zero : widget.textPadding,
child: widget.textBuilder != null child: widget.textBuilder != null
? widget.textBuilder!(context, widget.message) ? widget.textBuilder!(context, widget.message)
: MessageText( : StreamMessageText(
onLinkTap: widget.onLinkTap, onLinkTap: widget.onLinkTap,
message: widget.message, message: widget.message,
onMentionTap: widget.onMentionTap, onMentionTap: widget.onMentionTap,
@@ -1430,7 +1436,7 @@ class _ThreadParticipants extends StatelessWidget {
color: _streamChatTheme.colorTheme.barsBg, color: _streamChatTheme.colorTheme.barsBg,
), ),
padding: const EdgeInsets.all(1), padding: const EdgeInsets.all(1),
child: UserAvatar( child: StreamUserAvatar(
user: user, user: user,
constraints: BoxConstraints.loose(const Size.fromRadius(7)), constraints: BoxConstraints.loose(const Size.fromRadius(7)),
showOnlineStatus: false, showOnlineStatus: false,
@@ -2,15 +2,21 @@ import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_portal/flutter_portal.dart';
/// {@macro multi_overlay}
@Deprecated("Use 'StreamMultiOverlay' instead")
typedef MultiOverlay = StreamMultiOverlay;
/// {@template multi_overlay}
/// Widget that renders a single overlay widget from a list of [overlayOptions] /// Widget that renders a single overlay widget from a list of [overlayOptions]
/// It shows the first one that is visible /// It shows the first one that is visible
class MultiOverlay extends StatelessWidget { /// {@endtemplate}
class StreamMultiOverlay extends StatelessWidget {
/// Constructs a new MultiOverlay widget /// Constructs a new MultiOverlay widget
/// [overlayOptions] - the list of overlay options /// [overlayOptions] - the list of overlay options
/// [overlayAnchor] - the anchor relative to the overlay /// [overlayAnchor] - the anchor relative to the overlay
/// [childAnchor] - the anchor relative to the child /// [childAnchor] - the anchor relative to the child
/// [child] - the child widget /// [child] - the child widget
const MultiOverlay({ const StreamMultiOverlay({
Key? key, Key? key,
required this.overlayOptions, required this.overlayOptions,
required this.child, required this.child,
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro option_list_tile}
@Deprecated("Use 'StreamOptionListTile' instead")
typedef OptionListTile = StreamOptionListTile;
/// {@template option_list_tile}
/// List tile for [ChannelBottomSheet] /// List tile for [ChannelBottomSheet]
class OptionListTile extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating [OptionListTile] class StreamOptionListTile extends StatelessWidget {
const OptionListTile({ /// Constructor for creating [StreamOptionListTile]
const StreamOptionListTile({
Key? key, Key? key,
required this.title, required this.title,
this.leading, this.leading,
@@ -10,54 +10,14 @@ typedef QuotedMessageAttachmentThumbnailBuilder = Widget Function(
Attachment, Attachment,
); );
class _VideoAttachmentThumbnail extends StatefulWidget { /// Widget for the quoted message.
const _VideoAttachmentThumbnail({ @Deprecated("Use 'StreamQuotedMessageWidget' instead")
Key? key, typedef QuotedMessageWidget = StreamQuotedMessageWidget;
required this.attachment,
this.size = const Size(32, 32),
}) : super(key: key);
final Size size; /// Widget for the quoted message.
final Attachment attachment; class StreamQuotedMessageWidget extends StatelessWidget {
/// Creates a new instance of the widget.
@override const StreamQuotedMessageWidget({
_VideoAttachmentThumbnailState createState() =>
_VideoAttachmentThumbnailState();
}
class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.attachment.assetUrl!)
..initialize().then((_) {
// ignore: no-empty-block
setState(() {}); //when your thumbnail will show.
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) => SizedBox(
height: widget.size.height,
width: widget.size.width,
child: _controller.value.isInitialized
? VideoPlayer(_controller)
: const CircularProgressIndicator(),
);
}
///
class QuotedMessageWidget extends StatelessWidget {
///
const QuotedMessageWidget({
Key? key, Key? key,
required this.message, required this.message,
required this.messageTheme, required this.messageTheme,
@@ -73,7 +33,7 @@ class QuotedMessageWidget extends StatelessWidget {
final Message message; final Message message;
/// The message theme /// The message theme
final MessageThemeData messageTheme; final StreamMessageThemeData messageTheme;
/// If true the widget will be mirrored /// If true the widget will be mirrored
final bool reverse; final bool reverse;
@@ -134,7 +94,7 @@ class QuotedMessageWidget extends StatelessWidget {
if (_hasAttachments) _parseAttachments(context), if (_hasAttachments) _parseAttachments(context),
if (msg.text!.isNotEmpty) if (msg.text!.isNotEmpty)
Flexible( Flexible(
child: MessageText( child: StreamMessageText(
message: msg, message: msg,
messageTheme: isOnlyEmoji && _containsText messageTheme: isOnlyEmoji && _containsText
? messageTheme.copyWith( ? messageTheme.copyWith(
@@ -231,7 +191,7 @@ class QuotedMessageWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
); );
Widget _buildUserAvatar() => UserAvatar( Widget _buildUserAvatar() => StreamUserAvatar(
user: message.user!, user: message.user!,
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 24, height: 24,
@@ -242,7 +202,7 @@ class QuotedMessageWidget extends StatelessWidget {
Map<String, QuotedMessageAttachmentThumbnailBuilder> Map<String, QuotedMessageAttachmentThumbnailBuilder>
get _defaultAttachmentBuilder => { get _defaultAttachmentBuilder => {
'image': (_, attachment) => ImageAttachment( 'image': (_, attachment) => StreamImageAttachment(
attachment: attachment, attachment: attachment,
message: message, message: message,
messageTheme: messageTheme, messageTheme: messageTheme,
@@ -288,3 +248,47 @@ class QuotedMessageWidget extends StatelessWidget {
return messageTheme.messageBackgroundColor; return messageTheme.messageBackgroundColor;
} }
} }
class _VideoAttachmentThumbnail extends StatefulWidget {
const _VideoAttachmentThumbnail({
Key? key,
required this.attachment,
this.size = const Size(32, 32),
}) : super(key: key);
final Size size;
final Attachment attachment;
@override
_VideoAttachmentThumbnailState createState() =>
_VideoAttachmentThumbnailState();
}
class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.attachment.assetUrl!)
..initialize().then((_) {
// ignore: no-empty-block
setState(() {}); //when your thumbnail will show.
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) => SizedBox(
height: widget.size.height,
width: widget.size.width,
child: _controller.value.isInitialized
? VideoPlayer(_controller)
: const CircularProgressIndicator(),
);
}
@@ -4,10 +4,16 @@ import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro reaction_bubble}
@Deprecated("Use 'StreamReactionBubble' instead")
typedef ReactionBubble = StreamReactionBubble;
/// {@template reaction_bubble}
/// Creates reaction bubble widget for displaying over messages /// Creates reaction bubble widget for displaying over messages
class ReactionBubble extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [ReactionBubble] class StreamReactionBubble extends StatelessWidget {
const ReactionBubble({ /// Constructor for creating a [StreamReactionBubble]
const StreamReactionBubble({
Key? key, Key? key,
required this.reactions, required this.reactions,
required this.borderColor, required this.borderColor,
@@ -111,7 +117,7 @@ class ReactionBubble extends StatelessWidget {
} }
Widget _buildReaction( Widget _buildReaction(
List<ReactionIcon> reactionIcons, List<StreamReactionIcon> reactionIcons,
Reaction reaction, Reaction reaction,
BuildContext context, BuildContext context,
) { ) {
@@ -1,9 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// Reaction icon data /// Reaction icon data
class ReactionIcon { @Deprecated("Use 'StreamReactionIcon' instead")
/// Constructor for creating [ReactionIcon] typedef ReactionIcon = StreamReactionIcon;
ReactionIcon({
/// Reaction icon data
class StreamReactionIcon {
/// Constructor for creating [StreamReactionIcon]
StreamReactionIcon({
required this.type, required this.type,
required this.builder, required this.builder,
}); });
@@ -3,16 +3,22 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro reaction_picker}
@Deprecated("Use 'StreamReactionPicker' instead")
typedef ReactionPicker = StreamReactionPicker;
/// {@template reaction_picker}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/reaction_picker.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/reaction_picker.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/reaction_picker_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/reaction_picker_paint.png)
/// ///
/// It shows a reaction picker /// It shows a reaction picker
/// ///
/// Usually you don't use this widget as it's one of the default widgets used /// Usually you don't use this widget as it's one of the default widgets used
/// by [MessageWidget.onMessageActions]. /// by [StreamMessageWidget.onMessageActions].
class ReactionPicker extends StatefulWidget { /// {@endtemplate}
/// Constructor for creating a [ReactionPicker] widget class StreamReactionPicker extends StatefulWidget {
const ReactionPicker({ /// Constructor for creating a [StreamReactionPicker] widget
const StreamReactionPicker({
Key? key, Key? key,
required this.message, required this.message,
}) : super(key: key); }) : super(key: key);
@@ -21,10 +27,10 @@ class ReactionPicker extends StatefulWidget {
final Message message; final Message message;
@override @override
_ReactionPickerState createState() => _ReactionPickerState(); _StreamReactionPickerState createState() => _StreamReactionPickerState();
} }
class _ReactionPickerState extends State<ReactionPicker> class _StreamReactionPickerState extends State<StreamReactionPicker>
with TickerProviderStateMixin { with TickerProviderStateMixin {
List<EzAnimation> animations = []; List<EzAnimation> animations = [];
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro sending_indicator}
@Deprecated("Use 'StreamSendingIndicator' instead")
typedef SendingIndicator = StreamSendingIndicator;
/// {@template sending_indicator}
/// Used to show the sending status of the message /// Used to show the sending status of the message
class SendingIndicator extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [SendingIndicator] widget class StreamSendingIndicator extends StatelessWidget {
const SendingIndicator({ /// Constructor for creating a [StreamSendingIndicator] widget
const StreamSendingIndicator({
Key? key, Key? key,
required this.message, required this.message,
this.isMessageRead = false, this.isMessageRead = false,
@@ -38,29 +38,29 @@ class StreamChatThemeData {
/// Create a theme from scratch /// Create a theme from scratch
factory StreamChatThemeData({ factory StreamChatThemeData({
Brightness? brightness, Brightness? brightness,
TextTheme? textTheme, StreamTextTheme? textTheme,
ColorTheme? colorTheme, StreamColorTheme? colorTheme,
ChannelListHeaderThemeData? channelListHeaderTheme, StreamChannelListHeaderThemeData? channelListHeaderTheme,
ChannelPreviewThemeData? channelPreviewTheme, StreamChannelPreviewThemeData? channelPreviewTheme,
ChannelHeaderThemeData? channelHeaderTheme, StreamChannelHeaderThemeData? channelHeaderTheme,
MessageThemeData? otherMessageTheme, StreamMessageThemeData? otherMessageTheme,
MessageThemeData? ownMessageTheme, StreamMessageThemeData? ownMessageTheme,
MessageInputThemeData? messageInputTheme, StreamMessageInputThemeData? messageInputTheme,
Widget Function(BuildContext, User)? defaultUserImage, Widget Function(BuildContext, User)? defaultUserImage,
Widget Function(BuildContext, User)? placeholderUserImage, Widget Function(BuildContext, User)? placeholderUserImage,
IconThemeData? primaryIconTheme, IconThemeData? primaryIconTheme,
List<ReactionIcon>? reactionIcons, List<StreamReactionIcon>? reactionIcons,
GalleryHeaderThemeData? imageHeaderTheme, StreamGalleryHeaderThemeData? imageHeaderTheme,
GalleryFooterThemeData? imageFooterTheme, StreamGalleryFooterThemeData? imageFooterTheme,
MessageListViewThemeData? messageListViewTheme, StreamMessageListViewThemeData? messageListViewTheme,
ChannelListViewThemeData? channelListViewTheme, StreamChannelListViewThemeData? channelListViewTheme,
UserListViewThemeData? userListViewTheme, StreamUserListViewThemeData? userListViewTheme,
MessageSearchListViewThemeData? messageSearchListViewTheme, StreamMessageSearchListViewThemeData? messageSearchListViewTheme,
}) { }) {
brightness ??= colorTheme?.brightness ?? Brightness.light; brightness ??= colorTheme?.brightness ?? Brightness.light;
final isDark = brightness == Brightness.dark; final isDark = brightness == Brightness.dark;
textTheme ??= isDark ? TextTheme.dark() : TextTheme.light(); textTheme ??= isDark ? StreamTextTheme.dark() : StreamTextTheme.light();
colorTheme ??= isDark ? ColorTheme.dark() : ColorTheme.light(); colorTheme ??= isDark ? StreamColorTheme.dark() : StreamColorTheme.light();
final defaultData = StreamChatThemeData.fromColorAndTextTheme( final defaultData = StreamChatThemeData.fromColorAndTextTheme(
colorTheme, colorTheme,
@@ -133,14 +133,14 @@ class StreamChatThemeData {
/// Create theme from color and text theme /// Create theme from color and text theme
factory StreamChatThemeData.fromColorAndTextTheme( factory StreamChatThemeData.fromColorAndTextTheme(
ColorTheme colorTheme, StreamColorTheme colorTheme,
TextTheme textTheme, StreamTextTheme textTheme,
) { ) {
final accentColor = colorTheme.accentPrimary; final accentColor = colorTheme.accentPrimary;
final iconTheme = final iconTheme =
IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5)); IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5));
final channelHeaderTheme = ChannelHeaderThemeData( final channelHeaderTheme = StreamChannelHeaderThemeData(
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 40, height: 40,
@@ -153,9 +153,9 @@ class StreamChatThemeData {
color: const Color(0xff7A7A7A), color: const Color(0xff7A7A7A),
), ),
); );
final channelPreviewTheme = ChannelPreviewThemeData( final channelPreviewTheme = StreamChannelPreviewThemeData(
unreadCounterColor: colorTheme.accentError, unreadCounterColor: colorTheme.accentError,
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 40, height: 40,
@@ -176,14 +176,14 @@ class StreamChatThemeData {
colorTheme: colorTheme, colorTheme: colorTheme,
primaryIconTheme: iconTheme, primaryIconTheme: iconTheme,
defaultUserImage: (context, user) => Center( defaultUserImage: (context, user) => Center(
child: GradientAvatar( child: StreamGradientAvatar(
name: user.name, name: user.name,
userId: user.id, userId: user.id,
), ),
), ),
channelPreviewTheme: channelPreviewTheme, channelPreviewTheme: channelPreviewTheme,
channelListHeaderTheme: ChannelListHeaderThemeData( channelListHeaderTheme: StreamChannelListHeaderThemeData(
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 40, height: 40,
@@ -194,7 +194,7 @@ class StreamChatThemeData {
titleStyle: textTheme.headlineBold, titleStyle: textTheme.headlineBold,
), ),
channelHeaderTheme: channelHeaderTheme, channelHeaderTheme: channelHeaderTheme,
ownMessageTheme: MessageThemeData( ownMessageTheme: StreamMessageThemeData(
messageAuthorStyle: messageAuthorStyle:
textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis),
messageTextStyle: textTheme.body, messageTextStyle: textTheme.body,
@@ -206,7 +206,7 @@ class StreamChatThemeData {
reactionsBorderColor: colorTheme.borders, reactionsBorderColor: colorTheme.borders,
reactionsMaskColor: colorTheme.appBg, reactionsMaskColor: colorTheme.appBg,
messageBorderColor: colorTheme.disabled, messageBorderColor: colorTheme.disabled,
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 32, height: 32,
@@ -218,7 +218,7 @@ class StreamChatThemeData {
), ),
linkBackgroundColor: colorTheme.linkBg, linkBackgroundColor: colorTheme.linkBg,
), ),
otherMessageTheme: MessageThemeData( otherMessageTheme: StreamMessageThemeData(
reactionsBackgroundColor: colorTheme.disabled, reactionsBackgroundColor: colorTheme.disabled,
reactionsBorderColor: colorTheme.barsBg, reactionsBorderColor: colorTheme.barsBg,
reactionsMaskColor: colorTheme.appBg, reactionsMaskColor: colorTheme.appBg,
@@ -233,7 +233,7 @@ class StreamChatThemeData {
), ),
messageBackgroundColor: colorTheme.barsBg, messageBackgroundColor: colorTheme.barsBg,
messageBorderColor: colorTheme.borders, messageBorderColor: colorTheme.borders,
avatarTheme: AvatarThemeData( avatarTheme: StreamAvatarThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
constraints: const BoxConstraints.tightFor( constraints: const BoxConstraints.tightFor(
height: 32, height: 32,
@@ -242,7 +242,7 @@ class StreamChatThemeData {
), ),
linkBackgroundColor: colorTheme.linkBg, linkBackgroundColor: colorTheme.linkBg,
), ),
messageInputTheme: MessageInputThemeData( messageInputTheme: StreamMessageInputThemeData(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
sendAnimationDuration: const Duration(milliseconds: 300), sendAnimationDuration: const Duration(milliseconds: 300),
actionButtonColor: colorTheme.accentPrimary, actionButtonColor: colorTheme.accentPrimary,
@@ -267,7 +267,7 @@ class StreamChatThemeData {
), ),
), ),
reactionIcons: [ reactionIcons: [
ReactionIcon( StreamReactionIcon(
type: 'love', type: 'love',
builder: (context, highlighted, size) { builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
@@ -279,7 +279,7 @@ class StreamChatThemeData {
); );
}, },
), ),
ReactionIcon( StreamReactionIcon(
type: 'like', type: 'like',
builder: (context, highlighted, size) { builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
@@ -291,7 +291,7 @@ class StreamChatThemeData {
); );
}, },
), ),
ReactionIcon( StreamReactionIcon(
type: 'sad', type: 'sad',
builder: (context, highlighted, size) { builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
@@ -303,7 +303,7 @@ class StreamChatThemeData {
); );
}, },
), ),
ReactionIcon( StreamReactionIcon(
type: 'haha', type: 'haha',
builder: (context, highlighted, size) { builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
@@ -315,7 +315,7 @@ class StreamChatThemeData {
); );
}, },
), ),
ReactionIcon( StreamReactionIcon(
type: 'wow', type: 'wow',
builder: (context, highlighted, size) { builder: (context, highlighted, size) {
final theme = StreamChatTheme.of(context); final theme = StreamChatTheme.of(context);
@@ -328,7 +328,7 @@ class StreamChatThemeData {
}, },
), ),
], ],
galleryHeaderTheme: GalleryHeaderThemeData( galleryHeaderTheme: StreamGalleryHeaderThemeData(
closeButtonColor: colorTheme.textHighEmphasis, closeButtonColor: colorTheme.textHighEmphasis,
backgroundColor: channelHeaderTheme.color, backgroundColor: channelHeaderTheme.color,
iconMenuPointColor: colorTheme.textHighEmphasis, iconMenuPointColor: colorTheme.textHighEmphasis,
@@ -336,7 +336,7 @@ class StreamChatThemeData {
subtitleTextStyle: channelPreviewTheme.subtitleStyle, subtitleTextStyle: channelPreviewTheme.subtitleStyle,
bottomSheetBarrierColor: colorTheme.overlay, bottomSheetBarrierColor: colorTheme.overlay,
), ),
galleryFooterTheme: GalleryFooterThemeData( galleryFooterTheme: StreamGalleryFooterThemeData(
backgroundColor: colorTheme.barsBg, backgroundColor: colorTheme.barsBg,
shareIconColor: colorTheme.textHighEmphasis, shareIconColor: colorTheme.textHighEmphasis,
titleTextStyle: textTheme.headlineBold, titleTextStyle: textTheme.headlineBold,
@@ -346,52 +346,52 @@ class StreamChatThemeData {
bottomSheetPhotosTextStyle: textTheme.headlineBold, bottomSheetPhotosTextStyle: textTheme.headlineBold,
bottomSheetCloseIconColor: colorTheme.textHighEmphasis, bottomSheetCloseIconColor: colorTheme.textHighEmphasis,
), ),
messageListViewTheme: MessageListViewThemeData( messageListViewTheme: StreamMessageListViewThemeData(
backgroundColor: colorTheme.barsBg, backgroundColor: colorTheme.barsBg,
), ),
channelListViewTheme: ChannelListViewThemeData( channelListViewTheme: StreamChannelListViewThemeData(
backgroundColor: colorTheme.appBg, backgroundColor: colorTheme.appBg,
), ),
userListViewTheme: UserListViewThemeData( userListViewTheme: StreamUserListViewThemeData(
backgroundColor: colorTheme.appBg, backgroundColor: colorTheme.appBg,
), ),
messageSearchListViewTheme: MessageSearchListViewThemeData( messageSearchListViewTheme: StreamMessageSearchListViewThemeData(
backgroundColor: colorTheme.appBg, backgroundColor: colorTheme.appBg,
), ),
); );
} }
/// The text themes used in the widgets /// The text themes used in the widgets
final TextTheme textTheme; final StreamTextTheme textTheme;
/// The color themes used in the widgets /// The color themes used in the widgets
final ColorTheme colorTheme; final StreamColorTheme colorTheme;
/// Theme of the [ChannelPreview] /// Theme of the [StreamChannelPreview]
final ChannelPreviewThemeData channelPreviewTheme; final StreamChannelPreviewThemeData channelPreviewTheme;
/// Theme of the [ChannelListHeader] /// Theme of the [StreamChannelListHeader]
final ChannelListHeaderThemeData channelListHeaderTheme; final StreamChannelListHeaderThemeData channelListHeaderTheme;
/// Theme of the chat widgets dedicated to a channel header /// Theme of the chat widgets dedicated to a channel header
final ChannelHeaderThemeData channelHeaderTheme; final StreamChannelHeaderThemeData channelHeaderTheme;
/// The default style for [GalleryHeader]s below the overall /// The default style for [StreamGalleryHeader]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
final GalleryHeaderThemeData galleryHeaderTheme; final StreamGalleryHeaderThemeData galleryHeaderTheme;
/// The default style for [GalleryFooter]s below the overall /// The default style for [StreamGalleryFooter]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
final GalleryFooterThemeData galleryFooterTheme; final StreamGalleryFooterThemeData galleryFooterTheme;
/// Theme of the current user messages /// Theme of the current user messages
final MessageThemeData ownMessageTheme; final StreamMessageThemeData ownMessageTheme;
/// Theme of other users messages /// Theme of other users messages
final MessageThemeData otherMessageTheme; final StreamMessageThemeData otherMessageTheme;
/// Theme dedicated to the [MessageInput] widget /// Theme dedicated to the [StreamMessageInput] widget
final MessageInputThemeData messageInputTheme; final StreamMessageInputThemeData messageInputTheme;
/// The widget that will be built when the user image is unavailable /// The widget that will be built when the user image is unavailable
final Widget Function(BuildContext, User) defaultUserImage; final Widget Function(BuildContext, User) defaultUserImage;
@@ -403,41 +403,41 @@ class StreamChatThemeData {
final IconThemeData primaryIconTheme; final IconThemeData primaryIconTheme;
/// Assets used for rendering reactions /// Assets used for rendering reactions
final List<ReactionIcon> reactionIcons; final List<StreamReactionIcon> reactionIcons;
/// Theme configuration for the [MessageListView] widget. /// Theme configuration for the [StreamMessageListView] widget.
final MessageListViewThemeData messageListViewTheme; final StreamMessageListViewThemeData messageListViewTheme;
/// Theme configuration for the [ChannelListView] widget. /// Theme configuration for the [StreamChannelListView] widget.
final ChannelListViewThemeData channelListViewTheme; final StreamChannelListViewThemeData channelListViewTheme;
/// Theme configuration for the [UserListView] widget. /// Theme configuration for the [StreamUserListView] widget.
final UserListViewThemeData userListViewTheme; final StreamUserListViewThemeData userListViewTheme;
/// Theme configuration for the [MessageSearchListView] widget. /// Theme configuration for the [StreamMessageSearchListView] widget.
final MessageSearchListViewThemeData messageSearchListViewTheme; final StreamMessageSearchListViewThemeData messageSearchListViewTheme;
/// Creates a copy of [StreamChatThemeData] with specified attributes /// Creates a copy of [StreamChatThemeData] with specified attributes
/// overridden. /// overridden.
StreamChatThemeData copyWith({ StreamChatThemeData copyWith({
TextTheme? textTheme, StreamTextTheme? textTheme,
ColorTheme? colorTheme, StreamColorTheme? colorTheme,
ChannelPreviewThemeData? channelPreviewTheme, StreamChannelPreviewThemeData? channelPreviewTheme,
ChannelHeaderThemeData? channelHeaderTheme, StreamChannelHeaderThemeData? channelHeaderTheme,
MessageThemeData? ownMessageTheme, StreamMessageThemeData? ownMessageTheme,
MessageThemeData? otherMessageTheme, StreamMessageThemeData? otherMessageTheme,
MessageInputThemeData? messageInputTheme, StreamMessageInputThemeData? messageInputTheme,
Widget Function(BuildContext, User)? defaultUserImage, Widget Function(BuildContext, User)? defaultUserImage,
Widget Function(BuildContext, User)? placeholderUserImage, Widget Function(BuildContext, User)? placeholderUserImage,
IconThemeData? primaryIconTheme, IconThemeData? primaryIconTheme,
ChannelListHeaderThemeData? channelListHeaderTheme, StreamChannelListHeaderThemeData? channelListHeaderTheme,
List<ReactionIcon>? reactionIcons, List<StreamReactionIcon>? reactionIcons,
GalleryHeaderThemeData? galleryHeaderTheme, StreamGalleryHeaderThemeData? galleryHeaderTheme,
GalleryFooterThemeData? galleryFooterTheme, StreamGalleryFooterThemeData? galleryFooterTheme,
MessageListViewThemeData? messageListViewTheme, StreamMessageListViewThemeData? messageListViewTheme,
ChannelListViewThemeData? channelListViewTheme, StreamChannelListViewThemeData? channelListViewTheme,
UserListViewThemeData? userListViewTheme, StreamUserListViewThemeData? userListViewTheme,
MessageSearchListViewThemeData? messageSearchListViewTheme, StreamMessageSearchListViewThemeData? messageSearchListViewTheme,
}) => }) =>
StreamChatThemeData.raw( StreamChatThemeData.raw(
channelListHeaderTheme: channelListHeaderTheme:
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// It shows a date divider depending on the date difference /// {@macro system_message}
class SystemMessage extends StatelessWidget { @Deprecated("Use 'StreamSystemMessage' instead")
/// Constructor for creating a [SystemMessage] typedef SystemMessage = StreamSystemMessage;
const SystemMessage({
/// {@template system_message}
/// It shows a widget for the message with a system message type.
/// {@endtemplate}
class StreamSystemMessage extends StatelessWidget {
/// Constructor for creating a [StreamSystemMessage]
const StreamSystemMessage({
Key? key, Key? key,
required this.message, required this.message,
this.onMessageTap, this.onMessageTap,
@@ -1,11 +1,17 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// {@macro avatar_theme_data}
@Deprecated("Use 'StreamAvatarThemeData' instead")
typedef AvatarThemeData = StreamAvatarThemeData;
/// {@template avatar_theme_data}
/// A style that overrides the default appearance of various avatar widgets. /// A style that overrides the default appearance of various avatar widgets.
/// {@endtemplate}
// ignore: prefer-match-file-name // ignore: prefer-match-file-name
class AvatarThemeData with Diagnosticable { class StreamAvatarThemeData with Diagnosticable {
/// Creates an [AvatarThemeData]. /// Creates an [StreamAvatarThemeData].
const AvatarThemeData({ const StreamAvatarThemeData({
BoxConstraints? constraints, BoxConstraints? constraints,
BorderRadius? borderRadius, BorderRadius? borderRadius,
}) : _constraints = constraints, }) : _constraints = constraints,
@@ -25,12 +31,12 @@ class AvatarThemeData with Diagnosticable {
/// Get border radius /// Get border radius
BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20);
/// Copy this [AvatarThemeData] to another. /// Copy this [StreamAvatarThemeData] to another.
AvatarThemeData copyWith({ StreamAvatarThemeData copyWith({
BoxConstraints? constraints, BoxConstraints? constraints,
BorderRadius? borderRadius, BorderRadius? borderRadius,
}) => }) =>
AvatarThemeData( StreamAvatarThemeData(
constraints: constraints ?? _constraints, constraints: constraints ?? _constraints,
borderRadius: borderRadius ?? _borderRadius, borderRadius: borderRadius ?? _borderRadius,
); );
@@ -38,12 +44,12 @@ class AvatarThemeData with Diagnosticable {
/// Linearly interpolate between two [UserAvatar] themes. /// Linearly interpolate between two [UserAvatar] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
AvatarThemeData lerp( StreamAvatarThemeData lerp(
AvatarThemeData a, StreamAvatarThemeData a,
AvatarThemeData b, StreamAvatarThemeData b,
double t, double t,
) => ) =>
AvatarThemeData( StreamAvatarThemeData(
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t), borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
constraints: BoxConstraints.lerp(a.constraints, b.constraints, t), constraints: BoxConstraints.lerp(a.constraints, b.constraints, t),
); );
@@ -51,7 +57,7 @@ class AvatarThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is AvatarThemeData && other is StreamAvatarThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
_constraints == other._constraints && _constraints == other._constraints &&
_borderRadius == other._borderRadius; _borderRadius == other._borderRadius;
@@ -59,8 +65,8 @@ class AvatarThemeData with Diagnosticable {
@override @override
int get hashCode => _constraints.hashCode ^ _borderRadius.hashCode; int get hashCode => _constraints.hashCode ^ _borderRadius.hashCode;
/// Merges one [AvatarThemeData] with the another /// Merges one [StreamAvatarThemeData] with the another
AvatarThemeData merge(AvatarThemeData? other) { StreamAvatarThemeData merge(StreamAvatarThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
constraints: other._constraints, constraints: other._constraints,
@@ -4,27 +4,33 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/theme/themes.dart';
/// {@macro channel_header_theme}
@Deprecated("Use 'StreamChannelHeaderTheme' instead")
typedef ChannelHeaderTheme = StreamChannelHeaderTheme;
/// {@template channel_header_theme}
/// Overrides the default style of [ChannelHeader] descendants. /// Overrides the default style of [ChannelHeader] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelHeaderThemeData], which is used to configure this theme. /// * [StreamChannelHeaderThemeData], which is used to configure this theme.
class ChannelHeaderTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [ChannelHeaderTheme]. class StreamChannelHeaderTheme extends InheritedTheme {
/// Creates a [StreamChannelHeaderTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const ChannelHeaderTheme({ const StreamChannelHeaderTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final ChannelHeaderThemeData data; final StreamChannelHeaderThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [ChannelHeaderTheme] widget, then /// If there is no enclosing [StreamChannelHeaderTheme] widget, then
/// [StreamChatThemeData.channelTheme.channelHeaderTheme] is used. /// [StreamChatThemeData.channelTheme.channelHeaderTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -32,34 +38,40 @@ class ChannelHeaderTheme extends InheritedTheme {
/// ```dart /// ```dart
/// final theme = ChannelHeaderTheme.of(context); /// final theme = ChannelHeaderTheme.of(context);
/// ``` /// ```
static ChannelHeaderThemeData of(BuildContext context) { static StreamChannelHeaderThemeData of(BuildContext context) {
final channelHeaderTheme = final channelHeaderTheme =
context.dependOnInheritedWidgetOfExactType<ChannelHeaderTheme>(); context.dependOnInheritedWidgetOfExactType<StreamChannelHeaderTheme>();
return channelHeaderTheme?.data ?? return channelHeaderTheme?.data ??
StreamChatTheme.of(context).channelHeaderTheme; StreamChatTheme.of(context).channelHeaderTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
ChannelHeaderTheme(data: data, child: child); StreamChannelHeaderTheme(data: data, child: child);
@override @override
bool updateShouldNotify(ChannelHeaderTheme oldWidget) => bool updateShouldNotify(StreamChannelHeaderTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro channel_header_theme_data}
@Deprecated("Use 'StreamChannelHeaderThemeData' instead")
typedef ChannelHeaderThemeData = StreamChannelHeaderThemeData;
/// {@template channel_header_theme_data}
/// A style that overrides the default appearance of [ChannelHeader]s when used /// A style that overrides the default appearance of [ChannelHeader]s when used
/// with [ChannelHeaderTheme] or with the overall [StreamChatTheme]'s /// with [StreamChannelHeaderTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.channelHeaderTheme]. /// [StreamChatThemeData.channelHeaderTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelHeaderTheme], the theme which is configured with this class. /// * [StreamChannelHeaderTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.channelHeaderTheme], which can be used to override /// * [StreamChatThemeData.channelHeaderTheme], which can be used to override
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme]. /// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
class ChannelHeaderThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [ChannelHeaderThemeData] class StreamChannelHeaderThemeData with Diagnosticable {
const ChannelHeaderThemeData({ /// Creates a [StreamChannelHeaderThemeData]
const StreamChannelHeaderThemeData({
this.titleStyle, this.titleStyle,
this.subtitleStyle, this.subtitleStyle,
this.avatarTheme, this.avatarTheme,
@@ -73,43 +85,43 @@ class ChannelHeaderThemeData with Diagnosticable {
final TextStyle? subtitleStyle; final TextStyle? subtitleStyle;
/// Theme for avatar /// Theme for avatar
final AvatarThemeData? avatarTheme; final StreamAvatarThemeData? avatarTheme;
/// Color for [ChannelHeaderThemeData] /// Color for [StreamChannelHeaderThemeData]
final Color? color; final Color? color;
/// Copy with theme /// Copy with theme
ChannelHeaderThemeData copyWith({ StreamChannelHeaderThemeData copyWith({
TextStyle? titleStyle, TextStyle? titleStyle,
TextStyle? subtitleStyle, TextStyle? subtitleStyle,
AvatarThemeData? avatarTheme, StreamAvatarThemeData? avatarTheme,
Color? color, Color? color,
}) => }) =>
ChannelHeaderThemeData( StreamChannelHeaderThemeData(
titleStyle: titleStyle ?? this.titleStyle, titleStyle: titleStyle ?? this.titleStyle,
subtitleStyle: subtitleStyle ?? this.subtitleStyle, subtitleStyle: subtitleStyle ?? this.subtitleStyle,
avatarTheme: avatarTheme ?? this.avatarTheme, avatarTheme: avatarTheme ?? this.avatarTheme,
color: color ?? this.color, color: color ?? this.color,
); );
/// Linearly interpolate between two [ChannelHeaderThemeData]. /// Linearly interpolate between two [StreamChannelHeaderThemeData].
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
ChannelHeaderThemeData lerp( StreamChannelHeaderThemeData lerp(
ChannelHeaderThemeData a, StreamChannelHeaderThemeData a,
ChannelHeaderThemeData b, StreamChannelHeaderThemeData b,
double t, double t,
) => ) =>
ChannelHeaderThemeData( StreamChannelHeaderThemeData(
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t), titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t), subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
avatarTheme: avatarTheme: const StreamAvatarThemeData()
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t), .lerp(a.avatarTheme!, b.avatarTheme!, t),
color: Color.lerp(a.color, b.color, t), color: Color.lerp(a.color, b.color, t),
); );
/// Merge with other [ChannelHeaderThemeData] /// Merge with other [StreamChannelHeaderThemeData]
ChannelHeaderThemeData merge(ChannelHeaderThemeData? other) { StreamChannelHeaderThemeData merge(StreamChannelHeaderThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
@@ -123,7 +135,7 @@ class ChannelHeaderThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is ChannelHeaderThemeData && other is StreamChannelHeaderThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
titleStyle == other.titleStyle && titleStyle == other.titleStyle &&
subtitleStyle == other.subtitleStyle && subtitleStyle == other.subtitleStyle &&
@@ -3,27 +3,33 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
/// {@macro channel_list_header_theme}
@Deprecated("Use 'StreamChannelListHeaderTheme' instead")
typedef ChannelListHeaderTheme = StreamChannelListHeaderTheme;
/// {@template channel_list_header_theme}
/// Overrides the default style of [ChannelListHeader] descendants. /// Overrides the default style of [ChannelListHeader] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelListHeaderThemeData], which is used to configure this theme. /// * [StreamChannelListHeaderThemeData], which is used to configure this theme.
class ChannelListHeaderTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [ChannelListHeaderTheme]. class StreamChannelListHeaderTheme extends InheritedTheme {
/// Creates a [StreamChannelListHeaderTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const ChannelListHeaderTheme({ const StreamChannelListHeaderTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final ChannelListHeaderThemeData data; final StreamChannelListHeaderThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [ChannelListHeaderTheme] widget, then /// If there is no enclosing [StreamChannelListHeaderTheme] widget, then
/// [StreamChatThemeData.channelListHeaderTheme] is used. /// [StreamChatThemeData.channelListHeaderTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -31,26 +37,32 @@ class ChannelListHeaderTheme extends InheritedTheme {
/// ```dart /// ```dart
/// final theme = ChannelListHeaderTheme.of(context); /// final theme = ChannelListHeaderTheme.of(context);
/// ``` /// ```
static ChannelListHeaderThemeData of(BuildContext context) { static StreamChannelListHeaderThemeData of(BuildContext context) {
final channelListHeaderTheme = final channelListHeaderTheme = context
context.dependOnInheritedWidgetOfExactType<ChannelListHeaderTheme>(); .dependOnInheritedWidgetOfExactType<StreamChannelListHeaderTheme>();
return channelListHeaderTheme?.data ?? return channelListHeaderTheme?.data ??
StreamChatTheme.of(context).channelListHeaderTheme; StreamChatTheme.of(context).channelListHeaderTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
ChannelListHeaderTheme(data: data, child: child); StreamChannelListHeaderTheme(data: data, child: child);
@override @override
bool updateShouldNotify(ChannelListHeaderTheme oldWidget) => bool updateShouldNotify(StreamChannelListHeaderTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro channel_list_header_theme_data}
@Deprecated("Use ''StreamChannelListHeaderThemeData' instead")
typedef ChannelListHeaderThemeData = StreamChannelListHeaderThemeData;
/// {@template channel_list_header_theme_data}
/// Theme dedicated to the [ChannelListHeader] /// Theme dedicated to the [ChannelListHeader]
class ChannelListHeaderThemeData with Diagnosticable { /// {@endtemplate}
/// Returns a new [ChannelListHeaderThemeData] class StreamChannelListHeaderThemeData with Diagnosticable {
const ChannelListHeaderThemeData({ /// Returns a new [StreamChannelListHeaderThemeData]
const StreamChannelListHeaderThemeData({
this.titleStyle, this.titleStyle,
this.avatarTheme, this.avatarTheme,
this.color, this.color,
@@ -60,39 +72,41 @@ class ChannelListHeaderThemeData with Diagnosticable {
final TextStyle? titleStyle; final TextStyle? titleStyle;
/// Theme dedicated to the userAvatar /// Theme dedicated to the userAvatar
final AvatarThemeData? avatarTheme; final StreamAvatarThemeData? avatarTheme;
/// Background color of the appbar /// Background color of the appbar
final Color? color; final Color? color;
/// Returns a new [ChannelListHeaderThemeData] replacing some of its /// Returns a new [StreamChannelListHeaderThemeData] replacing some of its
/// properties /// properties
ChannelListHeaderThemeData copyWith({ StreamChannelListHeaderThemeData copyWith({
TextStyle? titleStyle, TextStyle? titleStyle,
AvatarThemeData? avatarTheme, StreamAvatarThemeData? avatarTheme,
Color? color, Color? color,
}) => }) =>
ChannelListHeaderThemeData( StreamChannelListHeaderThemeData(
titleStyle: titleStyle ?? this.titleStyle, titleStyle: titleStyle ?? this.titleStyle,
avatarTheme: avatarTheme ?? this.avatarTheme, avatarTheme: avatarTheme ?? this.avatarTheme,
color: color ?? this.color, color: color ?? this.color,
); );
/// Linearly interpolate from one [ChannelListHeaderThemeData] to another. /// Linearly interpolate from one [StreamChannelListHeaderThemeData] to another.
ChannelListHeaderThemeData lerp( StreamChannelListHeaderThemeData lerp(
ChannelListHeaderThemeData a, StreamChannelListHeaderThemeData a,
ChannelListHeaderThemeData b, StreamChannelListHeaderThemeData b,
double t, double t,
) => ) =>
ChannelListHeaderThemeData( StreamChannelListHeaderThemeData(
avatarTheme: avatarTheme: const StreamAvatarThemeData()
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t), .lerp(a.avatarTheme!, b.avatarTheme!, t),
color: Color.lerp(a.color, b.color, t), color: Color.lerp(a.color, b.color, t),
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t), titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
); );
/// Merges [this] [ChannelListHeaderThemeData] with the [other] /// Merges [this] [StreamChannelListHeaderThemeData] with the [other]
ChannelListHeaderThemeData merge(ChannelListHeaderThemeData? other) { StreamChannelListHeaderThemeData merge(
StreamChannelListHeaderThemeData? other,
) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
@@ -104,7 +118,7 @@ class ChannelListHeaderThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is ChannelListHeaderThemeData && other is StreamChannelListHeaderThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
titleStyle == other.titleStyle && titleStyle == other.titleStyle &&
avatarTheme == other.avatarTheme && avatarTheme == other.avatarTheme &&
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro channel_list_view_theme}
@Deprecated("Use 'StreamChannelListViewTheme' instead")
typedef ChannelListViewTheme = StreamChannelListViewTheme;
/// {@template channel_list_view_theme}
/// Overrides the default style of [ChannelListView] descendants. /// Overrides the default style of [ChannelListView] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelListViewThemeData], which is used to configure this theme. /// * [StreamChannelListViewThemeData], which is used to configure this theme.
class ChannelListViewTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [ChannelListViewTheme]. class StreamChannelListViewTheme extends InheritedTheme {
/// Creates a [StreamChannelListViewTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const ChannelListViewTheme({ const StreamChannelListViewTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final ChannelListViewThemeData data; final StreamChannelListViewThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [ChannelListViewTheme] widget, then /// If there is no enclosing [StreamChannelListViewTheme] widget, then
/// [StreamChatThemeData.channelListViewTheme] is used. /// [StreamChatThemeData.channelListViewTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -30,63 +36,69 @@ class ChannelListViewTheme extends InheritedTheme {
/// ```dart /// ```dart
/// ChannelListViewTheme theme = ChannelListViewTheme.of(context); /// ChannelListViewTheme theme = ChannelListViewTheme.of(context);
/// ``` /// ```
static ChannelListViewThemeData of(BuildContext context) { static StreamChannelListViewThemeData of(BuildContext context) {
final channelListViewTheme = final channelListViewTheme = context
context.dependOnInheritedWidgetOfExactType<ChannelListViewTheme>(); .dependOnInheritedWidgetOfExactType<StreamChannelListViewTheme>();
return channelListViewTheme?.data ?? return channelListViewTheme?.data ??
StreamChatTheme.of(context).channelListViewTheme; StreamChatTheme.of(context).channelListViewTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
ChannelListViewTheme(data: data, child: child); StreamChannelListViewTheme(data: data, child: child);
@override @override
bool updateShouldNotify(ChannelListViewTheme oldWidget) => bool updateShouldNotify(StreamChannelListViewTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro channel_list_view_theme_data}
@Deprecated("Use 'StreamChannelListViewThemeData' instead")
typedef ChannelListViewThemeData = StreamChannelListViewThemeData;
/// {@template channel_list_view_theme_data}
/// A style that overrides the default appearance of [ChannelListView]s when /// A style that overrides the default appearance of [ChannelListView]s when
/// used with [ChannelListViewTheme] or with the overall [StreamChatTheme]'s /// used with [StreamChannelListViewTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.channelListViewTheme]. /// [StreamChatThemeData.channelListViewTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelListViewTheme], the theme which is configured with this class. /// * [StreamChannelListViewTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.channelListViewTheme], which can be used to override /// * [StreamChatThemeData.channelListViewTheme], which can be used to override
/// the default style for [ChannelListView]s below the overall /// the default style for [ChannelListView]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
class ChannelListViewThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [ChannelListViewThemeData]. class StreamChannelListViewThemeData with Diagnosticable {
const ChannelListViewThemeData({ /// Creates a [StreamChannelListViewThemeData].
const StreamChannelListViewThemeData({
this.backgroundColor, this.backgroundColor,
}); });
/// The color of the [ChannelListView] background. /// The color of the [ChannelListView] background.
final Color? backgroundColor; final Color? backgroundColor;
/// Copies this [ChannelListViewThemeData] to another. /// Copies this [StreamChannelListViewThemeData] to another.
ChannelListViewThemeData copyWith({ StreamChannelListViewThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
}) => }) =>
ChannelListViewThemeData( StreamChannelListViewThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
); );
/// Linearly interpolate between two [ChannelListViewThemeData] themes. /// Linearly interpolate between two [StreamChannelListViewThemeData] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
ChannelListViewThemeData lerp( StreamChannelListViewThemeData lerp(
ChannelListViewThemeData a, StreamChannelListViewThemeData a,
ChannelListViewThemeData b, StreamChannelListViewThemeData b,
double t, double t,
) => ) =>
ChannelListViewThemeData( StreamChannelListViewThemeData(
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
); );
/// Merges one [ChannelListViewThemeData] with another. /// Merges one [StreamChannelListViewThemeData] with another.
ChannelListViewThemeData merge(ChannelListViewThemeData? other) { StreamChannelListViewThemeData merge(StreamChannelListViewThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
backgroundColor: other.backgroundColor, backgroundColor: other.backgroundColor,
@@ -96,7 +108,7 @@ class ChannelListViewThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is ChannelListViewThemeData && other is StreamChannelListViewThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor; backgroundColor == other.backgroundColor;
@@ -3,27 +3,33 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
/// {@macro channel_preview_theme}
@Deprecated("Use 'StreamChannelPreviewTheme' instead")
typedef ChannelPreviewTheme = StreamChannelPreviewTheme;
/// {@template channel_preview_theme}
/// Overrides the default style of [ChannelPreview] descendants. /// Overrides the default style of [ChannelPreview] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelPreviewThemeData], which is used to configure this theme. /// * [StreamChannelPreviewThemeData], which is used to configure this theme.
class ChannelPreviewTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [ChannelPreviewTheme]. class StreamChannelPreviewTheme extends InheritedTheme {
/// Creates a [StreamChannelPreviewTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const ChannelPreviewTheme({ const StreamChannelPreviewTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final ChannelPreviewThemeData data; final StreamChannelPreviewThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [ChannelPreviewTheme] widget, then /// If there is no enclosing [StreamChannelPreviewTheme] widget, then
/// [StreamChatThemeData.channelPreviewTheme] is used. /// [StreamChatThemeData.channelPreviewTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -31,34 +37,40 @@ class ChannelPreviewTheme extends InheritedTheme {
/// ```dart /// ```dart
/// final theme = ChannelPreviewTheme.of(context); /// final theme = ChannelPreviewTheme.of(context);
/// ``` /// ```
static ChannelPreviewThemeData of(BuildContext context) { static StreamChannelPreviewThemeData of(BuildContext context) {
final channelPreviewTheme = final channelPreviewTheme =
context.dependOnInheritedWidgetOfExactType<ChannelPreviewTheme>(); context.dependOnInheritedWidgetOfExactType<StreamChannelPreviewTheme>();
return channelPreviewTheme?.data ?? return channelPreviewTheme?.data ??
StreamChatTheme.of(context).channelPreviewTheme; StreamChatTheme.of(context).channelPreviewTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
ChannelPreviewTheme(data: data, child: child); StreamChannelPreviewTheme(data: data, child: child);
@override @override
bool updateShouldNotify(ChannelPreviewTheme oldWidget) => bool updateShouldNotify(StreamChannelPreviewTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro channel_preview_theme_data}
@Deprecated("Use 'StreamChannelPreviewThemeData' instead")
typedef ChannelPreviewThemeData = StreamChannelPreviewThemeData;
/// {@template channel_preview_theme_data}
/// A style that overrides the default appearance of [ChannelPreview]s when used /// A style that overrides the default appearance of [ChannelPreview]s when used
/// with [ChannelPreviewTheme] or with the overall [StreamChatTheme]'s /// with [StreamChannelPreviewTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.channelPreviewTheme]. /// [StreamChatThemeData.channelPreviewTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [ChannelPreviewTheme], the theme which is configured with this class. /// * [StreamChannelPreviewTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.channelPreviewTheme], which can be used to override /// * [StreamChatThemeData.channelPreviewTheme], which can be used to override
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme]. /// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
class ChannelPreviewThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [ChannelPreviewThemeData]. class StreamChannelPreviewThemeData with Diagnosticable {
const ChannelPreviewThemeData({ /// Creates a [StreamChannelPreviewThemeData].
const StreamChannelPreviewThemeData({
this.titleStyle, this.titleStyle,
this.subtitleStyle, this.subtitleStyle,
this.lastMessageAtStyle, this.lastMessageAtStyle,
@@ -77,7 +89,7 @@ class ChannelPreviewThemeData with Diagnosticable {
final TextStyle? lastMessageAtStyle; final TextStyle? lastMessageAtStyle;
/// Avatar theme /// Avatar theme
final AvatarThemeData? avatarTheme; final StreamAvatarThemeData? avatarTheme;
/// Unread counter color /// Unread counter color
final Color? unreadCounterColor; final Color? unreadCounterColor;
@@ -86,15 +98,15 @@ class ChannelPreviewThemeData with Diagnosticable {
final double? indicatorIconSize; final double? indicatorIconSize;
/// Copy with theme /// Copy with theme
ChannelPreviewThemeData copyWith({ StreamChannelPreviewThemeData copyWith({
TextStyle? titleStyle, TextStyle? titleStyle,
TextStyle? subtitleStyle, TextStyle? subtitleStyle,
TextStyle? lastMessageAtStyle, TextStyle? lastMessageAtStyle,
AvatarThemeData? avatarTheme, StreamAvatarThemeData? avatarTheme,
Color? unreadCounterColor, Color? unreadCounterColor,
double? indicatorIconSize, double? indicatorIconSize,
}) => }) =>
ChannelPreviewThemeData( StreamChannelPreviewThemeData(
titleStyle: titleStyle ?? this.titleStyle, titleStyle: titleStyle ?? this.titleStyle,
subtitleStyle: subtitleStyle ?? this.subtitleStyle, subtitleStyle: subtitleStyle ?? this.subtitleStyle,
lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle, lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle,
@@ -103,15 +115,15 @@ class ChannelPreviewThemeData with Diagnosticable {
indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize,
); );
/// Linearly interpolate one [ChannelPreviewThemeData] to another. /// Linearly interpolate one [StreamChannelPreviewThemeData] to another.
ChannelPreviewThemeData lerp( StreamChannelPreviewThemeData lerp(
ChannelPreviewThemeData a, StreamChannelPreviewThemeData a,
ChannelPreviewThemeData b, StreamChannelPreviewThemeData b,
double t, double t,
) => ) =>
ChannelPreviewThemeData( StreamChannelPreviewThemeData(
avatarTheme: avatarTheme: const StreamAvatarThemeData()
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t), .lerp(a.avatarTheme!, b.avatarTheme!, t),
indicatorIconSize: a.indicatorIconSize, indicatorIconSize: a.indicatorIconSize,
lastMessageAtStyle: lastMessageAtStyle:
TextStyle.lerp(a.lastMessageAtStyle, b.lastMessageAtStyle, t), TextStyle.lerp(a.lastMessageAtStyle, b.lastMessageAtStyle, t),
@@ -122,7 +134,7 @@ class ChannelPreviewThemeData with Diagnosticable {
); );
/// Merge with theme /// Merge with theme
ChannelPreviewThemeData merge(ChannelPreviewThemeData? other) { StreamChannelPreviewThemeData merge(StreamChannelPreviewThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
@@ -138,7 +150,7 @@ class ChannelPreviewThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is ChannelPreviewThemeData && other is StreamChannelPreviewThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
titleStyle == other.titleStyle && titleStyle == other.titleStyle &&
subtitleStyle == other.subtitleStyle && subtitleStyle == other.subtitleStyle &&
@@ -1,9 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// {@macro color_theme}
@Deprecated("Use 'StreamColorTheme' instead")
typedef ColorTheme = StreamColorTheme;
/// {@template color_theme}
/// Theme that holds colors /// Theme that holds colors
class ColorTheme { /// {@endtemplate}
class StreamColorTheme {
/// Initialise with light theme /// Initialise with light theme
ColorTheme.light({ StreamColorTheme.light({
this.textHighEmphasis = const Color(0xff000000), this.textHighEmphasis = const Color(0xff000000),
this.textLowEmphasis = const Color(0xff7a7a7a), this.textLowEmphasis = const Color(0xff7a7a7a),
this.disabled = const Color(0xffdbdbdb), this.disabled = const Color(0xffdbdbdb),
@@ -55,7 +61,7 @@ class ColorTheme {
}) : brightness = Brightness.light; }) : brightness = Brightness.light;
/// Initialise with dark theme /// Initialise with dark theme
ColorTheme.dark({ StreamColorTheme.dark({
this.textHighEmphasis = const Color(0xffffffff), this.textHighEmphasis = const Color(0xffffffff),
this.textLowEmphasis = const Color(0xff7a7a7a), this.textLowEmphasis = const Color(0xff7a7a7a),
this.disabled = const Color(0xff2d2f2f), this.disabled = const Color(0xff2d2f2f),
@@ -169,7 +175,7 @@ class ColorTheme {
final Brightness brightness; final Brightness brightness;
/// Copy with theme /// Copy with theme
ColorTheme copyWith({ StreamColorTheme copyWith({
Brightness brightness = Brightness.light, Brightness brightness = Brightness.light,
Color? textHighEmphasis, Color? textHighEmphasis,
Color? textLowEmphasis, Color? textLowEmphasis,
@@ -192,7 +198,7 @@ class ColorTheme {
Gradient? bgGradient, Gradient? bgGradient,
}) => }) =>
brightness == Brightness.light brightness == Brightness.light
? ColorTheme.light( ? StreamColorTheme.light(
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis, textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis, textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
disabled: disabled ?? this.disabled, disabled: disabled ?? this.disabled,
@@ -213,7 +219,7 @@ class ColorTheme {
overlayDark: overlayDark ?? this.overlayDark, overlayDark: overlayDark ?? this.overlayDark,
bgGradient: bgGradient ?? this.bgGradient, bgGradient: bgGradient ?? this.bgGradient,
) )
: ColorTheme.dark( : StreamColorTheme.dark(
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis, textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis, textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
disabled: disabled ?? this.disabled, disabled: disabled ?? this.disabled,
@@ -236,7 +242,7 @@ class ColorTheme {
); );
/// Merge color theme /// Merge color theme
ColorTheme merge(ColorTheme? other) { StreamColorTheme merge(StreamColorTheme? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
textHighEmphasis: other.textHighEmphasis, textHighEmphasis: other.textHighEmphasis,
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro gallery_footer_theme}
@Deprecated("Use 'StreamGalleryFooterTheme' instead")
typedef GalleryFooterTheme = StreamGalleryFooterTheme;
/// {@template gallery_footer_theme}
/// Overrides the default style of [GalleryFooter] descendants. /// Overrides the default style of [GalleryFooter] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [GalleryFooterThemeData], which is used to configure this theme. /// * [StreamGalleryFooterThemeData], which is used to configure this theme.
class GalleryFooterTheme extends InheritedTheme { /// {@endtemplate}
/// Creates an [GalleryFooterTheme]. class StreamGalleryFooterTheme extends InheritedTheme {
/// Creates an [StreamGalleryFooterTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const GalleryFooterTheme({ const StreamGalleryFooterTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final GalleryFooterThemeData data; final StreamGalleryFooterThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [GalleryFooterTheme] widget, then /// If there is no enclosing [StreamGalleryFooterTheme] widget, then
/// [StreamChatThemeData.galleryFooterTheme] is used. /// [StreamChatThemeData.galleryFooterTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -30,34 +36,40 @@ class GalleryFooterTheme extends InheritedTheme {
/// ```dart /// ```dart
/// ImageFooterTheme theme = ImageFooterTheme.of(context); /// ImageFooterTheme theme = ImageFooterTheme.of(context);
/// ``` /// ```
static GalleryFooterThemeData of(BuildContext context) { static StreamGalleryFooterThemeData of(BuildContext context) {
final imageFooterTheme = final imageFooterTheme =
context.dependOnInheritedWidgetOfExactType<GalleryFooterTheme>(); context.dependOnInheritedWidgetOfExactType<StreamGalleryFooterTheme>();
return imageFooterTheme?.data ?? return imageFooterTheme?.data ??
StreamChatTheme.of(context).galleryFooterTheme; StreamChatTheme.of(context).galleryFooterTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
GalleryFooterTheme(data: data, child: child); StreamGalleryFooterTheme(data: data, child: child);
@override @override
bool updateShouldNotify(GalleryFooterTheme oldWidget) => bool updateShouldNotify(StreamGalleryFooterTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro gallery_footer_theme_data}
@Deprecated("Use 'StreamGalleryFooterThemeData' instead")
typedef GalleryFooterThemeData = StreamGalleryFooterThemeData;
/// {@template gallery_footer_theme_data}
/// A style that overrides the default appearance of [GalleryFooter]s when used /// A style that overrides the default appearance of [GalleryFooter]s when used
/// with [GalleryFooterTheme] or with the overall [StreamChatTheme]'s /// with [StreamGalleryFooterTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.galleryFooterTheme]. /// [StreamChatThemeData.galleryFooterTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [GalleryFooterTheme], the theme which is configured with this class. /// * [StreamGalleryFooterTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.galleryFooterTheme], which can be used to override /// * [StreamChatThemeData.galleryFooterTheme], which can be used to override
/// the default style for [GalleryFooter]s below the overall [StreamChatTheme]. /// the default style for [GalleryFooter]s below the overall [StreamChatTheme].
class GalleryFooterThemeData with Diagnosticable { /// {@endtemplate}
/// Creates an [GalleryFooterThemeData]. class StreamGalleryFooterThemeData with Diagnosticable {
const GalleryFooterThemeData({ /// Creates an [StreamGalleryFooterThemeData].
const StreamGalleryFooterThemeData({
this.backgroundColor, this.backgroundColor,
this.shareIconColor, this.shareIconColor,
this.titleTextStyle, this.titleTextStyle,
@@ -108,8 +120,8 @@ class GalleryFooterThemeData with Diagnosticable {
/// Defaults to [ColorTheme.textHighEmphasis]. /// Defaults to [ColorTheme.textHighEmphasis].
final Color? bottomSheetCloseIconColor; final Color? bottomSheetCloseIconColor;
/// Copies this [GalleryFooterThemeData] to another. /// Copies this [StreamGalleryFooterThemeData] to another.
GalleryFooterThemeData copyWith({ StreamGalleryFooterThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
Color? shareIconColor, Color? shareIconColor,
TextStyle? titleTextStyle, TextStyle? titleTextStyle,
@@ -119,7 +131,7 @@ class GalleryFooterThemeData with Diagnosticable {
TextStyle? bottomSheetPhotosTextStyle, TextStyle? bottomSheetPhotosTextStyle,
Color? bottomSheetCloseIconColor, Color? bottomSheetCloseIconColor,
}) => }) =>
GalleryFooterThemeData( StreamGalleryFooterThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
shareIconColor: shareIconColor ?? this.shareIconColor, shareIconColor: shareIconColor ?? this.shareIconColor,
titleTextStyle: titleTextStyle ?? this.titleTextStyle, titleTextStyle: titleTextStyle ?? this.titleTextStyle,
@@ -137,12 +149,12 @@ class GalleryFooterThemeData with Diagnosticable {
/// Linearly interpolate between two [GalleryFooter] themes. /// Linearly interpolate between two [GalleryFooter] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
GalleryFooterThemeData lerp( StreamGalleryFooterThemeData lerp(
GalleryFooterThemeData a, StreamGalleryFooterThemeData a,
GalleryFooterThemeData b, StreamGalleryFooterThemeData b,
double t, double t,
) => ) =>
GalleryFooterThemeData( StreamGalleryFooterThemeData(
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
shareIconColor: Color.lerp(a.shareIconColor, b.shareIconColor, t), shareIconColor: Color.lerp(a.shareIconColor, b.shareIconColor, t),
titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t), titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t),
@@ -167,8 +179,8 @@ class GalleryFooterThemeData with Diagnosticable {
), ),
); );
/// Merges one [GalleryFooterThemeData] with another. /// Merges one [StreamGalleryFooterThemeData] with another.
GalleryFooterThemeData merge(GalleryFooterThemeData? other) { StreamGalleryFooterThemeData merge(StreamGalleryFooterThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
backgroundColor: other.backgroundColor, backgroundColor: other.backgroundColor,
@@ -185,7 +197,7 @@ class GalleryFooterThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is GalleryFooterThemeData && other is StreamGalleryFooterThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor && backgroundColor == other.backgroundColor &&
shareIconColor == other.shareIconColor && shareIconColor == other.shareIconColor &&
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro gallery_header_them}
@Deprecated("Use 'StreamGalleryHeaderTheme' instead")
typedef GalleryHeaderTheme = StreamGalleryHeaderTheme;
/// {@template gallery_header_theme}
/// Overrides the default style of [GalleryHeader] descendants. /// Overrides the default style of [GalleryHeader] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [GalleryHeaderThemeData], which is used to configure this theme. /// * [StreamGalleryHeaderThemeData], which is used to configure this theme.
class GalleryHeaderTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [GalleryHeaderTheme]. class StreamGalleryHeaderTheme extends InheritedTheme {
/// Creates a [StreamGalleryHeaderTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const GalleryHeaderTheme({ const StreamGalleryHeaderTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final GalleryHeaderThemeData data; final StreamGalleryHeaderThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [GalleryHeaderTheme] widget, then /// If there is no enclosing [StreamGalleryHeaderTheme] widget, then
/// [StreamChatThemeData.galleryHeaderTheme] is used. /// [StreamChatThemeData.galleryHeaderTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -30,34 +36,40 @@ class GalleryHeaderTheme extends InheritedTheme {
/// ```dart /// ```dart
/// ImageHeaderTheme theme = ImageHeaderTheme.of(context); /// ImageHeaderTheme theme = ImageHeaderTheme.of(context);
/// ``` /// ```
static GalleryHeaderThemeData of(BuildContext context) { static StreamGalleryHeaderThemeData of(BuildContext context) {
final galleryHeaderTheme = final galleryHeaderTheme =
context.dependOnInheritedWidgetOfExactType<GalleryHeaderTheme>(); context.dependOnInheritedWidgetOfExactType<StreamGalleryHeaderTheme>();
return galleryHeaderTheme?.data ?? return galleryHeaderTheme?.data ??
StreamChatTheme.of(context).galleryHeaderTheme; StreamChatTheme.of(context).galleryHeaderTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
GalleryHeaderTheme(data: data, child: child); StreamGalleryHeaderTheme(data: data, child: child);
@override @override
bool updateShouldNotify(GalleryHeaderTheme oldWidget) => bool updateShouldNotify(StreamGalleryHeaderTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro gallery_header_theme_data}
@Deprecated("Use 'StreamGalleryHeaderThemeData' instead")
typedef GalleryHeaderThemeData = StreamGalleryHeaderThemeData;
/// {@template gallery_header_theme_data}
/// A style that overrides the default appearance of [GalleryHeader]s when used /// A style that overrides the default appearance of [GalleryHeader]s when used
/// with [GalleryHeaderTheme] or with the overall [StreamChatTheme]'s /// with [StreamGalleryHeaderTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.galleryHeaderTheme]. /// [StreamChatThemeData.galleryHeaderTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [GalleryHeaderTheme], the theme which is configured with this class. /// * [StreamGalleryHeaderTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.galleryHeaderTheme], which can be used to override /// * [StreamChatThemeData.galleryHeaderTheme], which can be used to override
/// the default style for [GalleryHeader]s below the overall [StreamChatTheme]. /// the default style for [GalleryHeader]s below the overall [StreamChatTheme].
class GalleryHeaderThemeData with Diagnosticable { /// {@endtemplate}
/// Creates an [GalleryHeaderThemeData]. class StreamGalleryHeaderThemeData with Diagnosticable {
const GalleryHeaderThemeData({ /// Creates an [StreamGalleryHeaderThemeData].
const StreamGalleryHeaderThemeData({
this.closeButtonColor, this.closeButtonColor,
this.backgroundColor, this.backgroundColor,
this.iconMenuPointColor, this.iconMenuPointColor,
@@ -92,8 +104,8 @@ class GalleryHeaderThemeData with Diagnosticable {
/// ///
final Color? bottomSheetBarrierColor; final Color? bottomSheetBarrierColor;
/// Copies this [GalleryHeaderThemeData] to another. /// Copies this [StreamGalleryHeaderThemeData] to another.
GalleryHeaderThemeData copyWith({ StreamGalleryHeaderThemeData copyWith({
Color? closeButtonColor, Color? closeButtonColor,
Color? backgroundColor, Color? backgroundColor,
Color? iconMenuPointColor, Color? iconMenuPointColor,
@@ -101,7 +113,7 @@ class GalleryHeaderThemeData with Diagnosticable {
TextStyle? subtitleTextStyle, TextStyle? subtitleTextStyle,
Color? bottomSheetBarrierColor, Color? bottomSheetBarrierColor,
}) => }) =>
GalleryHeaderThemeData( StreamGalleryHeaderThemeData(
closeButtonColor: closeButtonColor ?? this.closeButtonColor, closeButtonColor: closeButtonColor ?? this.closeButtonColor,
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
iconMenuPointColor: iconMenuPointColor ?? this.iconMenuPointColor, iconMenuPointColor: iconMenuPointColor ?? this.iconMenuPointColor,
@@ -114,12 +126,12 @@ class GalleryHeaderThemeData with Diagnosticable {
/// Linearly interpolate between two [GalleryHeader] themes. /// Linearly interpolate between two [GalleryHeader] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
GalleryHeaderThemeData lerp( StreamGalleryHeaderThemeData lerp(
GalleryHeaderThemeData a, StreamGalleryHeaderThemeData a,
GalleryHeaderThemeData b, StreamGalleryHeaderThemeData b,
double t, double t,
) => ) =>
GalleryHeaderThemeData( StreamGalleryHeaderThemeData(
closeButtonColor: Color.lerp(a.closeButtonColor, b.closeButtonColor, t), closeButtonColor: Color.lerp(a.closeButtonColor, b.closeButtonColor, t),
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
iconMenuPointColor: iconMenuPointColor:
@@ -131,8 +143,8 @@ class GalleryHeaderThemeData with Diagnosticable {
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t), Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
); );
/// Merges one [GalleryHeaderThemeData] with the another /// Merges one [StreamGalleryHeaderThemeData] with the another
GalleryHeaderThemeData merge(GalleryHeaderThemeData? other) { StreamGalleryHeaderThemeData merge(StreamGalleryHeaderThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
closeButtonColor: other.closeButtonColor, closeButtonColor: other.closeButtonColor,
@@ -147,7 +159,7 @@ class GalleryHeaderThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is GalleryHeaderThemeData && other is StreamGalleryHeaderThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
closeButtonColor == other.closeButtonColor && closeButtonColor == other.closeButtonColor &&
backgroundColor == other.backgroundColor && backgroundColor == other.backgroundColor &&
@@ -5,27 +5,33 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro message_input_theme}
@Deprecated("Use 'StreamMessageInputTheme' instead")
typedef MessageInputTheme = StreamMessageInputTheme;
/// {@template message_input_theme}
/// Overrides the default style of [MessageInput] descendants. /// Overrides the default style of [MessageInput] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [MessageInputThemeData], which is used to configure this theme. /// * [StreamMessageInputThemeData], which is used to configure this theme.
class MessageInputTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [MessageInputTheme]. class StreamMessageInputTheme extends InheritedTheme {
/// Creates a [StreamMessageInputTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const MessageInputTheme({ const StreamMessageInputTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final MessageInputThemeData data; final StreamMessageInputThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [MessageInputTheme] widget, then /// If there is no enclosing [StreamMessageInputTheme] widget, then
/// [StreamChatThemeData.messageInputTheme] is used. /// [StreamChatThemeData.messageInputTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -33,28 +39,34 @@ class MessageInputTheme extends InheritedTheme {
/// ```dart /// ```dart
/// final theme = MessageInputTheme.of(context); /// final theme = MessageInputTheme.of(context);
/// ``` /// ```
static MessageInputThemeData of(BuildContext context) { static StreamMessageInputThemeData of(BuildContext context) {
final messageInputTheme = final messageInputTheme =
context.dependOnInheritedWidgetOfExactType<MessageInputTheme>(); context.dependOnInheritedWidgetOfExactType<StreamMessageInputTheme>();
return messageInputTheme?.data ?? return messageInputTheme?.data ??
StreamChatTheme.of(context).messageInputTheme; StreamChatTheme.of(context).messageInputTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
MessageInputTheme(data: data, child: child); StreamMessageInputTheme(data: data, child: child);
@override @override
bool updateShouldNotify(MessageInputTheme oldWidget) => bool updateShouldNotify(StreamMessageInputTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro message_input_theme_data}
@Deprecated("Use 'StreamMessageInputThemeData' instead")
typedef MessageInputThemeData = StreamMessageInputThemeData;
/// {@template message_input_theme_data}
/// A style that overrides the default appearance of [MessageInput] widgets /// A style that overrides the default appearance of [MessageInput] widgets
/// when used with [MessageInputTheme] or with the overall [StreamChatTheme]'s /// when used with [StreamMessageInputTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.messageInputTheme]. /// [StreamChatThemeData.messageInputTheme].
class MessageInputThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [MessageInputThemeData]. class StreamMessageInputThemeData with Diagnosticable {
const MessageInputThemeData({ /// Creates a [StreamMessageInputThemeData].
const StreamMessageInputThemeData({
this.sendAnimationDuration, this.sendAnimationDuration,
this.actionButtonColor, this.actionButtonColor,
this.sendButtonColor, this.sendButtonColor,
@@ -121,8 +133,8 @@ class MessageInputThemeData with Diagnosticable {
/// Shadow for the [MessageInput] widget /// Shadow for the [MessageInput] widget
final BoxShadow? shadow; final BoxShadow? shadow;
/// Returns a new [MessageInputThemeData] replacing some of its properties /// Returns a new [StreamMessageInputThemeData] replacing some of its properties
MessageInputThemeData copyWith({ StreamMessageInputThemeData copyWith({
Duration? sendAnimationDuration, Duration? sendAnimationDuration,
Color? inputBackgroundColor, Color? inputBackgroundColor,
Color? actionButtonColor, Color? actionButtonColor,
@@ -140,7 +152,7 @@ class MessageInputThemeData with Diagnosticable {
double? elevation, double? elevation,
BoxShadow? shadow, BoxShadow? shadow,
}) => }) =>
MessageInputThemeData( StreamMessageInputThemeData(
sendAnimationDuration: sendAnimationDuration:
sendAnimationDuration ?? this.sendAnimationDuration, sendAnimationDuration ?? this.sendAnimationDuration,
inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor, inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor,
@@ -161,13 +173,13 @@ class MessageInputThemeData with Diagnosticable {
shadow: shadow ?? this.shadow, shadow: shadow ?? this.shadow,
); );
/// Linearly interpolate from one [MessageInputThemeData] to another. /// Linearly interpolate from one [StreamMessageInputThemeData] to another.
MessageInputThemeData lerp( StreamMessageInputThemeData lerp(
MessageInputThemeData a, StreamMessageInputThemeData a,
MessageInputThemeData b, StreamMessageInputThemeData b,
double t, double t,
) => ) =>
MessageInputThemeData( StreamMessageInputThemeData(
actionButtonColor: actionButtonColor:
Color.lerp(a.actionButtonColor, b.actionButtonColor, t), Color.lerp(a.actionButtonColor, b.actionButtonColor, t),
actionButtonIdleColor: actionButtonIdleColor:
@@ -194,8 +206,8 @@ class MessageInputThemeData with Diagnosticable {
shadow: BoxShadow.lerp(a.shadow, b.shadow, t), shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
); );
/// Merges [this] [MessageInputThemeData] with the [other] /// Merges [this] [StreamMessageInputThemeData] with the [other]
MessageInputThemeData merge(MessageInputThemeData? other) { StreamMessageInputThemeData merge(StreamMessageInputThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
sendAnimationDuration: other.sendAnimationDuration, sendAnimationDuration: other.sendAnimationDuration,
@@ -222,7 +234,7 @@ class MessageInputThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is MessageInputThemeData && other is StreamMessageInputThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
sendAnimationDuration == other.sendAnimationDuration && sendAnimationDuration == other.sendAnimationDuration &&
sendButtonColor == other.sendButtonColor && sendButtonColor == other.sendButtonColor &&
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro message_list_view_theme}
@Deprecated("Use 'StreamMessageListViewTheme' instead")
typedef MessageListViewTheme = StreamMessageListViewTheme;
/// {@template message_list_view_theme}
/// Overrides the default style of [MessageListView] descendants. /// Overrides the default style of [MessageListView] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [MessageListViewThemeData], which is used to configure this theme. /// * [StreamMessageListViewThemeData], which is used to configure this theme.
class MessageListViewTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [MessageListViewTheme]. class StreamMessageListViewTheme extends InheritedTheme {
/// Creates a [StreamMessageListViewTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const MessageListViewTheme({ const StreamMessageListViewTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final MessageListViewThemeData data; final StreamMessageListViewThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [MessageListViewTheme] widget, then /// If there is no enclosing [StreamMessageListViewTheme] widget, then
/// [StreamChatThemeData.messageListViewTheme] is used. /// [StreamChatThemeData.messageListViewTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -30,35 +36,41 @@ class MessageListViewTheme extends InheritedTheme {
/// ```dart /// ```dart
/// MessageListViewTheme theme = MessageListViewTheme.of(context); /// MessageListViewTheme theme = MessageListViewTheme.of(context);
/// ``` /// ```
static MessageListViewThemeData of(BuildContext context) { static StreamMessageListViewThemeData of(BuildContext context) {
final messageListViewTheme = final messageListViewTheme = context
context.dependOnInheritedWidgetOfExactType<MessageListViewTheme>(); .dependOnInheritedWidgetOfExactType<StreamMessageListViewTheme>();
return messageListViewTheme?.data ?? return messageListViewTheme?.data ??
StreamChatTheme.of(context).messageListViewTheme; StreamChatTheme.of(context).messageListViewTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
MessageListViewTheme(data: data, child: child); StreamMessageListViewTheme(data: data, child: child);
@override @override
bool updateShouldNotify(MessageListViewTheme oldWidget) => bool updateShouldNotify(StreamMessageListViewTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro message_list_view_theme_data}
@Deprecated("Use 'StreamMessageListViewThemeData' instead")
typedef MessageListViewThemeData = StreamMessageListViewThemeData;
/// {@template message_list_view_theme_data}
/// A style that overrides the default appearance of [MessageListView]s when /// A style that overrides the default appearance of [MessageListView]s when
/// used with [MessageListViewTheme] or with the overall [StreamChatTheme]'s /// used with [StreamMessageListViewTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.messageListViewTheme]. /// [StreamChatThemeData.messageListViewTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [MessageListViewTheme], the theme which is configured with this class. /// * [StreamMessageListViewTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.messageListViewTheme], which can be used to override /// * [StreamChatThemeData.messageListViewTheme], which can be used to override
/// the default style for [MessageListView]s below the overall /// the default style for [MessageListView]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
class MessageListViewThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [MessageListViewThemeData]. class StreamMessageListViewThemeData with Diagnosticable {
const MessageListViewThemeData({ /// Creates a [StreamMessageListViewThemeData].
const StreamMessageListViewThemeData({
this.backgroundColor, this.backgroundColor,
this.backgroundImage, this.backgroundImage,
}); });
@@ -69,12 +81,12 @@ class MessageListViewThemeData with Diagnosticable {
/// The image of the [MessageListView] background. /// The image of the [MessageListView] background.
final DecorationImage? backgroundImage; final DecorationImage? backgroundImage;
/// Copies this [MessageListViewThemeData] to another. /// Copies this [StreamMessageListViewThemeData] to another.
MessageListViewThemeData copyWith({ StreamMessageListViewThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
DecorationImage? backgroundImage, DecorationImage? backgroundImage,
}) => }) =>
MessageListViewThemeData( StreamMessageListViewThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
backgroundImage: backgroundImage ?? this.backgroundImage, backgroundImage: backgroundImage ?? this.backgroundImage,
); );
@@ -82,18 +94,18 @@ class MessageListViewThemeData with Diagnosticable {
/// Linearly interpolate between two [MessageListView] themes. /// Linearly interpolate between two [MessageListView] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
MessageListViewThemeData lerp( StreamMessageListViewThemeData lerp(
MessageListViewThemeData a, StreamMessageListViewThemeData a,
MessageListViewThemeData b, StreamMessageListViewThemeData b,
double t, double t,
) => ) =>
MessageListViewThemeData( StreamMessageListViewThemeData(
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
backgroundImage: t < 0.5 ? a.backgroundImage : b.backgroundImage, backgroundImage: t < 0.5 ? a.backgroundImage : b.backgroundImage,
); );
/// Merges one [MessageListViewThemeData] with another. /// Merges one [StreamMessageListViewThemeData] with another.
MessageListViewThemeData merge(MessageListViewThemeData? other) { StreamMessageListViewThemeData merge(StreamMessageListViewThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
backgroundColor: other.backgroundColor, backgroundColor: other.backgroundColor,
@@ -104,7 +116,7 @@ class MessageListViewThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is MessageListViewThemeData && other is StreamMessageListViewThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor && backgroundColor == other.backgroundColor &&
backgroundImage == other.backgroundImage; backgroundImage == other.backgroundImage;
@@ -2,23 +2,29 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro message_search_list_view_theme}
@Deprecated("Use 'StreamMessageSearchListViewTheme' instead")
typedef MessageSearchListViewTheme = StreamMessageSearchListViewTheme;
/// {@template message_search_list_view_theme}
/// Overrides the default style of [MessageSearchListView] descendants. /// Overrides the default style of [MessageSearchListView] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [UserListViewThemeData], which is used to configure this theme. /// * [UserListViewThemeData], which is used to configure this theme.
class MessageSearchListViewTheme extends InheritedTheme { /// {@endtemplate}
class StreamMessageSearchListViewTheme extends InheritedTheme {
/// Creates a [UserListViewTheme]. /// Creates a [UserListViewTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const MessageSearchListViewTheme({ const StreamMessageSearchListViewTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final MessageSearchListViewThemeData data; final StreamMessageSearchListViewThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
@@ -30,64 +36,72 @@ class MessageSearchListViewTheme extends InheritedTheme {
/// ```dart /// ```dart
/// MessageSearchListViewTheme theme = MessageSearchListViewTheme.of(context); /// MessageSearchListViewTheme theme = MessageSearchListViewTheme.of(context);
/// ``` /// ```
static MessageSearchListViewThemeData of(BuildContext context) { static StreamMessageSearchListViewThemeData of(BuildContext context) {
final messageSearchListViewTheme = context final messageSearchListViewTheme = context
.dependOnInheritedWidgetOfExactType<MessageSearchListViewTheme>(); .dependOnInheritedWidgetOfExactType<StreamMessageSearchListViewTheme>();
return messageSearchListViewTheme?.data ?? return messageSearchListViewTheme?.data ??
StreamChatTheme.of(context).messageSearchListViewTheme; StreamChatTheme.of(context).messageSearchListViewTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
MessageSearchListViewTheme(data: data, child: child); StreamMessageSearchListViewTheme(data: data, child: child);
@override @override
bool updateShouldNotify(MessageSearchListViewTheme oldWidget) => bool updateShouldNotify(StreamMessageSearchListViewTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro message_search_list_view_theme_data}
@Deprecated("Use 'StreamMessageSearchListViewThemeData' instead")
typedef MessageSearchListViewThemeData = StreamMessageSearchListViewThemeData;
/// {@macro message_search_list_view_theme_data}
/// A style that overrides the default appearance of [MessageSearchListView]s /// A style that overrides the default appearance of [MessageSearchListView]s
/// when used with [MessageSearchListView] or with the overall /// when used with [MessageSearchListView] or with the overall
/// [StreamChatTheme]'s [StreamChatThemeData.messageSearchListViewTheme]. /// [StreamChatTheme]'s [StreamChatThemeData.messageSearchListViewTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [MessageSearchListViewTheme], the theme which is configured with this /// * [StreamMessageSearchListViewTheme], the theme which is configured with this
/// class. /// class.
/// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to /// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to
/// override the default style for [UserListView]s below the overall /// override the default style for [UserListView]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
class MessageSearchListViewThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [MessageSearchListViewThemeData]. class StreamMessageSearchListViewThemeData with Diagnosticable {
const MessageSearchListViewThemeData({ /// Creates a [StreamMessageSearchListViewThemeData].
const StreamMessageSearchListViewThemeData({
this.backgroundColor, this.backgroundColor,
}); });
/// The color of the [MessageSearchListView] background. /// The color of the [MessageSearchListView] background.
final Color? backgroundColor; final Color? backgroundColor;
/// Copies this [MessageSearchListViewThemeData] to another. /// Copies this [StreamMessageSearchListViewThemeData] to another.
MessageSearchListViewThemeData copyWith({ StreamMessageSearchListViewThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
}) => }) =>
MessageSearchListViewThemeData( StreamMessageSearchListViewThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
); );
/// Linearly interpolate between two [UserListViewThemeData] themes. /// Linearly interpolate between two [UserListViewThemeData] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
MessageSearchListViewThemeData lerp( StreamMessageSearchListViewThemeData lerp(
MessageSearchListViewThemeData a, StreamMessageSearchListViewThemeData a,
MessageSearchListViewThemeData b, StreamMessageSearchListViewThemeData b,
double t, double t,
) => ) =>
MessageSearchListViewThemeData( StreamMessageSearchListViewThemeData(
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
); );
/// Merges one [MessageSearchListViewThemeData] with another. /// Merges one [StreamMessageSearchListViewThemeData] with another.
MessageSearchListViewThemeData merge(MessageSearchListViewThemeData? other) { StreamMessageSearchListViewThemeData merge(
StreamMessageSearchListViewThemeData? other,
) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
backgroundColor: other.backgroundColor, backgroundColor: other.backgroundColor,
@@ -97,7 +111,7 @@ class MessageSearchListViewThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is MessageSearchListViewThemeData && other is StreamMessageSearchListViewThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor; backgroundColor == other.backgroundColor;
@@ -2,11 +2,17 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
/// {@macro message_theme_data}
@Deprecated("Use 'StreamMessageThemeData' instead")
typedef MessageThemeData = StreamMessageThemeData;
/// {@template message_theme_data}
/// Class for getting message theme /// Class for getting message theme
/// {@endtemplate}
// ignore: prefer-match-file-name // ignore: prefer-match-file-name
class MessageThemeData with Diagnosticable { class StreamMessageThemeData with Diagnosticable {
/// Creates a [MessageThemeData]. /// Creates a [StreamMessageThemeData].
const MessageThemeData({ const StreamMessageThemeData({
this.repliesStyle, this.repliesStyle,
this.messageTextStyle, this.messageTextStyle,
this.messageAuthorStyle, this.messageAuthorStyle,
@@ -52,13 +58,13 @@ class MessageThemeData with Diagnosticable {
final Color? reactionsMaskColor; final Color? reactionsMaskColor;
/// Theme of the avatar /// Theme of the avatar
final AvatarThemeData? avatarTheme; final StreamAvatarThemeData? avatarTheme;
/// Background color for messages with url attachments. /// Background color for messages with url attachments.
final Color? linkBackgroundColor; final Color? linkBackgroundColor;
/// Copy with a theme /// Copy with a theme
MessageThemeData copyWith({ StreamMessageThemeData copyWith({
TextStyle? messageTextStyle, TextStyle? messageTextStyle,
TextStyle? messageAuthorStyle, TextStyle? messageAuthorStyle,
TextStyle? messageLinksStyle, TextStyle? messageLinksStyle,
@@ -66,13 +72,13 @@ class MessageThemeData with Diagnosticable {
TextStyle? repliesStyle, TextStyle? repliesStyle,
Color? messageBackgroundColor, Color? messageBackgroundColor,
Color? messageBorderColor, Color? messageBorderColor,
AvatarThemeData? avatarTheme, StreamAvatarThemeData? avatarTheme,
Color? reactionsBackgroundColor, Color? reactionsBackgroundColor,
Color? reactionsBorderColor, Color? reactionsBorderColor,
Color? reactionsMaskColor, Color? reactionsMaskColor,
Color? linkBackgroundColor, Color? linkBackgroundColor,
}) => }) =>
MessageThemeData( StreamMessageThemeData(
messageTextStyle: messageTextStyle ?? this.messageTextStyle, messageTextStyle: messageTextStyle ?? this.messageTextStyle,
messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle, messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle,
messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle, messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle,
@@ -89,11 +95,15 @@ class MessageThemeData with Diagnosticable {
linkBackgroundColor: linkBackgroundColor ?? this.linkBackgroundColor, linkBackgroundColor: linkBackgroundColor ?? this.linkBackgroundColor,
); );
/// Linearly interpolate from one [MessageThemeData] to another. /// Linearly interpolate from one [StreamMessageThemeData] to another.
MessageThemeData lerp(MessageThemeData a, MessageThemeData b, double t) => StreamMessageThemeData lerp(
MessageThemeData( StreamMessageThemeData a,
avatarTheme: StreamMessageThemeData b,
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t), double t,
) =>
StreamMessageThemeData(
avatarTheme: const StreamAvatarThemeData()
.lerp(a.avatarTheme!, b.avatarTheme!, t),
createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t), createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t),
messageAuthorStyle: messageAuthorStyle:
TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t), TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t),
@@ -120,7 +130,7 @@ class MessageThemeData with Diagnosticable {
); );
/// Merge with a theme /// Merge with a theme
MessageThemeData merge(MessageThemeData? other) { StreamMessageThemeData merge(StreamMessageThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ?? messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ??
@@ -146,7 +156,7 @@ class MessageThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is MessageThemeData && other is StreamMessageThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
messageTextStyle == other.messageTextStyle && messageTextStyle == other.messageTextStyle &&
messageAuthorStyle == other.messageAuthorStyle && messageAuthorStyle == other.messageAuthorStyle &&
@@ -1,9 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// {@macro text_theme}
@Deprecated("Use 'StreamTextTheme' instead")
typedef TextTheme = StreamTextTheme;
/// {@template text_theme}
/// Class for holding text theme /// Class for holding text theme
class TextTheme { /// {@endtemplate}
class StreamTextTheme {
/// Initialise light text theme /// Initialise light text theme
TextTheme.light({ StreamTextTheme.light({
this.title = const TextStyle( this.title = const TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -46,7 +52,7 @@ class TextTheme {
}); });
/// Initialise with dark theme /// Initialise with dark theme
TextTheme.dark({ StreamTextTheme.dark({
this.title = const TextStyle( this.title = const TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -113,7 +119,7 @@ class TextTheme {
final TextStyle captionBold; final TextStyle captionBold;
/// Copy with theme /// Copy with theme
TextTheme copyWith({ StreamTextTheme copyWith({
Brightness brightness = Brightness.light, Brightness brightness = Brightness.light,
TextStyle? body, TextStyle? body,
TextStyle? title, TextStyle? title,
@@ -125,7 +131,7 @@ class TextTheme {
TextStyle? captionBold, TextStyle? captionBold,
}) => }) =>
brightness == Brightness.light brightness == Brightness.light
? TextTheme.light( ? StreamTextTheme.light(
body: body ?? this.body, body: body ?? this.body,
title: title ?? this.title, title: title ?? this.title,
headlineBold: headlineBold ?? this.headlineBold, headlineBold: headlineBold ?? this.headlineBold,
@@ -135,7 +141,7 @@ class TextTheme {
footnote: footnote ?? this.footnote, footnote: footnote ?? this.footnote,
captionBold: captionBold ?? this.captionBold, captionBold: captionBold ?? this.captionBold,
) )
: TextTheme.dark( : StreamTextTheme.dark(
body: body ?? this.body, body: body ?? this.body,
title: title ?? this.title, title: title ?? this.title,
headlineBold: headlineBold ?? this.headlineBold, headlineBold: headlineBold ?? this.headlineBold,
@@ -147,7 +153,7 @@ class TextTheme {
); );
/// Merge text theme /// Merge text theme
TextTheme merge(TextTheme? other) { StreamTextTheme merge(StreamTextTheme? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
body: body.merge(other.body), body: body.merge(other.body),
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
/// {@macro user_list_view_theme}
@Deprecated("Use 'StreamUserListViewTheme' instead")
typedef UserListViewTheme = StreamUserListViewTheme;
/// {@template user_list_view_theme}
/// Overrides the default style of [UserListView] descendants. /// Overrides the default style of [UserListView] descendants.
/// ///
/// See also: /// See also:
/// ///
/// * [UserListViewThemeData], which is used to configure this theme. /// * [StreamUserListViewThemeData], which is used to configure this theme.
class UserListViewTheme extends InheritedTheme { /// {@endtemplate}
/// Creates a [UserListViewTheme]. class StreamUserListViewTheme extends InheritedTheme {
/// Creates a [StreamUserListViewTheme].
/// ///
/// The [data] parameter must not be null. /// The [data] parameter must not be null.
const UserListViewTheme({ const StreamUserListViewTheme({
Key? key, Key? key,
required this.data, required this.data,
required Widget child, required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
/// The configuration of this theme. /// The configuration of this theme.
final UserListViewThemeData data; final StreamUserListViewThemeData data;
/// The closest instance of this class that encloses the given context. /// The closest instance of this class that encloses the given context.
/// ///
/// If there is no enclosing [UserListViewTheme] widget, then /// If there is no enclosing [StreamUserListViewTheme] widget, then
/// [StreamChatThemeData.userListViewTheme] is used. /// [StreamChatThemeData.userListViewTheme] is used.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
@@ -30,35 +36,41 @@ class UserListViewTheme extends InheritedTheme {
/// ```dart /// ```dart
/// UserListViewTheme theme = UserListViewTheme.of(context); /// UserListViewTheme theme = UserListViewTheme.of(context);
/// ``` /// ```
static UserListViewThemeData of(BuildContext context) { static StreamUserListViewThemeData of(BuildContext context) {
final userListViewTheme = final userListViewTheme =
context.dependOnInheritedWidgetOfExactType<UserListViewTheme>(); context.dependOnInheritedWidgetOfExactType<StreamUserListViewTheme>();
return userListViewTheme?.data ?? return userListViewTheme?.data ??
StreamChatTheme.of(context).userListViewTheme; StreamChatTheme.of(context).userListViewTheme;
} }
@override @override
Widget wrap(BuildContext context, Widget child) => Widget wrap(BuildContext context, Widget child) =>
UserListViewTheme(data: data, child: child); StreamUserListViewTheme(data: data, child: child);
@override @override
bool updateShouldNotify(UserListViewTheme oldWidget) => bool updateShouldNotify(StreamUserListViewTheme oldWidget) =>
data != oldWidget.data; data != oldWidget.data;
} }
/// {@macro user_list_view_theme_data}
@Deprecated("Use 'StreamUserListViewThemeData' instead")
typedef UserListViewThemeData = StreamUserListViewThemeData;
/// {@template user_list_view_theme_data}
/// A style that overrides the default appearance of [UserListView]s when /// A style that overrides the default appearance of [UserListView]s when
/// used with [UserListViewTheme] or with the overall [StreamChatTheme]'s /// used with [StreamUserListViewTheme] or with the overall [StreamChatTheme]'s
/// [StreamChatThemeData.userListViewTheme]. /// [StreamChatThemeData.userListViewTheme].
/// ///
/// See also: /// See also:
/// ///
/// * [UserListViewTheme], the theme which is configured with this class. /// * [StreamUserListViewTheme], the theme which is configured with this class.
/// * [StreamChatThemeData.userListViewTheme], which can be used to override /// * [StreamChatThemeData.userListViewTheme], which can be used to override
/// the default style for [UserListView]s below the overall /// the default style for [UserListView]s below the overall
/// [StreamChatTheme]. /// [StreamChatTheme].
class UserListViewThemeData with Diagnosticable { /// {@endtemplate}
/// Creates a [UserListViewThemeData]. class StreamUserListViewThemeData with Diagnosticable {
const UserListViewThemeData({ /// Creates a [StreamUserListViewThemeData].
const StreamUserListViewThemeData({
this.backgroundColor, this.backgroundColor,
}); });
@@ -66,27 +78,27 @@ class UserListViewThemeData with Diagnosticable {
final Color? backgroundColor; final Color? backgroundColor;
/// Copies this [ChannelListViewThemeData] to another. /// Copies this [ChannelListViewThemeData] to another.
UserListViewThemeData copyWith({ StreamUserListViewThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
}) => }) =>
UserListViewThemeData( StreamUserListViewThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
); );
/// Linearly interpolate between two [UserListViewThemeData] themes. /// Linearly interpolate between two [StreamUserListViewThemeData] themes.
/// ///
/// All the properties must be non-null. /// All the properties must be non-null.
UserListViewThemeData lerp( StreamUserListViewThemeData lerp(
UserListViewThemeData a, StreamUserListViewThemeData a,
UserListViewThemeData b, StreamUserListViewThemeData b,
double t, double t,
) => ) =>
UserListViewThemeData( StreamUserListViewThemeData(
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
); );
/// Merges one [UserListViewThemeData] with another. /// Merges one [StreamUserListViewThemeData] with another.
UserListViewThemeData merge(UserListViewThemeData? other) { StreamUserListViewThemeData merge(StreamUserListViewThemeData? other) {
if (other == null) return this; if (other == null) return this;
return copyWith( return copyWith(
backgroundColor: other.backgroundColor, backgroundColor: other.backgroundColor,
@@ -96,7 +108,7 @@ class UserListViewThemeData with Diagnosticable {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is UserListViewThemeData && other is StreamUserListViewThemeData &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
backgroundColor == other.backgroundColor; backgroundColor == other.backgroundColor;
@@ -3,6 +3,11 @@ import 'package:flutter/services.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro thread_header}
@Deprecated("Use 'StreamThreadHeader' instead")
typedef ThreadHeader = StreamThreadHeader;
/// {@template thread_header}
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/thread_header.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/thread_header.png)
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/thread_header_paint.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/packages/stream_chat_flutter/screenshots/thread_header_paint.png)
/// ///
@@ -56,9 +61,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// The widget components render the ui based on the first ancestor of type /// The widget components render the ui based on the first ancestor of type
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { /// {@endtemplate}
class StreamThreadHeader extends StatelessWidget
implements PreferredSizeWidget {
/// Instantiate a new ThreadHeader /// Instantiate a new ThreadHeader
const ThreadHeader({ const StreamThreadHeader({
Key? key, Key? key,
required this.parent, required this.parent,
this.showBackButton = true, this.showBackButton = true,
@@ -102,12 +109,12 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
/// if a user is typing in this thread /// if a user is typing in this thread
final bool showTypingIndicator; final bool showTypingIndicator;
/// The background color of this [ThreadHeader]. /// The background color of this [StreamThreadHeader].
final Color? backgroundColor; final Color? backgroundColor;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final channelHeaderTheme = ChannelHeaderTheme.of(context); final channelHeaderTheme = StreamChannelHeaderTheme.of(context);
final defaultSubtitle = subtitle ?? final defaultSubtitle = subtitle ??
Row( Row(
@@ -162,7 +169,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
const SizedBox(height: 2), const SizedBox(height: 2),
if (showTypingIndicator) if (showTypingIndicator)
Align( Align(
child: TypingIndicator( child: StreamTypingIndicator(
channel: StreamChannel.of(context).channel, channel: StreamChannel.of(context).channel,
style: channelHeaderTheme.subtitleStyle, style: channelHeaderTheme.subtitleStyle,
parentId: parent.id, parentId: parent.id,
@@ -3,10 +3,16 @@ import 'package:lottie/lottie.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// {@macro typing_indicator}
@Deprecated("Use 'StreamTypingIndicator' instead")
typedef TypingIndicator = StreamTypingIndicator;
/// {@template typing_indicator}
/// Widget to show the current list of typing users /// Widget to show the current list of typing users
class TypingIndicator extends StatelessWidget { /// {@endtemplate}
class StreamTypingIndicator extends StatelessWidget {
/// Instantiate a new TypingIndicator /// Instantiate a new TypingIndicator
const TypingIndicator({ const StreamTypingIndicator({
Key? key, Key? key,
this.channel, this.channel,
this.alternativeWidget, this.alternativeWidget,
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro unread_indicator}
@Deprecated("Use 'StreamUnreadIndicator' instead")
typedef UnreadIndicator = StreamUnreadIndicator;
/// {@template unread_indicator}
/// Widget for showing an unread indicator /// Widget for showing an unread indicator
class UnreadIndicator extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating an [UnreadIndicator] class StreamUnreadIndicator extends StatelessWidget {
const UnreadIndicator({ /// Constructor for creating an [StreamUnreadIndicator]
const StreamUnreadIndicator({
Key? key, Key? key,
this.cid, this.cid,
}) : super(key: key); }) : super(key: key);
@@ -1,10 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro upload_progress_indicator}
@Deprecated("Use 'StreamUploadProgressIndicator' instead")
typedef UploadProgressIndicator = StreamUploadProgressIndicator;
/// {@template upload_progress_indicator}
/// Widget for showing upload progress /// Widget for showing upload progress
class UploadProgressIndicator extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating an [UploadProgressIndicator] class StreamUploadProgressIndicator extends StatelessWidget {
const UploadProgressIndicator({ /// Constructor for creating an [StreamUploadProgressIndicator]
const StreamUploadProgressIndicator({
Key? key, Key? key,
required this.uploaded, required this.uploaded,
required this.total, required this.total,
@@ -2,10 +2,16 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro user_avatar}
@Deprecated("Use 'StreamUserAvatar' instead")
typedef UserAvatar = StreamUserAvatar;
/// {@template user_avatar}
/// Widget that displays a user avatar /// Widget that displays a user avatar
class UserAvatar extends StatelessWidget { /// {@endtemplate}
/// Constructor to create a [UserAvatar] class StreamUserAvatar extends StatelessWidget {
const UserAvatar({ /// Constructor to create a [StreamUserAvatar]
const StreamUserAvatar({
Key? key, Key? key,
required this.user, required this.user,
this.constraints, this.constraints,
@@ -2,21 +2,26 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// /// {@macro user_item}
@Deprecated("Use 'StreamUserItem' instead")
typedef UserItem = StreamUserItem;
/// {@template user_item}
/// It shows the current [User] preview. /// It shows the current [User] preview.
/// ///
/// The widget uses a [StreamBuilder] to render the user information /// The widget uses a [StreamBuilder] to render the user information
/// image as soon as it updates. /// image as soon as it updates.
/// ///
/// Usually you don't use this widget as it's the default user preview used /// Usually you don't use this widget as it's the default user preview used
/// by [UserListView]. /// by [StreamUserListView].
/// ///
/// The widget renders the ui based on the first ancestor of type /// The widget renders the ui based on the first ancestor of type
/// [StreamChatTheme]. /// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class UserItem extends StatelessWidget { /// {@endtemplate}
class StreamUserItem extends StatelessWidget {
/// Instantiate a new UserItem /// Instantiate a new UserItem
const UserItem({ const StreamUserItem({
Key? key, Key? key,
required this.user, required this.user,
this.onTap, this.onTap,
@@ -38,10 +43,10 @@ class UserItem extends StatelessWidget {
/// The function called when the image is tapped /// The function called when the image is tapped
final void Function(User)? onImageTap; final void Function(User)? onImageTap;
/// If true the [UserItem] will show a trailing checkmark /// If true the [StreamUserItem] will show a trailing checkmark
final bool selected; final bool selected;
/// If true the [UserItem] will show the last seen /// If true the [StreamUserItem] will show the last seen
final bool showLastOnline; final bool showLastOnline;
@override @override
@@ -58,7 +63,7 @@ class UserItem extends StatelessWidget {
onLongPress!(user); onLongPress!(user);
} }
}, },
leading: UserAvatar( leading: StreamUserAvatar(
user: user, user: user,
onTap: (user) { onTap: (user) {
if (onImageTap != null) { if (onImageTap != null) {
@@ -8,7 +8,11 @@ typedef UserTapCallback = void Function(User, Widget?);
/// Builder used to create a custom [ListUserItem] from a [User] /// Builder used to create a custom [ListUserItem] from a [User]
typedef UserItemBuilder = Widget Function(BuildContext, User, bool); typedef UserItemBuilder = Widget Function(BuildContext, User, bool);
/// /// {@macro user_list_view}
@Deprecated("Use 'StreamUserListView' instead")
typedef UserListView = StreamUserListView;
/// {@template user_list_view}
/// It shows the list of current users. /// It shows the list of current users.
/// ///
/// ```dart /// ```dart
@@ -42,9 +46,10 @@ typedef UserItemBuilder = Widget Function(BuildContext, User, bool);
/// The widget components render the ui based on the first ancestor of /// The widget components render the ui based on the first ancestor of
/// type [StreamChatTheme]. /// type [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class UserListView extends StatefulWidget { /// {@endtemplate}
class StreamUserListView extends StatefulWidget {
/// Instantiate a new UserListView /// Instantiate a new UserListView
UserListView({ StreamUserListView({
Key? key, Key? key,
this.filter = const Filter.empty(), this.filter = const Filter.empty(),
this.sort, this.sort,
@@ -160,10 +165,10 @@ class UserListView extends StatefulWidget {
final UserListController? userListController; final UserListController? userListController;
@override @override
_UserListViewState createState() => _UserListViewState(); _StreamUserListViewState createState() => _StreamUserListViewState();
} }
class _UserListViewState extends State<UserListView> class _StreamUserListViewState extends State<StreamUserListView>
with WidgetsBindingObserver { with WidgetsBindingObserver {
bool get _isListView => widget.crossAxisCount == 1; bool get _isListView => widget.crossAxisCount == 1;
@@ -203,7 +208,7 @@ class _UserListViewState extends State<UserListView>
userListController: _userListController, userListController: _userListController,
); );
final backgroundColor = UserListViewTheme.of(context).backgroundColor; final backgroundColor = StreamUserListViewTheme.of(context).backgroundColor;
Widget child; Widget child;
@@ -332,7 +337,7 @@ class _UserListViewState extends State<UserListView>
key: ValueKey<String>('USER-${user.id}'), key: ValueKey<String>('USER-${user.id}'),
child: widget.userItemBuilder != null child: widget.userItemBuilder != null
? widget.userItemBuilder!(context, user, selected) ? widget.userItemBuilder!(context, user, selected)
: UserItem( : StreamUserItem(
user: user, user: user,
onTap: (user) => widget.onUserTap!(user, widget.userWidget), onTap: (user) => widget.onUserTap!(user, widget.userWidget),
onLongPress: widget.onUserLongPress, onLongPress: widget.onUserLongPress,
@@ -362,7 +367,7 @@ class _UserListViewState extends State<UserListView>
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
UserAvatar( StreamUserAvatar(
user: user, user: user,
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
selected: selected, selected: selected,
@@ -1,12 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro user_mention_tile}
@Deprecated("Use 'StreamUserMentionTile' instead")
typedef UserMentionTile = StreamUserMentionTile;
/// {@template user_mention_tile}
/// This widget is used for showing user tiles for mentions /// This widget is used for showing user tiles for mentions
/// Use [title], [subtitle], [leading], [trailing] for /// Use [title], [subtitle], [leading], [trailing] for
/// substituting widgets in respective positions /// substituting widgets in respective positions
class UserMentionTile extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [UserMentionTile] widget class StreamUserMentionTile extends StatelessWidget {
const UserMentionTile( /// Constructor for creating a [StreamUserMentionTile] widget
const StreamUserMentionTile(
this.user, { this.user, {
Key? key, Key? key,
this.title, this.title,
@@ -41,7 +47,7 @@ class UserMentionTile extends StatelessWidget {
width: 16, width: 16,
), ),
leading ?? leading ??
UserAvatar( StreamUserAvatar(
user: user, user: user,
constraints: BoxConstraints.tight(const Size(40, 40)), constraints: BoxConstraints.tight(const Size(40, 40)),
), ),
@@ -6,16 +6,22 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Builder function for building a mention tile. /// Builder function for building a mention tile.
/// ///
/// Use [UserMentionTile] for the default implementation. /// Use [StreamUserMentionTile] for the default implementation.
typedef MentionTileBuilder = Widget Function( typedef MentionTileBuilder = Widget Function(
BuildContext context, BuildContext context,
User user, User user,
); );
/// {@macro user_mention_tile}
@Deprecated("Use 'StreamUserMentionsOverlay' instead")
typedef UserMentionsOverlay = StreamUserMentionsOverlay;
/// {@template user_mentions_overlay}
/// Overlay for displaying users that can be mentioned. /// Overlay for displaying users that can be mentioned.
class UserMentionsOverlay extends StatefulWidget { /// {@endtemplate}
/// Constructor for creating a [UserMentionsOverlay]. class StreamUserMentionsOverlay extends StatefulWidget {
UserMentionsOverlay({ /// Constructor for creating a [StreamUserMentionsOverlay].
StreamUserMentionsOverlay({
Key? key, Key? key,
required this.query, required this.query,
required this.channel, required this.channel,
@@ -62,10 +68,11 @@ class UserMentionsOverlay extends StatefulWidget {
final void Function(User user)? onMentionUserTap; final void Function(User user)? onMentionUserTap;
@override @override
_UserMentionsOverlayState createState() => _UserMentionsOverlayState(); _StreamUserMentionsOverlayState createState() =>
_StreamUserMentionsOverlayState();
} }
class _UserMentionsOverlayState extends State<UserMentionsOverlay> { class _StreamUserMentionsOverlayState extends State<StreamUserMentionsOverlay> {
late Future<List<User>> userMentionsFuture; late Future<List<User>> userMentionsFuture;
@override @override
@@ -75,7 +82,7 @@ class _UserMentionsOverlayState extends State<UserMentionsOverlay> {
} }
@override @override
void didUpdateWidget(covariant UserMentionsOverlay oldWidget) { void didUpdateWidget(covariant StreamUserMentionsOverlay oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.channel != oldWidget.channel || if (widget.channel != oldWidget.channel ||
widget.query != oldWidget.query || widget.query != oldWidget.query ||
@@ -116,7 +123,7 @@ class _UserMentionsOverlayState extends State<UserMentionsOverlay> {
child: InkWell( child: InkWell(
onTap: () => widget.onMentionUserTap?.call(user), onTap: () => widget.onMentionUserTap?.call(user),
child: widget.mentionsTileBuilder?.call(context, user) ?? child: widget.mentionsTileBuilder?.call(context, user) ??
UserMentionTile(user), StreamUserMentionTile(user),
), ),
); );
}, },
@@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/typing_indicator.dart';
import 'package:stream_chat_flutter/src/unread_indicator.dart'; import 'package:stream_chat_flutter/src/unread_indicator.dart';
import 'package:stream_chat_flutter/src/v4/stream_channel_avatar.dart'; import 'package:stream_chat_flutter/src/v4/stream_channel_avatar.dart';
import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart'; import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// A widget that displays a channel preview. /// A widget that displays a channel preview.
@@ -131,7 +132,7 @@ class StreamChannelListTile extends StatelessWidget {
final channelState = channel.state!; final channelState = channel.state!;
final currentUser = channel.client.state.currentUser!; final currentUser = channel.client.state.currentUser!;
final channelPreviewTheme = ChannelPreviewTheme.of(context); final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
final leading = this.leading ?? final leading = this.leading ??
StreamChannelAvatar( StreamChannelAvatar(
@@ -182,7 +183,7 @@ class StreamChannelListTile extends StatelessWidget {
return const Offstage(); return const Offstage();
} }
return unreadIndicatorBuilder?.call(context) ?? return unreadIndicatorBuilder?.call(context) ??
UnreadIndicator(cid: channel.cid); StreamUnreadIndicator(cid: channel.cid);
}, },
), ),
], ],
@@ -213,7 +214,7 @@ class StreamChannelListTile extends StatelessWidget {
padding: const EdgeInsets.only(right: 4), padding: const EdgeInsets.only(right: 4),
child: child:
sendingIndicatorBuilder?.call(context, lastMessage) ?? sendingIndicatorBuilder?.call(context, lastMessage) ??
SendingIndicator( StreamSendingIndicator(
message: lastMessage, message: lastMessage,
size: channelPreviewTheme.indicatorIconSize, size: channelPreviewTheme.indicatorIconSize,
isMessageRead: channelState isMessageRead: channelState
@@ -318,7 +319,7 @@ class ChannelListTileSubtitle extends StatelessWidget {
], ],
); );
} }
return TypingIndicator( return StreamTypingIndicator(
channel: channel, channel: channel,
style: textStyle, style: textStyle,
alternativeWidget: ChannelLastMessageText( alternativeWidget: ChannelLastMessageText(
@@ -359,10 +360,18 @@ class ChannelLastMessageText extends StatelessWidget {
if (lastMessage == null) return const Offstage(); if (lastMessage == null) return const Offstage();
final lastMessageText = lastMessage.text; final lastMessageText = lastMessage
.translate(channel.client.state.currentUser?.language ?? 'en')
.replaceMentions(linkify: false)
.text;
final lastMessageAttachments = lastMessage.attachments; final lastMessageAttachments = lastMessage.attachments;
final lastMessageMentionedUsers = lastMessage.mentionedUsers; final lastMessageMentionedUsers = lastMessage.mentionedUsers;
final mentionedUsersRegex = RegExp(
lastMessageMentionedUsers.map((it) => '@${it.name}').join('|'),
caseSensitive: false,
);
final messageTextParts = [ final messageTextParts = [
...lastMessageAttachments.map((it) { ...lastMessageAttachments.map((it) {
if (it.type == 'image') { if (it.type == 'image') {
@@ -376,7 +385,11 @@ class ChannelLastMessageText extends StatelessWidget {
? (it.title ?? 'File') ? (it.title ?? 'File')
: '${it.title ?? 'File'} , '; : '${it.title ?? 'File'} , ';
}), }),
if (lastMessageText != null) lastMessageText, if (lastMessageText != null)
if (lastMessageMentionedUsers.isNotEmpty)
...mentionedUsersRegex.allMatchesWithSep(lastMessageText)
else
lastMessageText,
]; ];
final fontStyle = (lastMessage.isSystem || lastMessage.isDeleted) final fontStyle = (lastMessage.isSystem || lastMessage.isDeleted)
@@ -395,7 +408,7 @@ class ChannelLastMessageText extends StatelessWidget {
if (lastMessageMentionedUsers.isNotEmpty && if (lastMessageMentionedUsers.isNotEmpty &&
lastMessageMentionedUsers.any((it) => '@${it.name}' == part)) lastMessageMentionedUsers.any((it) => '@${it.name}' == part))
TextSpan( TextSpan(
text: '$part ', text: part,
style: mentionsTextStyle, style: mentionsTextStyle,
) )
else if (lastMessageAttachments.isNotEmpty && else if (lastMessageAttachments.isNotEmpty &&
@@ -403,12 +416,14 @@ class ChannelLastMessageText extends StatelessWidget {
.where((it) => it.title != null) .where((it) => it.title != null)
.any((it) => it.title == part)) .any((it) => it.title == part))
TextSpan( TextSpan(
text: '$part ', text: part,
style: regularTextStyle, style: regularTextStyle?.copyWith(
fontStyle: FontStyle.italic,
),
) )
else else
TextSpan( TextSpan(
text: part == messageTextParts.last ? part : '$part ', text: part,
style: regularTextStyle, style: regularTextStyle,
), ),
]; ];
@@ -422,3 +437,18 @@ class ChannelLastMessageText extends StatelessWidget {
}, },
); );
} }
extension _RegExpX on RegExp {
List<String> allMatchesWithSep(String input, [int start = 0]) {
final result = <String>[];
for (final match in allMatches(input, start)) {
result.add(input.substring(start, match.start));
// ignore: cascade_invocations
result.add(match[0]!);
// ignore: parameter_assignments
start = match.end;
}
result.add(input.substring(start));
return result;
}
}
@@ -148,7 +148,7 @@ class StreamChannelAvatar extends StatelessWidget {
return BetterStreamBuilder<User>( return BetterStreamBuilder<User>(
stream: client.currentUserStream.map((it) => it!), stream: client.currentUserStream.map((it) => it!),
initialData: currentUser, initialData: currentUser,
builder: (context, user) => UserAvatar( builder: (context, user) => StreamUserAvatar(
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
user: user, user: user,
constraints: constraints ?? previewTheme?.constraints, constraints: constraints ?? previewTheme?.constraints,
@@ -171,7 +171,7 @@ class StreamChannelAvatar extends StatelessWidget {
), ),
), ),
initialData: member, initialData: member,
builder: (context, member) => UserAvatar( builder: (context, member) => StreamUserAvatar(
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
user: member.user!, user: member.user!,
constraints: constraints ?? previewTheme?.constraints, constraints: constraints ?? previewTheme?.constraints,
@@ -184,7 +184,7 @@ class StreamChannelAvatar extends StatelessWidget {
} }
// Group conversation // Group conversation
return GroupAvatar( return StreamGroupAvatar(
channel: channel, channel: channel,
members: otherMembers, members: otherMembers,
borderRadius: borderRadius ?? previewTheme?.borderRadius, borderRadius: borderRadius ?? previewTheme?.borderRadius,
@@ -52,7 +52,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final themeData = StreamChatTheme.of(context); final themeData = StreamChatTheme.of(context);
final colorTheme = themeData.colorTheme; final colorTheme = themeData.colorTheme;
final channelPreviewTheme = ChannelPreviewTheme.of(context); final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
final currentUser = channel.client.state.currentUser; final currentUser = channel.client.state.currentUser;
final isOneToOneChannel = channel.isDistinct && channel.memberCount == 2; final isOneToOneChannel = channel.isDistinct && channel.memberCount == 2;
@@ -84,7 +84,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
const SizedBox(height: 5), const SizedBox(height: 5),
Center( Center(
// TODO: Refactor ChannelInfo // TODO: Refactor ChannelInfo
child: ChannelInfo( child: StreamChannelInfo(
showTypingIndicator: false, showTypingIndicator: false,
channel: channel, channel: channel,
textStyle: channelPreviewTheme.subtitleStyle, textStyle: channelPreviewTheme.subtitleStyle,
@@ -105,7 +105,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
final user = member.user!; final user = member.user!;
return Column( return Column(
children: [ children: [
UserAvatar( StreamUserAvatar(
user: user, user: user,
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxHeight: 64, maxHeight: 64,
@@ -132,7 +132,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
), ),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.user( child: StreamSvgIcon.user(
@@ -143,7 +143,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
onTap: onViewInfoTap, onTap: onViewInfoTap,
), ),
if (!isOneToOneChannel) if (!isOneToOneChannel)
OptionListTile( StreamOptionListTile(
title: context.translations.leaveGroupLabel, title: context.translations.leaveGroupLabel,
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -154,7 +154,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
onTap: onLeaveChannelTap, onTap: onLeaveChannelTap,
), ),
if (isOwner) if (isOwner)
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.delete( child: StreamSvgIcon.delete(
@@ -165,7 +165,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
titleColor: colorTheme.accentError, titleColor: colorTheme.accentError,
onTap: onDeleteConversationTap, onTap: onDeleteConversationTap,
), ),
OptionListTile( StreamOptionListTile(
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: StreamSvgIcon.closeSmall( child: StreamSvgIcon.closeSmall(
@@ -1,8 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:synchronized/synchronized.dart';
import 'package:video_compress/video_compress.dart';
import 'package:video_thumbnail/video_thumbnail.dart'; import 'package:video_thumbnail/video_thumbnail.dart';
/// ///
@@ -12,32 +10,6 @@ class _IVideoService {
/// Singleton instance of [_IVideoService] /// Singleton instance of [_IVideoService]
static final _IVideoService instance = _IVideoService._(); static final _IVideoService instance = _IVideoService._();
final _lock = Lock();
/// compress video from [path]
/// compress video from [path] return [Future<MediaInfo>]
///
/// you can choose its [quality] and [frameRate]
///
/// ## example
/// ```dart
/// final info = await _flutterVideoCompress.compressVideo(
/// file.path,
/// );
/// debugPrint(info.toJson());
/// ```
Future<MediaInfo?> compressVideo(
String path, {
int frameRate = 30,
VideoQuality quality = VideoQuality.DefaultQuality,
}) async =>
_lock.synchronized(
() => VideoCompress.compressVideo(
path,
frameRate: frameRate,
quality: quality,
),
);
/// Generates a thumbnail image data in memory as UInt8List, /// Generates a thumbnail image data in memory as UInt8List,
/// it can be easily used by Image.memory(...). /// it can be easily used by Image.memory(...).
@@ -66,5 +38,10 @@ class _IVideoService {
} }
/// Get instance of [_IVideoService] /// Get instance of [_IVideoService]
@Deprecated("Use 'StreamVideoService' instead")
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
_IVideoService get VideoService => _IVideoService.instance; _IVideoService get VideoService => _IVideoService.instance;
/// Get instance of [_IVideoService]
// ignore: non_constant_identifier_names
_IVideoService get StreamVideoService => _IVideoService.instance;
@@ -6,10 +6,16 @@ import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:video_thumbnail/video_thumbnail.dart'; import 'package:video_thumbnail/video_thumbnail.dart';
/// {@macro video_thumbnail_image}
@Deprecated("Use 'StreamVideoThumbnailImage' instead")
typedef VideoThumbnailImage = StreamVideoThumbnailImage;
/// {@template video_thumbnail_image}
/// Widget for creating video thumbnail image /// Widget for creating video thumbnail image
class VideoThumbnailImage extends StatefulWidget { /// {@endtemplate}
/// Constructor for creating [VideoThumbnailImage] class StreamVideoThumbnailImage extends StatefulWidget {
const VideoThumbnailImage({ /// Constructor for creating [StreamVideoThumbnailImage]
const StreamVideoThumbnailImage({
Key? key, Key? key,
required this.video, required this.video,
this.width, this.width,
@@ -42,16 +48,17 @@ class VideoThumbnailImage extends StatefulWidget {
final WidgetBuilder? placeholderBuilder; final WidgetBuilder? placeholderBuilder;
@override @override
_VideoThumbnailImageState createState() => _VideoThumbnailImageState(); _StreamVideoThumbnailImageState createState() =>
_StreamVideoThumbnailImageState();
} }
class _VideoThumbnailImageState extends State<VideoThumbnailImage> { class _StreamVideoThumbnailImageState extends State<StreamVideoThumbnailImage> {
late Future<Uint8List?> thumbnailFuture; late Future<Uint8List?> thumbnailFuture;
late StreamChatThemeData _streamChatTheme; late StreamChatThemeData _streamChatTheme;
@override @override
void initState() { void initState() {
thumbnailFuture = VideoService.generateVideoThumbnail( thumbnailFuture = StreamVideoService.generateVideoThumbnail(
video: widget.video, video: widget.video,
imageFormat: widget.format, imageFormat: widget.format,
); );
@@ -65,9 +72,9 @@ class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
} }
@override @override
void didUpdateWidget(covariant VideoThumbnailImage oldWidget) { void didUpdateWidget(covariant StreamVideoThumbnailImage oldWidget) {
if (oldWidget.video != widget.video || oldWidget.format != widget.format) { if (oldWidget.video != widget.video || oldWidget.format != widget.format) {
thumbnailFuture = VideoService.generateVideoThumbnail( thumbnailFuture = StreamVideoService.generateVideoThumbnail(
video: widget.video, video: widget.video,
imageFormat: widget.format, imageFormat: widget.format,
); );
@@ -2,10 +2,16 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// {@macro visible_footnote}
@Deprecated("Use 'StreamVisibleFootnote' instead")
typedef VisibleFootnote = StreamVisibleFootnote;
/// {@template visible_footnote}
/// Widget for displaying a footnote /// Widget for displaying a footnote
class VisibleFootnote extends StatelessWidget { /// {@endtemplate}
/// Constructor for creating a [VisibleFootnote] class StreamVisibleFootnote extends StatelessWidget {
const VisibleFootnote({Key? key}) : super(key: key); /// Constructor for creating a [StreamVisibleFootnote]
const StreamVisibleFootnote({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

Some files were not shown because too many files have changed in this diff Show More