Merge remote-tracking branch 'origin/develop' into fix/channel-image

# Conflicts:
#	packages/stream_chat_flutter/test/src/channel_image_test.dart
This commit is contained in:
xsahil03x
2021-07-16 14:46:29 +05:30
47 changed files with 1163 additions and 1051 deletions
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_persistence/stream_chat_persistence.dart';
/// A chat-persisted StreamChatClient
final chatPersistentClient = StreamChatPersistenceClient(
logLevel: Level.INFO,
);
@@ -9,73 +10,84 @@ final chatPersistentClient = StreamChatPersistenceClient(
void main() async {
WidgetsFlutterBinding.ensureInitialized();
/// Create a new instance of [StreamChatClient] passing the apikey obtained from your
/// project dashboard.
/// Create a new instance of [StreamChatClient] passing the apikey obtained
/// from your project dashboard.
final client = StreamChatClient(
's2dxdhpxd94g',
logLevel: Level.INFO,
)..chatPersistenceClient = chatPersistentClient;
/// Set the current user and connect the websocket. In a production scenario, this should be done using
/// a backend to generate a user token using our server SDK.
/// Set the current user and connect the websocket. In a production
/// scenario, this should be done using a backend to generate a user token
/// using our server SDK.
///
/// Please see the following for more information:
/// https://getstream.io/chat/docs/ios_user_setup_and_tokens/
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.'
'0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
);
final channel = client.channel('messaging', id: 'godevs');
await channel.watch();
runApp(MyApp(client, channel));
runApp(
MyApp(
client: client,
channel: channel,
),
);
}
/// Example application using Stream Chat Flutter widgets.
/// Stream Chat Flutter is a set of Flutter widgets which provide full chat functionalities
/// for building Flutter applications using Stream.
/// If you'd prefer using minimal wrapper widgets for your app, please see our other
///
/// Stream Chat Flutter is a set of Flutter widgets which provide full chat
/// functionalities for building Flutter applications using Stream. If you'd
/// prefer using minimal wrapper widgets for your app, please see our other
/// package, `stream_chat_flutter_core`.
class MyApp extends StatelessWidget {
/// Example using Stream's Flutter package.
///
/// If you'd prefer using minimal wrapper widgets for your app, please see
/// our other package, `stream_chat_flutter_core`.
const MyApp({
Key? key,
required this.client,
required this.channel,
}) : super(key: key);
/// Instance of Stream Client.
/// Stream's [StreamChatClient] can be used to connect to our servers and set the default
/// user for the application. Performing these actions trigger a websocket connection
/// allowing for real-time updates.
///
/// Stream's [StreamChatClient] can be used to connect to our servers and
/// set the default user for the application. Performing these actions
/// trigger a websocket connection allowing for real-time updates.
final StreamChatClient client;
/// Instance of the Channel
final Channel channel;
/// Example using Stream's Flutter package.
/// If you'd prefer using minimal wrapper widgets for your app, please see our other
/// package, `stream_chat_flutter_core`.
MyApp(this.client, this.channel);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
builder: (context, widget) {
return StreamChat(
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
builder: (context, widget) => StreamChat(
client: client,
child: widget,
);
},
home: StreamChannel(
channel: channel,
child: ChannelPage(),
),
);
}
),
home: StreamChannel(
channel: channel,
child: const ChannelPage(),
),
);
}
/// A list of messages sent in the current channel.
///
/// This is implemented using [MessageListView], a widget that provides query functionalities
/// fetching the messages from the api and showing them in a listView
/// This is implemented using [MessageListView], a widget that provides query
/// functionalities fetching the messages from the api and showing them in a
/// listView.
class ChannelPage extends StatelessWidget {
/// Creates the page that shows the list of messages
const ChannelPage({
@@ -83,17 +95,15 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
body: Column(
children: <Widget>[
Expanded(
child: MessageListView(),
),
MessageInput(),
],
),
);
}
Widget build(BuildContext context) => Scaffold(
appBar: const ChannelHeader(),
body: Column(
children: const <Widget>[
Expanded(
child: MessageListView(),
),
MessageInput(),
],
),
);
}
@@ -10,30 +10,39 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
final StreamChatClient client;
MyApp(this.client);
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: SplitView(),
);
}
Widget build(BuildContext context) => MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: const SplitView(),
);
}
class SplitView extends StatefulWidget {
const SplitView({
Key? key,
}) : super(key: key);
@override
_SplitViewState createState() => _SplitViewState();
}
@@ -42,69 +51,67 @@ class _SplitViewState extends State<SplitView> {
Channel? selectedChannel;
@override
Widget build(BuildContext context) {
return Flex(
direction: Axis.horizontal,
children: <Widget>[
Flexible(
flex: 1,
child: ChannelListPage(
onTap: (channel) {
setState(() {
selectedChannel = channel;
});
},
Widget build(BuildContext context) => Flex(
direction: Axis.horizontal,
children: <Widget>[
Flexible(
child: ChannelListPage(
onTap: (channel) {
setState(() {
selectedChannel = channel;
});
},
),
),
),
Flexible(
flex: 2,
child: Scaffold(
body: selectedChannel != null
? StreamChannel(
key: ValueKey(selectedChannel!.cid),
channel: selectedChannel!,
child: ChannelPage(),
)
: Center(
child: Text(
'Pick a channel to show the messages 💬',
style: Theme.of(context).textTheme.headline5,
Flexible(
flex: 2,
child: Scaffold(
body: selectedChannel != null
? StreamChannel(
key: ValueKey(selectedChannel!.cid),
channel: selectedChannel!,
child: const ChannelPage(),
)
: Center(
child: Text(
'Pick a channel to show the messages 💬',
style: Theme.of(context).textTheme.headline5,
),
),
),
),
),
),
],
);
}
],
);
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
this.onTap,
}) : super(key: key);
final void Function(Channel)? onTap;
ChannelListPage({this.onTap});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
child: ChannelListView(
onChannelTap: onTap != null
? (channel, _) {
onTap!(channel);
}
: null,
filter: Filter.in_(
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
limit: 20,
Widget build(BuildContext context) => Scaffold(
body: ChannelsBloc(
child: ChannelListView(
onChannelTap: onTap != null
? (channel, _) {
onTap!(channel);
}
: null,
filter: Filter.in_(
'members',
[StreamChat.of(context).user!.id],
),
sort: const [SortOption('last_message_at')],
pagination: const PaginationParams(
limit: 20,
),
),
),
),
);
}
);
}
class ChannelPage extends StatelessWidget {
@@ -113,27 +120,21 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Navigator(
onGenerateRoute: (settings) {
return MaterialPageRoute(
builder: (context) {
return Scaffold(
appBar: ChannelHeader(
showBackButton: false,
),
body: Column(
children: <Widget>[
Expanded(
child: MessageListView(),
),
MessageInput(),
],
),
);
},
);
},
);
}
Widget build(BuildContext context) => Navigator(
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => Scaffold(
appBar: const ChannelHeader(
showBackButton: false,
),
body: Column(
children: const <Widget>[
Expanded(
child: MessageListView(),
),
MessageInput(),
],
),
),
),
);
}
@@ -4,25 +4,30 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// First step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// There are three important things to notice that are common to all Flutter application using StreamChat:
/// There are three important things to notice that are common to all Flutter
/// application using StreamChat:
///
/// 1. The Dart API [StreamChatClient] is initialized with your API Key
/// 2. The current user is set by calling [StreamChatClient.connectUser]
/// 3. The client is then passed to the top-level [StreamChat] widget
/// [StreamChat] is an inherited widget and must be the parent of all Chat related widgets.
/// [StreamChat] is an inherited widget and must be the parent of all
/// Chat related widgets.
///
/// Please note that while Flutter can be used to build both mobile and web applications;
/// in this tutorial we focus on mobile, make sure when running the app you use a mobile device.
/// Please note that while Flutter can be used to build both mobile and web
/// applications, in this tutorial we focus on mobile. Make sure when running
/// the app that you use a mobile device.
///
/// Let's have a look at what we've built:
///
/// - We set up the Chat [StreamChatClient] with the API key
///
/// - We set the the current user for Chat with [StreamChatClient.connectUser] and a pre-generated user token
/// - We set the the current user for Chat with [StreamChatClient.connectUser]
/// and a pre-generated user token
///
/// - We make [StreamChat] the root Widget of our application
///
/// - We create a single [ChannelPage] widget under [StreamChat] with three widgets: [ChannelHeader], [MessageListView] and [MessageInput]
/// - We create a single [ChannelPage] widget under [StreamChat] with three
/// widgets: [ChannelHeader], [MessageListView] and [MessageInput]
///
/// If you now run the simulator you will see a single channel UI.
void main() async {
@@ -33,26 +38,38 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
final channel = client.channel('messaging', id: 'godevs');
// ignore: unawaited_futures
// ignore: unawaited_futures, cascade_invocations
channel.watch();
runApp(MyApp(client, channel));
runApp(
MyApp(
client: client,
channel: channel,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
required this.channel,
}) : super(key: key);
final StreamChatClient client;
final Channel channel;
MyApp(this.client, this.channel);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
// ignore: prefer_expression_function_bodies
builder: (context, widget) {
return StreamChat(
client: client,
@@ -61,7 +78,7 @@ class MyApp extends StatelessWidget {
},
home: StreamChannel(
channel: channel,
child: ChannelPage(),
child: const ChannelPage(),
),
);
}
@@ -73,11 +90,12 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
children: const <Widget>[
Expanded(
child: MessageListView(),
),
@@ -5,20 +5,29 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Second step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// Most chat applications handle more than just one single conversation.
/// Apps like Facebook Messenger, Whatsapp and Telegram allows you to have multiple one to one and group conversations.
/// Apps like Facebook Messenger, Whatsapp and Telegram allows you to have
/// multiple one-to-one and group conversations.
///
/// Lets find out how we can change our application chat screen to display the list of conversations and navigate between them.
/// Lets find out how we can change our application chat screen to display
/// the list of conversations and navigate between them.
///
/// > Note: the SDK uses Flutters [Navigator] to move from one route to another, this allows us to avoid any boiler-plate code.
/// > Of course you can take total control of how navigation works by customizing widgets like [Channel] and [ChannelList].
/// > Note: the SDK uses Flutters [Navigator] to move from one route to
/// another. This allows us to avoid any boiler-plate code.
/// > Of course, you can take total control of how navigation works by
/// customizing widgets like [Channel] and [ChannelList].
///
/// If you run the application, you will see that the first screen shows a list of conversations, you can open each by tapping and go back to the list.
/// If you run the application, you will see that the first screen shows a
/// list of conversations, you can open each by tapping and go back to the list.
///
/// Every single widget involved in this UI can be customized or swapped with your own.
/// Every single widget involved in this UI can be customized or swapped
/// with your own.
///
/// The [ChannelListPage] widget retrieves the list of channels based on a custom query and ordering.
/// In this case we are showing the list of channels the current user is a member and we order them based on the time they had a new message.
/// [ChannelListView] handles pagination and updates automatically out of the box when new channels are created or when a new message is added to a channel.
/// The [ChannelListPage] widget retrieves the list of channels based on a
/// 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
/// on the time they had a new message. [ChannelListView] handles pagination
/// and updates automatically when new channels are created or when a new
/// message is added to a channel.
void main() async {
final client = StreamChatClient(
's2dxdhpxd94g',
@@ -27,31 +36,44 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
final StreamChatClient client;
MyApp(this.client);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: ChannelListPage(),
home: const ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
@@ -60,11 +82,11 @@ class ChannelListPage extends StatelessWidget {
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
sort: const [SortOption('last_message_at')],
pagination: const PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
channelWidget: const ChannelPage(),
),
),
);
@@ -77,11 +99,12 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
children: const <Widget>[
Expanded(
child: MessageListView(),
),
@@ -6,22 +6,30 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Third step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// So far youve learned how to use the default widgets.
/// The library has been designed with composition in mind and to allow all common customizations to be very easy.
/// This means that you can change any component in your application by swapping the default widgets with the ones you build yourself.
/// The library has been designed with composition in mind and to allow all
/// common customizations to be very easy.
/// This means that you can change any component in your application by
/// swapping the default widgets with the ones you build yourself.
///
/// Lets see how we can make some changes to the SDKs UI components.
/// We start by changing how channel previews are shown in the channel list and include the number of unread messages for each.
/// We start by changing how channel previews are shown in the channel list
/// and include the number of unread messages for each.
///
/// We're passing a custom widget to [ChannelListView.channelPreviewBuilder], this will override the default [ChannelPreview] and allows you to create one yourself.
/// We're passing a custom widget to [ChannelListView.channelPreviewBuilder];
/// this will override the default [ChannelPreview] and allows you to create
/// one yourself.
///
/// There are a couple interesting things we do in this widget:
///
/// - Instead of creating a whole new style for the channel name, we inherit the text style from the parent theme ([StreamChatTheme.of]) and only change the color attribute
/// - Instead of creating a whole new style for the channel name, we inherit
/// the text style from the parent theme ([StreamChatTheme.of]) and only
/// change the color attribute
///
/// - We loop over the list of channel messages to search for the first not deleted message ([Channel.state.messages])
/// - We loop over the list of channel messages to search for the first not
/// deleted message ([Channel.state.messages])
///
/// - We retrieve the count of unread messages from [Channel.state]
void main() async {
Future<void> main() async {
final client = StreamChatClient(
's2dxdhpxd94g',
logLevel: Level.INFO,
@@ -29,31 +37,44 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
final StreamChatClient client;
MyApp(this.client);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: ChannelListPage(),
home: const ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
@@ -64,10 +85,10 @@ class ChannelListPage extends StatelessWidget {
),
channelPreviewBuilder: _channelPreviewBuilder,
// sort: [SortOption('last_message_at')],
pagination: PaginationParams(
pagination: const PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
channelWidget: const ChannelPage(),
),
),
);
@@ -78,7 +99,7 @@ class ChannelListPage extends StatelessWidget {
(message) => !message.isDeleted,
);
final subtitle = (lastMessage == null ? 'nothing yet' : lastMessage.text!);
final subtitle = lastMessage == null ? 'nothing yet' : lastMessage.text!;
final opacity = (channel.state?.unreadCount ?? 0) > 0 ? 1.0 : 0.5;
return ListTile(
@@ -88,7 +109,7 @@ class ChannelListPage extends StatelessWidget {
MaterialPageRoute(
builder: (_) => StreamChannel(
channel: channel,
child: ChannelPage(),
child: const ChannelPage(),
),
),
);
@@ -111,7 +132,7 @@ class ChannelListPage extends StatelessWidget {
radius: 10,
child: Text(channel.state!.unreadCount.toString()),
)
: SizedBox(),
: const SizedBox(),
);
}
}
@@ -122,11 +143,12 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
children: const <Widget>[
Expanded(
child: MessageListView(),
),
@@ -4,13 +4,17 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Fourth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// Stream Chat supports message threads out of the box. Threads allows users to create sub-conversations inside the same channel.
/// Stream Chat supports message threads out of the box. Threads allows users
/// to create sub-conversations inside the same channel.
///
/// Using threaded conversations is very simple and mostly a matter of plugging the [MessageListView] to another widget that renders the widget.
/// To make this simple, such a widget only needs to build [MessageListView] with the parent attribute set to the threads root message.
/// Using threaded conversations is very simple and mostly a matter of
/// plugging the [MessageListView] to another widget that renders the widget.
/// To make this simple, such a widget only needs to build [MessageListView]
/// 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 message you can tap on Reply and it will open the same [ThreadPage].
void main() async {
/// Now we can open threads and create new ones as well. If you long-press a
/// message, you can tap on "Reply" and it will open the same [ThreadPage].
Future<void> main() async {
final client = StreamChatClient(
's2dxdhpxd94g',
logLevel: Level.INFO,
@@ -18,33 +22,44 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
final StreamChatClient client;
MyApp(this.client);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: Container(
child: ChannelListPage(),
),
home: const ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
@@ -53,11 +68,11 @@ class ChannelListPage extends StatelessWidget {
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
sort: const [SortOption('last_message_at')],
pagination: const PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
channelWidget: const ChannelPage(),
),
),
);
@@ -70,21 +85,20 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
Expanded(
child: MessageListView(
threadBuilder: (_, parentMessage) {
return ThreadPage(
parent: parentMessage,
);
},
threadBuilder: (_, parentMessage) => ThreadPage(
parent: parentMessage,
),
),
),
MessageInput(),
const MessageInput(),
],
),
);
@@ -92,14 +106,15 @@ class ChannelPage extends StatelessWidget {
}
class ThreadPage extends StatelessWidget {
final Message? parent;
ThreadPage({
const ThreadPage({
Key? key,
this.parent,
}) : super(key: key);
final Message? parent;
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ThreadHeader(
@@ -4,18 +4,23 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Fifth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// Customizing how messages are rendered is another very common use-case that the SDK supports easily.
/// Customizing how messages are rendered is another very common use-case that
/// the SDK supports easily.
///
/// Replace the built-in message component with your own is done by passing it as a builder function to the [MessageListView] widget.
/// Replacing the built-in message component with your own is done by passing
/// it as a builder function to the [MessageListView] widget.
///
/// The message builder function will get the usual [BuildContext] argument as well as the [Message] object and its position inside the list.
/// The message builder function will get the usual [BuildContext] argument
/// as well as the [Message] object and its position inside the list.
///
/// If you look at the code you can see that we use [StreamChat.of] to retrieve the current user so that we can style messages own messages in a different way.
/// If you look at the code you can see that we use [StreamChat.of] to
/// retrieve the current user so that we can style messages in a different way.
///
/// Since custom widgets and builders are always children of [StreamChat] or part of a [Channel],
/// you can use [StreamChat.of], [StreamChannel.of] and [StreamChatTheme.of] to use the API client directly
/// or to retrieve outer scope needed such as messages from the [Channel.state].
void main() async {
/// Since custom widgets and builders are always children of [StreamChat] or
/// part of a [Channel], you can use [StreamChat.of], [StreamChannel.of],
/// and [StreamChatTheme.of] to use the API client directly or to retrieve
/// outer scope needed such as messages from the [Channel.state].
Future<void> main() async {
final client = StreamChatClient(
's2dxdhpxd94g',
logLevel: Level.INFO,
@@ -23,31 +28,44 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
final StreamChatClient client;
MyApp(this.client);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => StreamChat(
client: client,
child: child,
),
home: ChannelListPage(),
home: const ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
@@ -56,11 +74,11 @@ class ChannelListPage extends StatelessWidget {
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
sort: const [SortOption('last_message_at')],
pagination: const PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
channelWidget: const ChannelPage(),
),
),
);
@@ -73,9 +91,10 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
Expanded(
@@ -83,7 +102,7 @@ class ChannelPage extends StatelessWidget {
messageBuilder: _messageBuilder,
),
),
MessageInput(),
const MessageInput(),
],
),
);
@@ -101,12 +120,14 @@ class ChannelPage extends StatelessWidget {
final color = isCurrentUser ? Colors.blueGrey : Colors.blue;
return Padding(
padding: EdgeInsets.all(5.0),
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: color, width: 1),
borderRadius: BorderRadius.all(
Radius.circular(5.0),
border: Border.all(
color: color,
),
borderRadius: const BorderRadius.all(
Radius.circular(5),
),
),
child: ListTile(
@@ -115,7 +136,7 @@ class ChannelPage extends StatelessWidget {
textAlign: textAlign,
),
subtitle: Text(
message.user!.extraData['name'] as String,
message.user!.name,
textAlign: textAlign,
),
),
@@ -4,22 +4,29 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Sixth step of the [tutorial](https://getstream.io/chat/flutter/tutorial/)
///
/// The Flutter SDK comes with a fully designed set of widgets which you can customize to fit with your application style and typography.
/// Changing the theme of Chat widgets works in a very similar way that [MaterialApp] and [Theme] do.
/// The Flutter SDK comes with a fully designed set of widgets which you can
/// customize to fit with your application style and typography.
/// Changing the theme of Chat widgets works in a very similar way that
/// [MaterialApp] and [Theme] do.
///
/// Out of the box all chat widgets use their own default styling, there are two ways to change the styling:
/// All chat widgets use their own default styling out of the box. There are
/// two ways to change the styling:
///
/// 1. Initialize the [StreamChatTheme] from your existing [MaterialApp] style
/// 2. Construct a custom theme and provide all the customizations needed
///
/// First we create a new Material [Theme] and pick [Colors.green] as swatch color. The theme is then passed to [MaterialApp] as usual.
/// First, we create a new Material [Theme] and pick [Colors.green] as the
/// swatch color. The theme is then passed to [MaterialApp] as usual.
///
/// Then we create a new [StreamChatTheme] from the green theme we just created.
/// After saving the app you will see the UI will update several widgets to match with the new color.
/// Then, we create a new [StreamChatTheme] from the green theme we just
/// created. After saving the app you will see that several widgets have
/// been updated with the new color.
///
/// We also change the message color posted by the current user.
/// You can perform these more granular style changes using [StreamChatTheme.copyWith].
void main() async {
///
/// You can perform these more granular style changes using
/// [StreamChatTheme.copyWith].
Future<void> main() async {
final client = StreamChatClient(
's2dxdhpxd94g',
logLevel: Level.INFO,
@@ -27,16 +34,23 @@ void main() async {
await client.connectUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
'''eyJ0eXAiO«iJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
);
runApp(MyApp(client));
runApp(
MyApp(
client: client,
),
);
}
class MyApp extends StatelessWidget {
final StreamChatClient client;
const MyApp({
Key? key,
required this.client,
}) : super(key: key);
MyApp(this.client);
final StreamChatClient client;
@override
Widget build(BuildContext context) {
@@ -62,20 +76,23 @@ class MyApp extends StatelessWidget {
return MaterialApp(
theme: themeData,
builder: (context, child) {
return StreamChat(
client: client,
streamChatThemeData: customTheme,
child: child,
);
},
home: ChannelListPage(),
builder: (context, child) => StreamChat(
client: client,
streamChatThemeData: customTheme,
child: child,
),
home: const ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
const ChannelListPage({
Key? key,
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
body: ChannelsBloc(
@@ -84,11 +101,11 @@ class ChannelListPage extends StatelessWidget {
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
sort: const [SortOption('last_message_at')],
pagination: const PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
channelWidget: const ChannelPage(),
),
),
);
@@ -101,21 +118,20 @@ class ChannelPage extends StatelessWidget {
}) : super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
appBar: const ChannelHeader(),
body: Column(
children: <Widget>[
Expanded(
child: MessageListView(
threadBuilder: (_, parentMessage) {
return ThreadPage(
parent: parentMessage,
);
},
threadBuilder: (_, parentMessage) => ThreadPage(
parent: parentMessage,
),
),
),
MessageInput(),
const MessageInput(),
],
),
);
@@ -123,14 +139,15 @@ class ChannelPage extends StatelessWidget {
}
class ThreadPage extends StatelessWidget {
final Message? parent;
ThreadPage({
const ThreadPage({
Key? key,
this.parent,
}) : super(key: key);
final Message? parent;
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: ThreadHeader(
@@ -21,21 +21,21 @@ environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
# stream_chat:
# path: ../../stream_chat
# stream_chat_flutter_core:
# path: ../../stream_chat_flutter_core
stream_chat_flutter:
path: ../
stream_chat_persistence:
path: ../../stream_chat_persistence
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
collection: ^1.15.0
cupertino_icons: ^1.0.3
flutter:
sdk: flutter
# stream_chat:
# path: ../../stream_chat
# stream_chat_flutter_core:
# path: ../../stream_chat_flutter_core
stream_chat_flutter:
path: ../
stream_chat_persistence:
path: ../../stream_chat_persistence
dev_dependencies:
flutter_test:
@@ -70,6 +70,7 @@ void main() {
StreamChat(
streamChatThemeData: theme,
client: client,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: StreamChannel(
showLoading: false,
channel: channel,
@@ -79,7 +80,6 @@ void main() {
),
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
),
surfaceSize: const Size.square(200),
@@ -123,6 +123,7 @@ void main() {
StreamChat(
streamChatThemeData: theme,
client: client,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: StreamChannel(
showLoading: false,
channel: channel,
@@ -132,7 +133,6 @@ void main() {
),
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
),
surfaceSize: const Size.square(200),
@@ -176,6 +176,7 @@ void main() {
StreamChat(
streamChatThemeData: theme,
client: client,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: StreamChannel(
showLoading: false,
channel: channel,
@@ -189,7 +190,6 @@ void main() {
),
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
),
surfaceSize: const Size.square(200),
@@ -54,12 +54,12 @@ void main() {
)
]));
when(() => channelState.typingEvents).thenAnswer((i) => {
User(id: 'other-user', extraData: {'name': 'demo'}):
User(id: 'other-user', extraData: const {'name': 'demo'}):
Event(type: EventType.typingStart),
});
when(() => channelState.typingEventsStream)
.thenAnswer((i) => Stream.value({
User(id: 'other-user', extraData: {'name': 'demo'}):
User(id: 'other-user', extraData: const {'name': 'demo'}):
Event(type: EventType.typingStart),
}));
@@ -14,7 +14,7 @@ void main() {
});
test(
'Light GalleryFooterThemeData lerps completely to dark GalleryFooterThemeData',
'''Light GalleryFooterThemeData lerps completely to dark GalleryFooterThemeData''',
() {
expect(
const GalleryFooterThemeData().lerp(_galleryFooterThemeDataControl,
@@ -23,7 +23,7 @@ void main() {
});
test(
'Light GalleryFooterThemeData lerps halfway to dark GalleryFooterThemeData',
'''Light GalleryFooterThemeData lerps halfway to dark GalleryFooterThemeData''',
() {
expect(
const GalleryFooterThemeData().lerp(_galleryFooterThemeDataControl,
@@ -32,7 +32,7 @@ void main() {
});
test(
'Dark GalleryFooterThemeData lerps completely to light GalleryFooterThemeData',
'''Dark GalleryFooterThemeData lerps completely to light GalleryFooterThemeData''',
() {
expect(
const GalleryFooterThemeData().lerp(_galleryFooterThemeDataControlDark,
@@ -14,7 +14,7 @@ void main() {
});
test(
'Light GalleryHeaderThemeData lerps completely to dark GalleryHeaderThemeData',
'''Light GalleryHeaderThemeData lerps completely to dark GalleryHeaderThemeData''',
() {
expect(
const GalleryHeaderThemeData().lerp(_galleryHeaderThemeDataControl,
@@ -23,7 +23,7 @@ void main() {
});
test(
'Light GalleryHeaderThemeData lerps halfway to dark GalleryHeaderThemeData',
'''Light GalleryHeaderThemeData lerps halfway to dark GalleryHeaderThemeData''',
() {
expect(
const GalleryHeaderThemeData().lerp(_galleryHeaderThemeDataControl,
@@ -32,7 +32,7 @@ void main() {
});
test(
'Dark GalleryHeaderThemeData lerps completely to light GalleryHeaderThemeData',
'''Dark GalleryHeaderThemeData lerps completely to light GalleryHeaderThemeData''',
() {
expect(
const GalleryHeaderThemeData().lerp(_galleryHeaderThemeDataDarkControl,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -79,7 +79,8 @@ void main() {
'name': 'test',
});
final messageText = '''a message.
const messageText = '''
a message.
with multiple lines
and a list:
- a. okasd
@@ -47,6 +47,7 @@ void main() {
StreamChat(
client: client,
streamChatThemeData: theme,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: SizedBox(
child: ReactionBubble(
reactions: [
@@ -60,7 +61,6 @@ void main() {
maskColor: theme.ownMessageTheme.reactionsMaskColor!,
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
surfaceSize: const Size(100, 100),
);
@@ -83,6 +83,7 @@ void main() {
StreamChat(
client: client,
streamChatThemeData: StreamChatThemeData.fromTheme(themeData),
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: Container(
color: Colors.black,
child: ReactionBubble(
@@ -97,7 +98,6 @@ void main() {
maskColor: theme.ownMessageTheme.reactionsMaskColor!,
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
surfaceSize: const Size(100, 100),
);
@@ -89,6 +89,7 @@ void main() {
)(
StreamChat(
client: client,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: StreamChannel(
showLoading: false,
channel: channel,
@@ -100,7 +101,6 @@ void main() {
),
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
),
surfaceSize: const Size.square(200),
@@ -141,6 +141,7 @@ void main() {
)(
StreamChat(
client: client,
connectivityStream: Stream.value(ConnectivityResult.mobile),
child: StreamChannel(
showLoading: false,
channel: channel,
@@ -152,7 +153,6 @@ void main() {
),
),
),
connectivityStream: Stream.value(ConnectivityResult.mobile),
),
),
surfaceSize: const Size.square(200),
@@ -54,12 +54,12 @@ void main() {
]));
when(() => channelState.typingEvents).thenAnswer((i) => {
User(id: 'other-user', extraData: {'name': 'demo'}):
User(id: 'other-user', extraData: const {'name': 'demo'}):
Event(type: EventType.typingStart),
});
when(() => channelState.typingEventsStream)
.thenAnswer((i) => Stream.value({
User(id: 'other-user', extraData: {'name': 'demo'}):
User(id: 'other-user', extraData: const {'name': 'demo'}):
Event(type: EventType.typingStart),
}));