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:
@@ -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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+32
-14
@@ -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(),
|
||||
),
|
||||
+42
-19
@@ -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.
|
||||
///
|
||||
/// Let’s find out how we can change our application chat screen to display the list of conversations and navigate between them.
|
||||
/// Let’s find out how we can change our application chat screen to display
|
||||
/// the list of conversations and navigate between them.
|
||||
///
|
||||
/// > Note: the SDK uses Flutter’s [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 Flutter’s [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(),
|
||||
),
|
||||
+41
-19
@@ -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 you’ve 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.
|
||||
///
|
||||
/// Let’s see how we can make some changes to the SDK’s 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(),
|
||||
),
|
||||
+40
-25
@@ -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 thread’s 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 thread’s 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(
|
||||
+44
-23
@@ -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,
|
||||
),
|
||||
),
|
||||
+50
-33
@@ -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),
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user