rfac: Changed over group info screen to use streams

This commit is contained in:
Deven Joshi
2021-01-01 15:11:22 +05:30
parent dc643c0f71
commit b11543ea7f
2 changed files with 237 additions and 254 deletions
+237 -252
View File
@@ -16,12 +16,9 @@ class GroupInfoScreen extends StatefulWidget {
} }
class _GroupInfoScreenState extends State<GroupInfoScreen> { class _GroupInfoScreenState extends State<GroupInfoScreen> {
Future _memberQueryFuture;
TextEditingController _nameController; TextEditingController _nameController;
bool _userSearchMode = false;
TextEditingController _searchController; TextEditingController _searchController;
bool _loading = false;
String _userNameQuery = ''; String _userNameQuery = '';
Timer _debounce; Timer _debounce;
@@ -29,9 +26,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
final FocusNode _focusNode = FocusNode(); final FocusNode _focusNode = FocusNode();
bool namedChanged = false;
String changedName = '';
int groupMemberListLength; int groupMemberListLength;
void _userNameListener() { void _userNameListener() {
@@ -52,10 +46,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
void initState() { void initState() {
super.initState(); super.initState();
var channel = StreamChannel.of(context); var channel = StreamChannel.of(context);
_memberQueryFuture = channel.channel.queryMembers(
filter: {},
);
_nameController = TextEditingController.fromValue( _nameController = TextEditingController.fromValue(
TextEditingValue(text: channel.channel.extraData['name'] ?? '')); TextEditingValue(text: channel.channel.extraData['name'] ?? ''));
_searchController = TextEditingController()..addListener(_userNameListener); _searchController = TextEditingController()..addListener(_userNameListener);
@@ -69,50 +59,59 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var channel = StreamChannel.of(context); var channel = StreamChannel.of(context);
return Scaffold( return StreamBuilder<List<Member>>(
backgroundColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, stream: channel.channel.state.membersStream,
appBar: AppBar( builder: (context, snapshot) {
elevation: 1.0, if (!snapshot.hasData) {
toolbarHeight: 56.0, return Container(
backgroundColor: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
leading: InkWell( child: Center(child: CircularProgressIndicator()),
onTap: () { );
Navigator.pop(context); }
},
child: Padding( return Scaffold(
padding: const EdgeInsets.only(left: 12.0), backgroundColor:
child: StreamSvgIcon.left( StreamChatTheme.of(context).colorTheme.greyGainsboro,
color: StreamChatTheme.of(context).colorTheme.black, appBar: AppBar(
), elevation: 1.0,
), toolbarHeight: 56.0,
), backgroundColor: StreamChatTheme.of(context).colorTheme.white,
leadingWidth: 36.0, leading: InkWell(
title: Column( onTap: () {
children: [ Navigator.pop(context);
FutureBuilder<QueryMembersResponse>( },
future: _memberQueryFuture, child: Padding(
builder: (context, snapshot) { padding: const EdgeInsets.only(left: 12.0),
return Text( child: StreamSvgIcon.left(
_getChannelName(MediaQuery.of(context).size.width, color: StreamChatTheme.of(context).colorTheme.black,
members: snapshot.data?.members ),
?.map((e) => e.user) ),
?.toList()), ),
style: TextStyle( leadingWidth: 36.0,
color: StreamChatTheme.of(context).colorTheme.black, title: Column(
fontSize: 16, children: [
), StreamBuilder<ChannelState>(
maxLines: 1, stream: channel.channelStateStream,
overflow: TextOverflow.ellipsis, builder: (context, state) {
); return Text(
}), _getChannelName(
SizedBox( 2 * MediaQuery.of(context).size.width / 3,
height: 3.0, members: snapshot.data,
), extraData: state.data.channel.extraData,
FutureBuilder<QueryMembersResponse>( maxFontSize: 16.0),
future: _memberQueryFuture, style: TextStyle(
builder: (context, snapshot) { color: StreamChatTheme.of(context).colorTheme.black,
return Text( fontSize: 16,
'${channel.channel.memberCount} Members, ${snapshot?.data?.members?.where((e) => e.user.online)?.length ?? 0} Online', ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
}),
SizedBox(
height: 3.0,
),
Text(
'${channel.channel.memberCount} Members, ${snapshot?.data?.where((e) => e.user.online)?.length ?? 0} Online',
style: TextStyle( style: TextStyle(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
@@ -120,199 +119,178 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
.withOpacity(0.5), .withOpacity(0.5),
fontSize: 12.0, fontSize: 12.0,
), ),
); ),
}), ],
],
),
centerTitle: true,
actions: [
StreamNeumorphicButton(
child: InkWell(
onTap: () {
_buildAddUserModal(context);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StreamSvgIcon.userAdd(
color: StreamChatTheme.of(context).colorTheme.accentBlue),
), ),
), centerTitle: true,
), actions: [
], StreamNeumorphicButton(
),
body: ListView(
children: [
_buildMembers(),
Container(
height: 8.0,
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
),
_buildNameTile(),
_buildOptionListTiles(),
],
),
);
}
Widget _buildMembers() {
var channel = StreamChannel.of(context);
return FutureBuilder<QueryMembersResponse>(
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
),
);
}
groupMemberListLength ??=
snapshot.data.members.length > 6 ? 6 : snapshot.data.members.length;
return Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: groupMemberListLength,
itemBuilder: (context, position) {
return Material(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
var userMember = snapshot.data.members.firstWhere( _buildAddUserModal(context);
(e) => e.user.id == StreamChat.of(context).user.id);
_showUserInfoModal(snapshot.data.members[position].user,
userMember.role == 'owner');
}, },
child: Container( child: Padding(
height: 65.0, padding: const EdgeInsets.all(8.0),
child: Column( child: StreamSvgIcon.userAdd(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue),
),
),
),
],
),
body: ListView(
children: [
_buildMembers(snapshot.data),
Container(
height: 8.0,
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
),
_buildNameTile(),
_buildOptionListTiles(),
],
),
);
});
}
Widget _buildMembers(List<Member> members) {
groupMemberListLength ??= members.length > 6 ? 6 : members.length;
return Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: groupMemberListLength,
itemBuilder: (context, position) {
return Material(
child: InkWell(
onTap: () {
var userMember = members.firstWhere(
(e) => e.user.id == StreamChat.of(context).user.id);
_showUserInfoModal(
members[position].user, userMember.role == 'owner');
},
child: Container(
height: 65.0,
child: Column(
children: [
Row(
children: [ children: [
Row( Padding(
children: [ padding: const EdgeInsets.symmetric(
Padding( horizontal: 8.0, vertical: 12.0),
padding: const EdgeInsets.symmetric( child: UserAvatar(
horizontal: 8.0, vertical: 12.0), user: members[position].user,
child: UserAvatar( constraints: BoxConstraints(
user: snapshot.data.members[position].user, maxHeight: 40.0, maxWidth: 40.0),
constraints: BoxConstraints( ),
maxHeight: 40.0, maxWidth: 40.0), ),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
members[position].user.name,
style: TextStyle(fontWeight: FontWeight.bold),
), ),
), SizedBox(
Expanded( height: 1.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
snapshot.data.members[position].user.name,
style: TextStyle(
fontWeight: FontWeight.bold),
),
SizedBox(
height: 1.0,
),
Text(
_getLastSeen(
snapshot.data.members[position].user),
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5)),
),
],
), ),
), Text(
Padding( _getLastSeen(members[position].user),
padding: const EdgeInsets.all(8.0),
child: Text(
snapshot.data.members[position].role ==
'owner'
? 'Owner'
: '',
style: TextStyle( style: TextStyle(
color: StreamChatTheme.of(context) color: StreamChatTheme.of(context)
.colorTheme .colorTheme
.black .black
.withOpacity(0.5)), .withOpacity(0.5)),
), ),
), ],
], ),
), ),
Container( Padding(
height: 1.0, padding: const EdgeInsets.all(8.0),
color: StreamChatTheme.of(context) child: Text(
.colorTheme members[position].role == 'owner' ? 'Owner' : '',
.greyGainsboro, style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5)),
),
),
],
),
Container(
height: 1.0,
color: StreamChatTheme.of(context)
.colorTheme
.greyGainsboro,
),
],
),
),
),
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
);
},
),
if (groupMemberListLength != members.length)
InkWell(
onTap: () {
setState(() {
groupMemberListLength = members.length;
});
},
child: Material(
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
child: Container(
height: 65.0,
child: Column(
children: [
Expanded(
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 21.0, vertical: 12.0),
child: StreamSvgIcon.down(
color:
StreamChatTheme.of(context).colorTheme.white,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${members.length - groupMemberListLength} more',
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.grey),
),
],
),
), ),
], ],
), ),
), ),
), Container(
color: StreamChatTheme.of(context).colorTheme.white, height: 1.0,
); color:
}, StreamChatTheme.of(context).colorTheme.greyGainsboro,
),
if (groupMemberListLength != snapshot.data.members.length)
InkWell(
onTap: () {
setState(() {
groupMemberListLength = snapshot.data.members.length;
});
},
child: Material(
child: Container(
height: 65.0,
child: Column(
children: [
Expanded(
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 21.0, vertical: 12.0),
child: StreamSvgIcon.down(
color: StreamChatTheme.of(context)
.colorTheme
.grey,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${snapshot.data.members.length - groupMemberListLength} more',
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.grey),
),
],
),
),
],
),
),
Container(
height: 1.0,
color: StreamChatTheme.of(context)
.colorTheme
.greyGainsboro,
),
],
), ),
), ],
), ),
), ),
], ),
); ),
}, ],
future: _memberQueryFuture,
); );
} }
@@ -321,7 +299,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
var channelName = channel.extraData['name'] ?? ''; var channelName = channel.extraData['name'] ?? '';
return Material( return Material(
color: StreamChatTheme.of(context).colorTheme.white, color: StreamChatTheme.of(context).colorTheme.whiteSnow,
child: Container( child: Container(
height: 56.0, height: 56.0,
alignment: Alignment.center, alignment: Alignment.center,
@@ -389,12 +367,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
onTap: () { onTap: () {
StreamChannel.of(context).channel.update({ StreamChannel.of(context).channel.update({
'name': _nameController.text.trim(), 'name': _nameController.text.trim(),
}).then((value) {
setState(() {
_focusNode.unfocus();
namedChanged = true;
changedName = _nameController.text.trim();
});
}).catchError((err) { }).catchError((err) {
setState(() { setState(() {
_nameController.text = channelName; _nameController.text = channelName;
@@ -433,7 +405,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
stream: StreamChannel.of(context).channel.isMutedStream, stream: StreamChannel.of(context).channel.isMutedStream,
builder: (context, snapshot) { builder: (context, snapshot) {
return OptionListTile( return OptionListTile(
tileColor: StreamChatTheme.of(context).colorTheme.white, tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
separatorColor: separatorColor:
StreamChatTheme.of(context).colorTheme.greyGainsboro, StreamChatTheme.of(context).colorTheme.greyGainsboro,
title: 'Mute group', title: 'Mute group',
@@ -460,7 +432,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
); );
}), }),
OptionListTile( OptionListTile(
tileColor: StreamChatTheme.of(context).colorTheme.white, tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro,
title: 'Photos & Videos', title: 'Photos & Videos',
leading: StreamSvgIcon.pictures( leading: StreamSvgIcon.pictures(
@@ -494,7 +466,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
}, },
), ),
OptionListTile( OptionListTile(
tileColor: StreamChatTheme.of(context).colorTheme.white, tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro,
title: 'Files', title: 'Files',
leading: StreamSvgIcon.files( leading: StreamSvgIcon.files(
@@ -529,7 +501,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
), ),
if (!channel.channel.isDistinct) if (!channel.channel.isDistinct)
OptionListTile( OptionListTile(
tileColor: StreamChatTheme.of(context).colorTheme.white, tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
separatorColor: separatorColor:
StreamChatTheme.of(context).colorTheme.greyGainsboro, StreamChatTheme.of(context).colorTheme.greyGainsboro,
title: 'Leave Group', title: 'Leave Group',
@@ -582,9 +554,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
await channel.addMembers([user.id]); await channel.addMembers([user.id]);
Navigator.pop(context); Navigator.pop(context);
_memberQueryFuture = channel.queryMembers(
filter: {},
);
setState(() {}); setState(() {});
}, },
crossAxisCount: 4, crossAxisCount: 4,
@@ -852,9 +821,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
'Remove From Group', () async { 'Remove From Group', () async {
await channel.removeMembers([user.id]); await channel.removeMembers([user.id]);
Navigator.pop(context); Navigator.pop(context);
_memberQueryFuture = channel.queryMembers(
filter: {},
);
}, color: StreamChatTheme.of(context).colorTheme.accentRed), }, color: StreamChatTheme.of(context).colorTheme.accentRed),
_buildModalListTile( _buildModalListTile(
context, context,
@@ -971,17 +937,36 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
); );
} }
String _getChannelName(double width, {List<User> members}) { String _getChannelName(double width,
if (namedChanged) { {List<Member> members, Map extraData, double maxFontSize}) {
return changedName; String title;
} var client = StreamChat.of(context);
if (extraData['name'] == null) {
final otherMembers =
members.where((member) => member.user.id != client.user.id);
if (otherMembers.isNotEmpty) {
final maxWidth = width;
final maxChars = maxWidth / maxFontSize;
var currentChars = 0;
final currentMembers = <Member>[];
otherMembers.forEach((element) {
final newLength = currentChars + element.user.name.length;
if (newLength < maxChars) {
currentChars = newLength;
currentMembers.add(element);
}
});
if (StreamChannel.of(context).channel.extraData['name'] == null && final exceedingMembers = otherMembers.length - currentMembers.length;
members != null) { title =
return '${members[0].name} & ${members.length - 1} others'; '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}';
} else {
title = 'No title';
}
} else {
title = extraData['name'];
} }
return title;
return StreamChannel.of(context).channel.extraData['name'] ?? '';
} }
String _getLastSeen(User user) { String _getLastSeen(User user) {
-2
View File
@@ -423,8 +423,6 @@ class _ChannelListPageState extends State<ChannelListPage> {
), ),
); );
} }
// TODO: Add group screen
}, },
), ),
), ),