update example using new client

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