feat: Switched to UserListView

This commit is contained in:
Deven Joshi
2020-11-30 15:56:25 +05:30
parent 3d1ea5d588
commit 832e31cbc6
2 changed files with 124 additions and 214 deletions
+112 -214
View File
@@ -60,7 +60,7 @@ class _ImageFooterState extends State<ImageFooter> {
TextEditingController _searchController = TextEditingController(); TextEditingController _searchController = TextEditingController();
TextEditingController _messageController = TextEditingController(); TextEditingController _messageController = TextEditingController();
List<User> _selectedUsers = []; Set<User> _selectedUsers = {};
bool _loading = false; bool _loading = false;
@override @override
@@ -204,171 +204,93 @@ class _ImageFooterState extends State<ImageFooter> {
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return StreamChannel( return StatefulBuilder(builder: (context, modalSetState) {
channel: channel, return Padding(
child: Scaffold( padding: const EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0),
backgroundColor: Colors.transparent, child: Material(
body: StatefulBuilder(builder: (modalContext, modalSetState) { borderRadius: BorderRadius.only(
return Align( topLeft: Radius.circular(16.0),
alignment: _userSearchMode topRight: Radius.circular(16.0),
? Alignment.topCenter ),
: Alignment.bottomCenter, clipBehavior: Clip.antiAlias,
child: Material( child: Scaffold(
color: Colors.transparent, body: UsersBloc(
shape: RoundedRectangleBorder( child: Column(
borderRadius: BorderRadius.circular(16.0),
),
child: Stack(
children: [ children: [
ListView( _buildTextInputSection(modalSetState),
children: [ Expanded(
if (!_userSearchMode && child: UserListView(
MediaQuery.of(context).viewInsets.bottom == 0.0) selectedUsers: _selectedUsers,
GestureDetector( onUserTap: (user, _) {
child: Container( _searchController.clear();
height: if (!_selectedUsers.contains(user)) {
MediaQuery.of(modalContext).size.height / 2, modalSetState(() {
color: Colors.transparent, _selectedUsers.add(user);
), });
onTapUp: (val) { } else {
Navigator.pop(modalContext); modalSetState(() {
_selectedUsers.remove(user);
});
}
},
crossAxisCount: 3,
pagination: PaginationParams(
limit: 25,
),
filter: {
if (_searchController.text.isNotEmpty)
'name': {
r'$autocomplete': _searchController.text,
}, },
'id': {
r'$ne': StreamChat.of(context).user.id,
},
},
sort: [
SortOption(
'name',
direction: 1,
), ),
Container( ],
margin: EdgeInsets.symmetric( emptyBuilder: (_) {
horizontal: 8.0, return LayoutBuilder(
), builder: (context, viewportConstraints) {
padding: EdgeInsets.symmetric( return SingleChildScrollView(
vertical: 4.0, physics: AlwaysScrollableScrollPhysics(),
), child: ConstrainedBox(
decoration: BoxDecoration( constraints: BoxConstraints(
color: Colors.white, minHeight: viewportConstraints.maxHeight,
borderRadius: BorderRadius.only(
topRight: Radius.circular(16.0),
topLeft: Radius.circular(16.0),
)),
child: _buildTextInputSection(modalSetState),
),
Container(
margin: EdgeInsets.symmetric(
horizontal: 8.0,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(
_userSearchMode ? 16.0 : 0.0),
bottomLeft: Radius.circular(
_userSearchMode ? 16.0 : 0.0),
),
),
child: FutureBuilder<QueryUsersResponse>(
future: _userQuery,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
var filteredData =
snapshot.data.users.toList();
if (_userSearchMode &&
_searchController.text.length > 0) {
filteredData = snapshot.data.users
.where((element) => element.name
.toLowerCase()
.contains(_searchController.text
.toLowerCase()))
.toList();
}
return GridView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
var user = filteredData[position];
var isUserSelected =
_selectedUsers.contains(user);
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Stack(
children: [
CircleAvatar(
maxRadius: 32.0,
child: UserAvatar(
onTap: (user) {
if (isUserSelected) {
_selectedUsers
.remove(user);
} else {
_selectedUsers
.add(user);
}
modalSetState(() {});
},
user: user,
constraints:
BoxConstraints.tightFor(
height: isUserSelected
? 56
: 64,
width: isUserSelected
? 56
: 64,
),
borderRadius:
BorderRadius.circular(
32),
),
),
],
),
Padding(
padding:
const EdgeInsets.all(8.0),
child: Text(
user.name,
style: Theme.of(context)
.textTheme
.subtitle2,
textAlign: TextAlign.center,
maxLines: 2,
),
),
],
),
);
},
itemCount: filteredData.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 0.75,
), ),
); child: Center(
}), child: Column(
), children: [
], Padding(
padding: const EdgeInsets.all(24),
child: StreamSvgIcon.search(
size: 96,
color: Colors.grey,
),
),
Text(
'No user matches these keywords...'),
],
),
),
),
);
},
);
},
),
), ),
if (_selectedUsers.isNotEmpty)
_buildShareTextInputSection(modalSetState),
if (!_userSearchMode && _selectedUsers.isEmpty) if (!_userSearchMode && _selectedUsers.isEmpty)
Align( Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Container( child: Container(
color: Colors.white, color: Colors.white,
height: 48.0, height: 48.0,
margin: EdgeInsets.symmetric(
horizontal: 8.0,
),
child: Material( child: Material(
child: InkWell( child: InkWell(
onTap: () async { onTap: () async {
@@ -392,7 +314,7 @@ class _ImageFooterState extends State<ImageFooter> {
child: Text( child: Text(
'Save to Photos', 'Save to Photos',
style: TextStyle( style: TextStyle(
color: StreamChatTheme.of(modalContext) color: StreamChatTheme.of(context)
.accentColor, .accentColor,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -403,15 +325,13 @@ class _ImageFooterState extends State<ImageFooter> {
), ),
), ),
), ),
if (!_userSearchMode && _selectedUsers.isNotEmpty)
_buildShareTextInputSection(modalSetState),
], ],
), ),
), ),
); ),
}), ),
), );
); });
}, },
); );
} }
@@ -440,13 +360,14 @@ class _ImageFooterState extends State<ImageFooter> {
decoration: InputDecoration( decoration: InputDecoration(
isDense: true, isDense: true,
prefixIconConstraints: prefixIconConstraints:
BoxConstraints.tight(Size(38.0, 38.0)), BoxConstraints.tight(Size(36.0, 44.0)),
prefixIcon: Transform.scale( prefixIcon: Padding(
scale: 1.2, padding: const EdgeInsets.symmetric(
alignment: Alignment.center, vertical: 2.0, horizontal: 6.0),
child: StreamSvgIcon.search( child: StreamSvgIcon.search(
color: Colors.black, color: Colors.black,
)), ),
),
hintText: 'Search', hintText: 'Search',
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0), borderRadius: BorderRadius.circular(32.0),
@@ -512,10 +433,9 @@ class _ImageFooterState extends State<ImageFooter> {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0), padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: IconButton( child: IconButton(
icon: StreamSvgIcon.search( icon: StreamSvgIcon.share_arrow(
color: Colors.black, color: Colors.black,
), ),
iconSize: 24.0,
onPressed: () async { onPressed: () async {
var url = widget.urls[widget.currentPage].imageUrl ?? var url = widget.urls[widget.currentPage].imageUrl ??
widget.urls[widget.currentPage].assetUrl ?? widget.urls[widget.currentPage].assetUrl ??
@@ -580,54 +500,32 @@ class _ImageFooterState extends State<ImageFooter> {
), ),
), ),
), ),
AnimatedCrossFade( IconTheme(
crossFadeState: _messageController.text.isNotEmpty data: StreamChatTheme.of(context)
? CrossFadeState.showFirst .channelTheme
: CrossFadeState.showSecond, .messageInputButtonIconTheme,
firstChild: IconTheme( child: Center(
data: StreamChatTheme.of(context) child: Padding(
.channelTheme padding: const EdgeInsets.all(8.0),
.messageInputButtonIconTheme, child: InkWell(
child: Center( onTap: () async {
child: Padding( modalSetState(() {
padding: const EdgeInsets.all(8.0), _loading = true;
child: InkWell( });
onTap: () async { await sendMessage();
modalSetState(() { modalSetState(() {
_loading = true; _loading = false;
}); });
await sendMessage(); },
modalSetState(() { child: Transform.rotate(
_loading = false; angle: -pi / 2,
}); child: StreamSvgIcon.Icon_send_message(
}, color: StreamChatTheme.of(context).accentColor,
child: Transform.rotate(
angle: -pi / 2,
child: StreamSvgIcon.Icon_send_message(
color: StreamChatTheme.of(context).accentColor,
),
), ),
), ),
), ),
), ),
), ),
secondChild: IconTheme(
data: StreamChatTheme.of(context)
.channelTheme
.messageInputButtonIconTheme,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: InkWell(
onTap: () {},
child: StreamSvgIcon.Icon_send_message(
color: Colors.grey,
),
)),
),
),
duration: Duration(milliseconds: 300),
alignment: Alignment.center,
), ),
], ],
), ),
+12
View File
@@ -469,4 +469,16 @@ class StreamSvgIcon extends StatelessWidget {
height: size, height: size,
); );
} }
factory StreamSvgIcon.share_arrow({
double size,
Color color,
}) {
return StreamSvgIcon(
assetName: 'share_arrow.svg',
color: color,
width: size,
height: size,
);
}
} }