feat: user list

This commit is contained in:
xsahil03x
2020-11-17 23:32:16 +05:30
parent cd8ca90052
commit e5b25d8d06
5 changed files with 148 additions and 129 deletions
+13 -1
View File
@@ -464,7 +464,19 @@ class _NewChatScreenState extends State<NewChatScreen> {
style: TextStyle(color: Colors.black),
),
),
body: Container(),
body: UsersBloc(
child: UserListView(
pagination: PaginationParams(
limit: 25,
),
sort: [
SortOption(
'name',
direction: SortOption.ASC,
),
],
),
),
);
}
}
+69
View File
@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/user_list_view.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'stream_chat_theme.dart';
///
/// It shows the current [User] preview.
///
/// The widget uses a [StreamBuilder] to render the user information image as soon as it updates.
///
/// Usually you don't use this widget as it's the default user preview used by [UserListView].
///
/// The widget renders the ui based on the first ancestor of type [StreamChatTheme].
/// Modify it to change the widget appearance.
class UserItem extends StatelessWidget {
/// Instantiate a new UserItem
const UserItem(
{Key key,
@required this.user,
this.onTap,
this.onLongPress,
this.onImageTap})
: super(key: key);
/// Function called when tapping this widget
final void Function(User) onTap;
/// Function called when long pressing this widget
final void Function(User) onLongPress;
/// User displayed
final User user;
/// The function called when the image is tapped
final void Function(User) onImageTap;
@override
Widget build(BuildContext context) {
return ListTile(
onTap: () {
if (onTap != null) {
onTap(user);
}
},
onLongPress: () {
if (onLongPress != null) {
onLongPress(user);
}
},
leading: UserAvatar(
user: user,
showOnlineStatus: true,
onTap: (user) {
if (onImageTap != null) {
onImageTap(user);
}
}),
title: Text(user.name),
subtitle: _buildLastActive(context),
);
}
Widget _buildLastActive(context) {
return Text('Last seen ${Jiffy(user.lastActive).fromNow()}');
}
}
+65 -122
View File
@@ -1,11 +1,18 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/users_bloc.dart';
import 'stream_chat.dart';
import 'user_item.dart';
/// Callback called when tapping on a user
typedef UserTapCallback = void Function(User, Widget);
/// Builder used to create a custom [UserItem] from a [User]
typedef UserItemBuilder = Widget Function(BuildContext, User);
///
/// It shows the list of current users.
///
@@ -50,6 +57,7 @@ class UserListView extends StatefulWidget {
this.onUserTap,
this.onUserLongPress,
this.userWidget,
this.userItemBuilder,
this.separatorBuilder,
this.onImageTap,
this.swipeToAction = false,
@@ -99,8 +107,8 @@ class UserListView extends StatefulWidget {
/// Widget used when opening a channel
final Widget userWidget;
// /// Builder used to create a custom channel preview
// final ChannelPreviewBuilder channelPreviewBuilder;
/// Builder used to create a custom user preview
final UserItemBuilder userItemBuilder;
/// Builder used to create a custom item separator
final Function(BuildContext, int) separatorBuilder;
@@ -122,6 +130,21 @@ class _UserListViewState extends State<UserListView>
@override
void initState() {
super.initState();
final channelsBloc = UsersBloc.of(context);
channelsBloc.queryUsers(
filter: widget.filter,
sort: widget.sort,
pagination: widget.pagination,
options: widget.options,
);
_scrollController.addListener(() {
channelsBloc.queryUsersLoading.first.then((loading) {
if (!loading) {
_listenUserPagination(channelsBloc);
}
});
});
}
@override
@@ -263,8 +286,8 @@ class _UserListViewState extends State<UserListView>
childCount: (users.length * 2) + 1,
findChildIndexCallback: (key) {
final ValueKey<String> valueKey = key;
final index = users.indexWhere(
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
final index = users
.indexWhere((user) => 'USER-${user.id}' == valueKey.value);
return index != -1 ? (index * 2) : null;
},
),
@@ -306,125 +329,12 @@ class _UserListViewState extends State<UserListView>
};
}
return Container(
return UserItem(
key: ValueKey<String>('USER-${user.id}'),
child: Builder(
builder: (context) {
Widget child;
child = ListTile(
title: Text(user.name),
);
// if (widget.channelPreviewBuilder != null) {
// child = Stack(
// children: [
// widget.channelPreviewBuilder(
// context,
// channel,
// ),
// Positioned.fill(
// child: Material(
// color: Colors.transparent,
// child: InkWell(
// onTap: () {
// onTap(channel, widget.channelWidget);
// },
// ),
// ),
// ),
// ],
// );
// } else {
// final backgroundColor =
// Theme.of(context).brightness == Brightness.light
// ? Color(0xffEBEBEB)
// : Color(0xff141414);
// child = Slidable(
// enabled: widget.swipeToAction,
// actionPane: SlidableBehindActionPane(),
// actionExtentRatio: 0.12,
// closeOnScroll: true,
// secondaryActions: <Widget>[
// IconSlideAction(
// color: backgroundColor,
// icon: Icons.more_horiz,
// onTap: () {
// showModalBottomSheet(
// clipBehavior: Clip.hardEdge,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.only(
// topLeft: Radius.circular(32),
// topRight: Radius.circular(32),
// ),
// ),
// context: context,
// builder: (context) {
// return ChannelBottomSheet(channel: channel);
// },
// );
// },
// ),
// IconSlideAction(
// color: backgroundColor,
// icon: StreamIcons.mute,
// onTap: () async {
// if (!channel.isMuted) {
// await channel.mute();
// } else {
// await channel.unmute();
// }
// },
// ),
// if (channel.isGroup && !channel.isDistinct)
// IconSlideAction(
// color: backgroundColor,
// icon: StreamIcons.user_minus,
// onTap: () async {
// final confirm = await showConfirmationDialog(
// context,
// 'Do you want to leave the group?',
// );
// if (confirm == true) {
// await channel
// .removeMembers([StreamChat.of(context).user.id]);
// }
// },
// ),
// if (!channel.isGroup && !channel.isDistinct)
// IconSlideAction(
// color: backgroundColor,
// icon: Icons.delete_outline,
// onTap: () async {
// final confirm = await showConfirmationDialog(
// context,
// 'Do you want to delete the chat?',
// );
// if (confirm == true) {
// await channel
// .removeMembers([StreamChat.of(context).user.id]);
// }
// },
// ),
// ],
// child: Container(
// color: StreamChatTheme.of(context).backgroundColor,
// child: ChannelPreview(
// onLongPress: widget.onChannelLongPress,
// channel: channel,
// onImageTap: widget.onImageTap != null
// ? () {
// widget.onImageTap(channel);
// }
// : null,
// onTap: (channel) {
// onTap(channel, widget.userWidget);
// },
// ),
// ),
// );
// }
return child;
},
),
user: user,
onTap: (user) => onTap(user, widget.userWidget),
onLongPress: widget.onUserLongPress,
onImageTap: widget.onImageTap,
);
} else {
return _buildQueryProgressIndicator(context, usersProvider);
@@ -465,4 +375,37 @@ class _UserListViewState extends State<UserListView>
: Colors.black.withOpacity(0.1),
);
}
void _listenUserPagination(UsersBlocState usersProvider) {
if (_scrollController.position.maxScrollExtent ==
_scrollController.offset &&
_scrollController.offset != 0) {
usersProvider.queryUsers(
filter: widget.filter,
sort: widget.sort,
pagination: widget.pagination.copyWith(
offset: usersProvider.users?.length ?? 0,
),
options: widget.options,
);
}
}
@override
void didUpdateWidget(UserListView oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.filter?.toString() != oldWidget.filter?.toString() ||
jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) ||
widget.pagination?.toJson()?.toString() !=
oldWidget.pagination?.toJson()?.toString() ||
widget.options?.toString() != oldWidget.options?.toString()) {
final channelsBloc = UsersBloc.of(context);
channelsBloc.queryUsers(
filter: widget.filter,
sort: widget.sort,
pagination: widget.pagination,
options: widget.options,
);
}
}
}
-6
View File
@@ -90,12 +90,6 @@ class UsersBlocState extends State<UsersBloc>
}
}
@override
void initState() {
super.initState();
final client = StreamChat.of(context).client;
}
@override
Widget build(BuildContext context) {
super.build(context);
+1
View File
@@ -30,4 +30,5 @@ export 'src/typing_indicator.dart';
export 'src/user_avatar.dart';
export 'src/utils.dart';
export 'src/video_attachment.dart';
export 'src/users_bloc.dart';
export 'src/user_list_view.dart';