feat: Added gridview for channel list view and changed implementation for image sharing

This commit is contained in:
Deven Joshi
2020-12-22 17:45:08 +05:30
parent b0093dc065
commit 4aa2a8946a
5 changed files with 192 additions and 92 deletions
+6
View File
@@ -52,6 +52,7 @@ class ChannelImage extends StatelessWidget {
this.onTap, this.onTap,
this.showOnlineStatus = true, this.showOnlineStatus = true,
this.borderRadius, this.borderRadius,
this.selected = false,
}) : super(key: key); }) : super(key: key);
final BorderRadius borderRadius; final BorderRadius borderRadius;
@@ -67,6 +68,8 @@ class ChannelImage extends StatelessWidget {
final bool showOnlineStatus; final bool showOnlineStatus;
final bool selected;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final streamChat = StreamChat.of(context); final streamChat = StreamChat.of(context);
@@ -99,6 +102,7 @@ class ChannelImage extends StatelessWidget {
onTap(); onTap();
} }
: null, : null,
selected: selected,
); );
}); });
} else { } else {
@@ -111,12 +115,14 @@ class ChannelImage extends StatelessWidget {
.toList(); .toList();
return GroupImage( return GroupImage(
images: images, images: images,
borderRadius: borderRadius,
constraints: constraints ?? constraints: constraints ??
StreamChatTheme.of(context) StreamChatTheme.of(context)
.channelPreviewTheme .channelPreviewTheme
.avatarTheme .avatarTheme
.constraints, .constraints,
onTap: onTap, onTap: onTap,
selected: selected,
); );
} }
+61
View File
@@ -74,6 +74,8 @@ class ChannelListView extends StatefulWidget {
this.onStartChatPressed, this.onStartChatPressed,
this.swipeToAction = false, this.swipeToAction = false,
this.pullToRefresh = true, this.pullToRefresh = true,
this.crossAxisCount = 1,
this.selectedChannels = const [],
}) : super(key: key); }) : super(key: key);
/// The builder that will be used in case of error /// The builder that will be used in case of error
@@ -134,6 +136,11 @@ class ChannelListView extends StatefulWidget {
/// Callback used in the default empty list widget /// Callback used in the default empty list widget
final VoidCallback onStartChatPressed; final VoidCallback onStartChatPressed;
/// The number of children in the cross axis.
final int crossAxisCount;
final List<Channel> selectedChannels;
@override @override
_ChannelListViewState createState() => _ChannelListViewState(); _ChannelListViewState createState() => _ChannelListViewState();
} }
@@ -259,6 +266,18 @@ class _ChannelListViewState extends State<ChannelListView>
} }
if (channels.isNotEmpty) { if (channels.isNotEmpty) {
if (widget.crossAxisCount > 1) {
child = GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: widget.crossAxisCount),
itemCount: channels.length,
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
itemBuilder: (context, index) {
return _gridItemBuilder(context, index, channels);
},
);
} else {
child = ListView.custom( child = ListView.custom(
physics: AlwaysScrollableScrollPhysics(), physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController, controller: _scrollController,
@@ -277,6 +296,7 @@ class _ChannelListViewState extends State<ChannelListView>
); );
} }
} }
}
return AnimatedSwitcher( return AnimatedSwitcher(
child: child, child: child,
@@ -581,6 +601,47 @@ class _ChannelListViewState extends State<ChannelListView>
} }
} }
Widget _gridItemBuilder(BuildContext context, int i, List<Channel> channels) {
var channel = channels[i];
var selected = widget.selectedChannels.contains(channel);
return Container(
key: ValueKey<String>('CHANNEL-${channel.id}'),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ChannelImage(
channel: channel,
borderRadius: BorderRadius.circular(32),
selected: selected,
constraints: BoxConstraints.tightFor(
width: 64,
height: 64,
),
onTap: () {
widget.onChannelTap(channel, null);
},
),
SizedBox(height: 7),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: StreamChannel(
child: ChannelName(
textStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
channel: channel,
),
),
],
),
);
}
Widget _buildQueryProgressIndicator( Widget _buildQueryProgressIndicator(
context, context,
ChannelsBlocState channelsProvider, ChannelsBlocState channelsProvider,
+33 -2
View File
@@ -9,18 +9,30 @@ class GroupImage extends StatelessWidget {
@required this.images, @required this.images,
this.constraints, this.constraints,
this.onTap, this.onTap,
this.borderRadius,
this.selected = false,
this.selectionColor = const Color(0xFF006CFF),
this.selectionThickness = 4,
}) : super(key: key); }) : super(key: key);
final List<String> images; final List<String> images;
final BoxConstraints constraints; final BoxConstraints constraints;
final VoidCallback onTap; final VoidCallback onTap;
final bool selected;
final BorderRadius borderRadius;
final Color selectionColor;
final double selectionThickness;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( var avatar;
final streamChatTheme = StreamChatTheme.of(context);
avatar = GestureDetector(
onTap: onTap, onTap: onTap,
child: ClipRRect( child: ClipRRect(
borderRadius: StreamChatTheme.of(context) borderRadius: borderRadius ??
StreamChatTheme.of(context)
.ownMessageTheme .ownMessageTheme
.avatarTheme .avatarTheme
.borderRadius, .borderRadius,
@@ -91,5 +103,24 @@ class GroupImage extends StatelessWidget {
), ),
), ),
); );
if (selected) {
avatar = ClipRRect(
borderRadius: (borderRadius ??
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) +
BorderRadius.circular(selectionThickness),
child: Container(
color: selectionColor,
height: 64.0,
width: 64.0,
child: Padding(
padding: EdgeInsets.all(selectionThickness),
child: avatar,
),
),
);
}
return avatar;
} }
} }
+21 -22
View File
@@ -68,7 +68,7 @@ class _ImageFooterState extends State<ImageFooter> {
String _userNameQuery; String _userNameQuery;
bool _isSearchActive = false; bool _isSearchActive = false;
Set<User> _selectedUsers = {}; List<Channel> _selectedChannels = [];
bool _loading = false; bool _loading = false;
Timer _debounce; Timer _debounce;
@@ -278,22 +278,28 @@ class _ImageFooterState extends State<ImageFooter> {
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: false,
body: UsersBloc( body: UsersBloc(
child: Column( child: Column(
children: [ children: [
_buildTextInputSection(modalSetState), _buildTextInputSection(modalSetState),
if (_userSearchMode)
SizedBox(
height: 22.0,
),
Expanded( Expanded(
child: UserListView( child: ChannelsBloc(
selectedUsers: _selectedUsers, child: ChannelListView(
onUserTap: (user, _) { selectedChannels: _selectedChannels,
onChannelTap: (user, _) {
_searchController.clear(); _searchController.clear();
if (!_selectedUsers.contains(user)) { if (!_selectedChannels.contains(user)) {
modalSetState(() { modalSetState(() {
_selectedUsers.add(user); _selectedChannels.add(user);
}); });
} else { } else {
modalSetState(() { modalSetState(() {
_selectedUsers.remove(user); _selectedChannels.remove(user);
}); });
} }
}, },
@@ -323,7 +329,8 @@ class _ImageFooterState extends State<ImageFooter> {
physics: AlwaysScrollableScrollPhysics(), physics: AlwaysScrollableScrollPhysics(),
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight, minHeight:
viewportConstraints.maxHeight,
), ),
child: Center( child: Center(
child: Column( child: Column(
@@ -347,9 +354,10 @@ class _ImageFooterState extends State<ImageFooter> {
}, },
), ),
), ),
if (_selectedUsers.isNotEmpty) ),
if (_selectedChannels.isNotEmpty)
_buildShareTextInputSection(modalSetState), _buildShareTextInputSection(modalSetState),
if (!_userSearchMode && _selectedUsers.isEmpty) if (!_userSearchMode && _selectedChannels.isEmpty)
Align( Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Container( child: Container(
@@ -614,25 +622,16 @@ class _ImageFooterState extends State<ImageFooter> {
final client = StreamChat.of(context).client; final client = StreamChat.of(context).client;
for (var user in _selectedUsers) { for (var channel in _selectedChannels) {
var c = client.channel('messaging', extraData: {
'members': [
user.id,
StreamChat.of(context).user.id,
],
});
await c.watch();
final message = Message( final message = Message(
text: text, text: text,
attachments: [attachments[widget.currentPage]], attachments: [attachments[widget.currentPage]],
); );
await c.sendMessage(message); await channel.sendMessage(message);
} }
_selectedUsers.clear(); _selectedChannels.clear();
Navigator.pop(context); Navigator.pop(context);
} }
+3
View File
@@ -61,12 +61,15 @@ class UserAvatar extends StatelessWidget {
: streamChatTheme.defaultUserImage(context, user), : streamChatTheme.defaultUserImage(context, user),
), ),
); );
if (selected) { if (selected) {
avatar = ClipRRect( avatar = ClipRRect(
borderRadius: (borderRadius ?? borderRadius: (borderRadius ??
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) +
BorderRadius.circular(selectionThickness), BorderRadius.circular(selectionThickness),
child: Container( child: Container(
constraints: constraints ??
streamChatTheme.ownMessageTheme.avatarTheme.constraints,
color: selectionColor, color: selectionColor,
child: Padding( child: Padding(
padding: EdgeInsets.all(selectionThickness), padding: EdgeInsets.all(selectionThickness),