update example using new client
This commit is contained in:
@@ -9,24 +9,36 @@ void main() async {
|
|||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
final channelClient = client.channel('messaging', id: 'godevs');
|
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
channelClient.watch();
|
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
StreamChat(
|
StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: StreamChannel(
|
home: ChannelListPage(),
|
||||||
channelClient: channelClient,
|
|
||||||
child: ChannelPage(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ChannelListPage extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: ChannelListView(
|
||||||
|
filter: {
|
||||||
|
'members': {
|
||||||
|
'\$in': [StreamChat.of(context).user.id],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort: [SortOption('last_message_at')],
|
||||||
|
pagination: PaginationParams(
|
||||||
|
limit: 20,
|
||||||
|
),
|
||||||
|
channelWidget: ChannelPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key key,
|
Key key,
|
||||||
@@ -39,22 +51,7 @@ class ChannelPage extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: MessageListView(
|
||||||
messageBuilder: (context, message, _) {
|
messageBuilder: _messageBuilder,
|
||||||
final isCurrentUser =
|
|
||||||
StreamChat.of(context).user.id == message.user.id;
|
|
||||||
final textAlign =
|
|
||||||
isCurrentUser ? TextAlign.right : TextAlign.left;
|
|
||||||
return ListTile(
|
|
||||||
title: Text(
|
|
||||||
message.text,
|
|
||||||
textAlign: textAlign,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
message.user.extraData['name'],
|
|
||||||
textAlign: textAlign,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MessageInput(),
|
MessageInput(),
|
||||||
@@ -62,4 +59,19 @@ class ChannelPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _messageBuilder(context, message, _) {
|
||||||
|
final isCurrentUser = StreamChat.of(context).user.id == message.user.id;
|
||||||
|
final textAlign = isCurrentUser ? TextAlign.right : TextAlign.left;
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
message.text,
|
||||||
|
textAlign: textAlign,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
message.user.extraData['name'],
|
||||||
|
textAlign: textAlign,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,25 +27,9 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
filter: {
|
filter: {
|
||||||
'members': {
|
'members': {
|
||||||
'\$in': [StreamChat.of(context).user.id],
|
'\$in': [StreamChat.of(context).user.id],
|
||||||
}
|
},
|
||||||
},
|
|
||||||
channelPreviewBuilder: (context, channelClient) {
|
|
||||||
final channelState = channelClient.state.channelState;
|
|
||||||
return ListTile(
|
|
||||||
leading: ChannelAvatar(
|
|
||||||
channel: channelState.channel,
|
|
||||||
),
|
|
||||||
title: ChannelName(
|
|
||||||
channel: channelState.channel,
|
|
||||||
),
|
|
||||||
trailing: channelClient.state.unreadCount > 0
|
|
||||||
? CircleAvatar(
|
|
||||||
radius: 10,
|
|
||||||
child: Text(channelClient.state.unreadCount.toString()),
|
|
||||||
)
|
|
||||||
: SizedBox(),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
channelPreviewBuilder: _channelPreviewBuilder,
|
||||||
sort: [SortOption('last_message_at')],
|
sort: [SortOption('last_message_at')],
|
||||||
pagination: PaginationParams(
|
pagination: PaginationParams(
|
||||||
limit: 20,
|
limit: 20,
|
||||||
@@ -54,6 +38,23 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _channelPreviewBuilder(BuildContext context, Channel channel) {
|
||||||
|
return ListTile(
|
||||||
|
leading: ChannelImage(
|
||||||
|
channel: channel,
|
||||||
|
),
|
||||||
|
title: ChannelName(
|
||||||
|
channel: channel,
|
||||||
|
),
|
||||||
|
trailing: channel.state.unreadCount > 0
|
||||||
|
? CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
child: Text(channel.state.unreadCount.toString()),
|
||||||
|
)
|
||||||
|
: SizedBox(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final client = Client('qk4nn7rpcn75', logLevel: Level.INFO);
|
final client = Client('qk4nn7rpcn75');
|
||||||
|
|
||||||
await client.setUser(
|
await client.setUser(
|
||||||
User(id: 'wild-breeze-7'),
|
User(id: 'wild-breeze-7'),
|
||||||
|
|||||||
@@ -2,24 +2,27 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final client = Client('qk4nn7rpcn75');
|
final client = Client(
|
||||||
|
'qk4nn7rpcn75',
|
||||||
|
logLevel: Level.INFO,
|
||||||
|
);
|
||||||
|
|
||||||
await client.setUser(
|
await client.setUser(
|
||||||
User(id: 'wild-breeze-7'),
|
User(id: 'wild-breeze-7'),
|
||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
final channelClient = client.channel('messaging', id: 'godevs');
|
final channel = client.channel('messaging', id: 'godevs');
|
||||||
|
|
||||||
// ignore: unawaited_futures
|
// ignore: unawaited_futures
|
||||||
channelClient.watch();
|
channel.watch();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
StreamChat(
|
StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: StreamChannel(
|
home: StreamChannel(
|
||||||
channelClient: channelClient,
|
channel: channel,
|
||||||
child: ChannelPage(),
|
child: ChannelPage(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ class ChannelPage extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: MessageListView(
|
||||||
threadBuilder: (_, message) {
|
threadBuilder: (_, parentMessage) {
|
||||||
return ThreadPage(
|
return ThreadPage(
|
||||||
parent: message,
|
parent: parentMessage,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ class ChannelImage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
radius: radius,
|
radius: radius,
|
||||||
backgroundImage: channel.extraData.containsKey('image')
|
backgroundImage: channel.extraData?.containsKey('image') ?? false
|
||||||
? CachedNetworkImageProvider(channel.extraData['image'])
|
? CachedNetworkImageProvider(channel.extraData['image'])
|
||||||
: null,
|
: null,
|
||||||
child: channel.extraData.containsKey('image')
|
child: channel.extraData?.containsKey('image') ?? false
|
||||||
? null
|
? null
|
||||||
: Text(channel.extraData.containsKey('name')
|
: Text(channel.extraData?.containsKey('name') ?? false
|
||||||
? channel.extraData['name'][0]
|
? channel.extraData['name'][0]
|
||||||
: ''),
|
: ''),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
import 'channel_preview.dart';
|
import 'channel_preview.dart';
|
||||||
import 'stream_channel.dart';
|
import 'stream_channel.dart';
|
||||||
import 'stream_chat.dart';
|
import 'stream_chat.dart';
|
||||||
|
|
||||||
typedef ChannelTapCallback = void Function(ChannelClient, Widget);
|
typedef ChannelTapCallback = void Function(Channel, Widget);
|
||||||
typedef ChannelPreviewBuilder = Widget Function(BuildContext, ChannelClient);
|
typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel);
|
||||||
|
|
||||||
class ChannelListView extends StatefulWidget {
|
class ChannelListView extends StatefulWidget {
|
||||||
ChannelListView({
|
ChannelListView({
|
||||||
@@ -47,7 +48,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
options: widget.options,
|
options: widget.options,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: StreamBuilder<List<ChannelState>>(
|
child: StreamBuilder<List<Channel>>(
|
||||||
stream: streamChat.channelsStream,
|
stream: streamChat.channelsStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
@@ -63,19 +64,19 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final channelsStates = snapshot.data;
|
final channels = snapshot.data;
|
||||||
return ListView.custom(
|
return ListView.custom(
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
controller: widget._scrollController,
|
controller: widget._scrollController,
|
||||||
childrenDelegate: SliverChildBuilderDelegate(
|
childrenDelegate: SliverChildBuilderDelegate(
|
||||||
(context, i) {
|
(context, i) {
|
||||||
return _itemBuilder(context, i, channelsStates);
|
return _itemBuilder(context, i, channels);
|
||||||
},
|
},
|
||||||
childCount: (channelsStates.length * 2) + 1,
|
childCount: (channels.length * 2) + 1,
|
||||||
findChildIndexCallback: (key) {
|
findChildIndexCallback: (key) {
|
||||||
final ValueKey<String> valueKey = key;
|
final ValueKey<String> valueKey = key;
|
||||||
final index = channelsStates.indexWhere(
|
final index = channels.indexWhere(
|
||||||
(cs) => 'CHANNEL-${cs.channel.id}' == valueKey.value);
|
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
|
||||||
return index != -1 ? (index * 2) : null;
|
return index != -1 ? (index * 2) : null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -84,7 +85,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _itemBuilder(context, int i, List<ChannelState> channelsStates) {
|
Widget _itemBuilder(context, int i, List<Channel> channels) {
|
||||||
if (i % 2 != 0) {
|
if (i % 2 != 0) {
|
||||||
return _separatorBuilder(context, i);
|
return _separatorBuilder(context, i);
|
||||||
}
|
}
|
||||||
@@ -92,11 +93,10 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
i = i ~/ 2;
|
i = i ~/ 2;
|
||||||
|
|
||||||
final streamChat = StreamChat.of(context);
|
final streamChat = StreamChat.of(context);
|
||||||
if (i < channelsStates.length) {
|
if (i < channels.length) {
|
||||||
final channelState = channelsStates[i];
|
final channel = channels[i];
|
||||||
|
|
||||||
final channelClient =
|
final channelClient = streamChat.client.channelClients[channel.id];
|
||||||
streamChat.client.channelClients[channelState.channel.id];
|
|
||||||
|
|
||||||
ChannelTapCallback onTap;
|
ChannelTapCallback onTap;
|
||||||
if (widget.onChannelTap != null) {
|
if (widget.onChannelTap != null) {
|
||||||
@@ -109,7 +109,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
builder: (context) {
|
builder: (context) {
|
||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
child: widget.channelWidget,
|
child: widget.channelWidget,
|
||||||
channelClient: client,
|
channel: client,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -119,12 +119,11 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
|
|
||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
key: ValueKey<String>('CHANNEL-${channelClient.id}'),
|
key: ValueKey<String>('CHANNEL-${channelClient.id}'),
|
||||||
child: StreamBuilder<ChannelState>(
|
channel: channelClient,
|
||||||
initialData: channelClient.state.channelState,
|
child: StreamBuilder<DateTime>(
|
||||||
stream: channelClient.state.channelStateStream,
|
initialData: channelClient.updatedAt,
|
||||||
|
stream: channelClient.updatedAtStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final channelState = snapshot.data;
|
|
||||||
|
|
||||||
Widget child;
|
Widget child;
|
||||||
if (widget.channelPreviewBuilder != null) {
|
if (widget.channelPreviewBuilder != null) {
|
||||||
child = Stack(
|
child = Stack(
|
||||||
@@ -147,17 +146,15 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
child = ChannelPreview(
|
child = ChannelPreview(
|
||||||
channelClient: channelClient,
|
channel: channelClient,
|
||||||
onTap: (channelClient) {
|
onTap: (channelClient) {
|
||||||
onTap(channelClient, widget.channelWidget);
|
onTap(channelClient, widget.channelWidget);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
channelClient: channelClient,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return _buildQueryProgressIndicator(context, streamChat);
|
return _buildQueryProgressIndicator(context, streamChat);
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ class ChannelName extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
channel.extraData['name'] as String ?? channel.cid,
|
channel?.extraData != null
|
||||||
|
? (channel?.extraData['name'] ?? channel.cid)
|
||||||
|
: channel.cid,
|
||||||
style: Theme.of(context).textTheme.body2,
|
style: Theme.of(context).textTheme.body2,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,39 +3,37 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
import 'channel_image.dart';
|
import '../stream_chat_flutter.dart';
|
||||||
import 'channel_name.dart';
|
import 'channel_name.dart';
|
||||||
|
|
||||||
class ChannelPreview extends StatelessWidget {
|
class ChannelPreview extends StatelessWidget {
|
||||||
final void Function(ChannelClient) onTap;
|
final void Function(Channel) onTap;
|
||||||
final ChannelState channelState;
|
final Channel channel;
|
||||||
final ChannelClient channelClient;
|
|
||||||
|
|
||||||
ChannelPreview({
|
ChannelPreview({
|
||||||
@required this.channelClient,
|
@required this.channel,
|
||||||
Key key,
|
Key key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
}) : channelState = channelClient.state.channelState,
|
}) : super(key: key);
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
onTap(channelClient);
|
onTap(channel);
|
||||||
},
|
},
|
||||||
leading: ChannelImage(
|
leading: ChannelImage(
|
||||||
channel: channelState.channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
title: ChannelName(
|
title: ChannelName(
|
||||||
channel: channelState.channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
subtitle: _buildSubtitle(),
|
subtitle: _buildSubtitle(),
|
||||||
trailing: Column(
|
trailing: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_buildDate(context, channelState.channel.lastMessageAt),
|
_buildDate(context, channel.lastMessageAt),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -64,11 +62,11 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _buildSubtitle() {
|
Widget _buildSubtitle() {
|
||||||
return StreamBuilder<List<User>>(
|
return StreamBuilder<List<User>>(
|
||||||
stream: channelClient.state.typingEventsStream,
|
stream: channel.state.typingEventsStream,
|
||||||
initialData: [],
|
initialData: [],
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final typings = snapshot.data;
|
final typings = snapshot.data;
|
||||||
final opacity = channelClient.state.unreadCount > .0 ? 1.0 : 0.5;
|
final opacity = channel.state.unreadCount > .0 ? 1.0 : 0.5;
|
||||||
return typings.isNotEmpty
|
return typings.isNotEmpty
|
||||||
? _buildTypings(typings, context, opacity)
|
? _buildTypings(typings, context, opacity)
|
||||||
: _buildLastMessage(context, opacity);
|
: _buildLastMessage(context, opacity);
|
||||||
@@ -77,7 +75,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _buildLastMessage(BuildContext context, double opacity) {
|
Widget _buildLastMessage(BuildContext context, double opacity) {
|
||||||
final lastMessage =
|
final lastMessage =
|
||||||
channelState.messages.isNotEmpty ? channelState.messages.last : null;
|
channel.state.messages.isNotEmpty ? channel.state.messages.last : null;
|
||||||
if (lastMessage == null) {
|
if (lastMessage == null) {
|
||||||
return SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
},
|
},
|
||||||
controller: _textController,
|
controller: _textController,
|
||||||
onChanged: (s) {
|
onChanged: (s) {
|
||||||
StreamChannel.of(context).channelClient.keyStroke();
|
StreamChannel.of(context).channel.keyStroke();
|
||||||
setState(() {
|
setState(() {
|
||||||
_messageIsPresent = s.trim().isNotEmpty;
|
_messageIsPresent = s.trim().isNotEmpty;
|
||||||
});
|
});
|
||||||
@@ -121,7 +121,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
|
||||||
StreamChannel.of(context)
|
StreamChannel.of(context)
|
||||||
.channelClient
|
.channel
|
||||||
.sendMessage(
|
.sendMessage(
|
||||||
Message(
|
Message(
|
||||||
parentId: widget.parent?.id,
|
parentId: widget.parent?.id,
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
if (widget.parentMessage != null) {
|
if (widget.parentMessage != null) {
|
||||||
if (widget.parentMessageBuilder != null) {
|
if (widget.parentMessageBuilder != null) {
|
||||||
return widget.parentMessageBuilder(
|
return widget.parentMessageBuilder(
|
||||||
context, widget.parentMessage);
|
context,
|
||||||
|
widget.parentMessage,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -104,10 +106,6 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
}
|
}
|
||||||
final message = _messages[i];
|
final message = _messages[i];
|
||||||
|
|
||||||
if (widget.messageBuilder != null) {
|
|
||||||
return widget.messageBuilder(context, message, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
final previousMessage =
|
final previousMessage =
|
||||||
i < _messages.length - 1 ? _messages[i + 1] : null;
|
i < _messages.length - 1 ? _messages[i + 1] : null;
|
||||||
final nextMessage = i > 0 ? _messages[i - 1] : null;
|
final nextMessage = i > 0 ? _messages[i - 1] : null;
|
||||||
@@ -130,6 +128,13 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (widget.messageBuilder != null) {
|
||||||
|
return Builder(
|
||||||
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
|
builder: (_) => widget.messageBuilder(context, message, i),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return MessageWidget(
|
return MessageWidget(
|
||||||
key: ValueKey<String>('MESSAGE-${message.id}'),
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
previousMessage: previousMessage,
|
previousMessage: previousMessage,
|
||||||
@@ -182,15 +187,25 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
StreamChannelState streamChannelState,
|
StreamChannelState streamChannelState,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
return VisibilityDetector(
|
Widget messageWidget;
|
||||||
key: ValueKey<String>('TOP-MESSAGE'),
|
if (widget.messageBuilder != null) {
|
||||||
child: MessageWidget(
|
messageWidget = Builder(
|
||||||
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
|
builder: (_) => widget.messageBuilder(context, message, 0),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
messageWidget = MessageWidget(
|
||||||
key: ValueKey<String>('MESSAGE-${message.id}'),
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
previousMessage: null,
|
previousMessage: null,
|
||||||
message: message,
|
message: message,
|
||||||
nextMessage: nextMessage,
|
nextMessage: nextMessage,
|
||||||
onThreadTap: _onThreadTap,
|
onThreadTap: _onThreadTap,
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return VisibilityDetector(
|
||||||
|
key: ValueKey<String>('TOP-MESSAGE'),
|
||||||
|
child: messageWidget,
|
||||||
onVisibilityChanged: (visibility) {
|
onVisibilityChanged: (visibility) {
|
||||||
final topIsVisible = visibility.visibleBounds != Rect.zero;
|
final topIsVisible = visibility.visibleBounds != Rect.zero;
|
||||||
if (topIsVisible && !_topWasVisible) {
|
if (topIsVisible && !_topWasVisible) {
|
||||||
@@ -207,23 +222,33 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
Message message,
|
Message message,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
return VisibilityDetector(
|
Widget messageWidget;
|
||||||
key: ValueKey<String>('BOTTOM-MESSAGE'),
|
if (widget.messageBuilder != null) {
|
||||||
onVisibilityChanged: (visibility) {
|
messageWidget = Builder(
|
||||||
_isBottom = visibility.visibleBounds != Rect.zero;
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
if (_isBottom) {
|
builder: (_) => widget.messageBuilder(context, message, 0),
|
||||||
if (channelBloc.channelClient.state.unreadCount > 0) {
|
);
|
||||||
channelBloc.channelClient.markRead();
|
} else {
|
||||||
}
|
messageWidget = MessageWidget(
|
||||||
}
|
|
||||||
},
|
|
||||||
child: MessageWidget(
|
|
||||||
key: ValueKey<String>('MESSAGE-${message.id}'),
|
key: ValueKey<String>('MESSAGE-${message.id}'),
|
||||||
previousMessage: previousMessage,
|
previousMessage: previousMessage,
|
||||||
message: message,
|
message: message,
|
||||||
nextMessage: null,
|
nextMessage: null,
|
||||||
onThreadTap: _onThreadTap,
|
onThreadTap: _onThreadTap,
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return VisibilityDetector(
|
||||||
|
key: ValueKey<String>('BOTTOM-MESSAGE'),
|
||||||
|
onVisibilityChanged: (visibility) {
|
||||||
|
_isBottom = visibility.visibleBounds != Rect.zero;
|
||||||
|
if (_isBottom) {
|
||||||
|
if (channelBloc.channel.state.unreadCount > 0) {
|
||||||
|
channelBloc.channel.markRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: messageWidget,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,17 +259,17 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
final streamChannel = StreamChannel.of(context);
|
final streamChannel = StreamChannel.of(context);
|
||||||
if (streamChannel.channelClient.state.unreadCount > 0) {
|
if (streamChannel.channel.state.unreadCount > 0) {
|
||||||
streamChannel.channelClient.markRead();
|
streamChannel.channel.markRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<Message>> stream;
|
Stream<List<Message>> stream;
|
||||||
|
|
||||||
if (widget.parentMessage == null) {
|
if (widget.parentMessage == null) {
|
||||||
stream = streamChannel.channelStateStream.map((c) => c.messages);
|
stream = streamChannel.channel.state.messagesStream;
|
||||||
} else {
|
} else {
|
||||||
streamChannel.getReplies(widget.parentMessage.id);
|
streamChannel.getReplies(widget.parentMessage.id);
|
||||||
stream = streamChannel.channelClient.state.threadsStream
|
stream = streamChannel.channel.state.threadsStream
|
||||||
.where((threads) => threads.containsKey(widget.parentMessage.id))
|
.where((threads) => threads.containsKey(widget.parentMessage.id))
|
||||||
.map((threads) => threads[widget.parentMessage.id]);
|
.map((threads) => threads[widget.parentMessage.id]);
|
||||||
}
|
}
|
||||||
@@ -258,7 +283,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
_messages = newMessages;
|
_messages = newMessages;
|
||||||
});
|
});
|
||||||
} else if (newMessages.first.user.id ==
|
} else if (newMessages.first.user.id ==
|
||||||
streamChannel.channelClient.client.state.user.id) {
|
streamChannel.channel.client.state.user.id) {
|
||||||
_scrollController.jumpTo(0);
|
_scrollController.jumpTo(0);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -293,7 +318,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (_) {
|
MaterialPageRoute(builder: (_) {
|
||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
channelClient: StreamChannel.of(context).channelClient,
|
channel: StreamChannel.of(context).channel,
|
||||||
child: widget.threadBuilder(context, message),
|
child: widget.threadBuilder(context, message),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
|
|
||||||
void sendReaction(String reactionType) {
|
void sendReaction(String reactionType) {
|
||||||
StreamChannel.of(context)
|
StreamChannel.of(context)
|
||||||
.channelClient
|
.channel
|
||||||
.sendReaction(widget.message.id, reactionType);
|
.sendReaction(widget.message.id, reactionType);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-15
@@ -8,13 +8,13 @@ class StreamChannel extends StatefulWidget {
|
|||||||
StreamChannel({
|
StreamChannel({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.child,
|
@required this.child,
|
||||||
@required this.channelClient,
|
@required this.channel,
|
||||||
}) : super(
|
}) : super(
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final ChannelClient channelClient;
|
final Channel channel;
|
||||||
|
|
||||||
static StreamChannelState of(BuildContext context) {
|
static StreamChannelState of(BuildContext context) {
|
||||||
StreamChannelState streamChannelState;
|
StreamChannelState streamChannelState;
|
||||||
@@ -36,12 +36,10 @@ class StreamChannel extends StatefulWidget {
|
|||||||
class StreamChannelState extends State<StreamChannel> {
|
class StreamChannelState extends State<StreamChannel> {
|
||||||
StreamChannelState();
|
StreamChannelState();
|
||||||
|
|
||||||
ChannelClient get channelClient => widget.channelClient;
|
Channel get channel => widget.channel;
|
||||||
|
|
||||||
ChannelState get channelState => widget.channelClient.state.channelState;
|
|
||||||
|
|
||||||
Stream<ChannelState> get channelStateStream =>
|
Stream<ChannelState> get channelStateStream =>
|
||||||
widget.channelClient.state.channelStateStream;
|
widget.channel.state.channelStateStream;
|
||||||
|
|
||||||
final BehaviorSubject<bool> _queryMessageController = BehaviorSubject();
|
final BehaviorSubject<bool> _queryMessageController = BehaviorSubject();
|
||||||
|
|
||||||
@@ -51,11 +49,11 @@ class StreamChannelState extends State<StreamChannel> {
|
|||||||
_queryMessageController.add(true);
|
_queryMessageController.add(true);
|
||||||
|
|
||||||
String firstId;
|
String firstId;
|
||||||
if (channelState.messages.isNotEmpty) {
|
if (channel.state.messages.isNotEmpty) {
|
||||||
firstId = channelState.messages.first.id;
|
firstId = channel.state.messages.first.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
widget.channelClient
|
widget.channel
|
||||||
.query(
|
.query(
|
||||||
messagesPagination: PaginationParams(
|
messagesPagination: PaginationParams(
|
||||||
lessThan: firstId,
|
lessThan: firstId,
|
||||||
@@ -73,11 +71,11 @@ class StreamChannelState extends State<StreamChannel> {
|
|||||||
_queryMessageController.add(true);
|
_queryMessageController.add(true);
|
||||||
|
|
||||||
String firstId;
|
String firstId;
|
||||||
if (widget.channelClient.state.threads.containsKey(parentId)) {
|
if (widget.channel.state.threads.containsKey(parentId)) {
|
||||||
firstId = widget.channelClient.state.threads[parentId].first.id;
|
firstId = widget.channel.state.threads[parentId].first.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return widget.channelClient
|
return widget.channel
|
||||||
.getReplies(
|
.getReplies(
|
||||||
parentId,
|
parentId,
|
||||||
PaginationParams(
|
PaginationParams(
|
||||||
@@ -100,14 +98,14 @@ class StreamChannelState extends State<StreamChannel> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.channelClient == null) {
|
if (widget.channel == null) {
|
||||||
return Center(
|
return Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return FutureBuilder<bool>(
|
return FutureBuilder<bool>(
|
||||||
future: widget.channelClient.initialized,
|
future: widget.channel.initialized,
|
||||||
initialData: widget.channelClient.state != null,
|
initialData: widget.channel.state != null,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData || !snapshot.data) {
|
if (!snapshot.hasData || !snapshot.data) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class StreamChat extends InheritedWidget {
|
|||||||
child: child,
|
child: child,
|
||||||
) {
|
) {
|
||||||
_subscriptions.add(client.on('message.new').listen((Event e) {
|
_subscriptions.add(client.on('message.new').listen((Event e) {
|
||||||
final index = channels.indexWhere((c) => c.channel.cid == e.cid);
|
final index = channels.indexWhere((c) => c.cid == e.cid);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final channel = channels.removeAt(index);
|
final channel = channels.removeAt(index);
|
||||||
channels.insert(0, channel);
|
channels.insert(0, channel);
|
||||||
@@ -31,10 +31,9 @@ class StreamChat extends InheritedWidget {
|
|||||||
|
|
||||||
Stream<User> get userStream => client.state.userStream;
|
Stream<User> get userStream => client.state.userStream;
|
||||||
|
|
||||||
Stream<List<ChannelState>> get channelsStream => _channelsController.stream;
|
Stream<List<Channel>> get channelsStream => _channelsController.stream;
|
||||||
final BehaviorSubject<List<ChannelState>> _channelsController =
|
final BehaviorSubject<List<Channel>> _channelsController = BehaviorSubject();
|
||||||
BehaviorSubject();
|
final List<Channel> channels = [];
|
||||||
final List<ChannelState> channels = [];
|
|
||||||
|
|
||||||
final BehaviorSubject<bool> _queryChannelsLoadingController =
|
final BehaviorSubject<bool> _queryChannelsLoadingController =
|
||||||
BehaviorSubject.seeded(false);
|
BehaviorSubject.seeded(false);
|
||||||
@@ -60,7 +59,7 @@ class StreamChat extends InheritedWidget {
|
|||||||
options: options,
|
options: options,
|
||||||
paginationParams: paginationParams,
|
paginationParams: paginationParams,
|
||||||
);
|
);
|
||||||
channels.addAll(res.map((c) => c.state.channelState));
|
channels.addAll(res);
|
||||||
_channelsController.sink.add(channels);
|
_channelsController.sink.add(channels);
|
||||||
_queryChannelsLoadingController.sink.add(false);
|
_queryChannelsLoadingController.sink.add(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export 'package:stream_chat/stream_chat.dart';
|
export 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
export 'src/channel_avatar.dart';
|
export 'src/channel_image.dart';
|
||||||
export 'src/channel_list_view.dart';
|
export 'src/channel_list_view.dart';
|
||||||
export 'src/channel_name.dart';
|
export 'src/channel_name.dart';
|
||||||
export 'src/channel_preview.dart';
|
export 'src/channel_preview.dart';
|
||||||
|
|||||||
+2
-1
@@ -19,7 +19,8 @@ dependencies:
|
|||||||
video_player: ^0.10.7
|
video_player: ^0.10.7
|
||||||
chewie: ^0.9.8+1
|
chewie: ^0.9.8+1
|
||||||
animations: ^1.0.0+3
|
animations: ^1.0.0+3
|
||||||
stream_chat: ^0.1.6
|
stream_chat:
|
||||||
|
path: ../stream_chat_dart
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
pedantic: ^1.8.0+1
|
pedantic: ^1.8.0+1
|
||||||
|
|||||||
Reference in New Issue
Block a user