update lists
This commit is contained in:
@@ -264,6 +264,7 @@
|
|||||||
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
|
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
|
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
|
||||||
|
"${BUILT_PRODUCTS_DIR}/video_compress/video_compress.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework",
|
"${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework",
|
"${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
|
"${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework",
|
||||||
@@ -292,6 +293,7 @@
|
|||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
|
||||||
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_compress.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework",
|
||||||
|
|||||||
@@ -20,9 +20,21 @@ class ChannelList extends StatefulWidget {
|
|||||||
class _ChannelList extends State<ChannelList> {
|
class _ChannelList extends State<ChannelList> {
|
||||||
ScrollController _scrollController = ScrollController();
|
ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
TextEditingController? _controller;
|
late StreamMessageSearchListController _messageSearchListController =
|
||||||
|
StreamMessageSearchListController(
|
||||||
|
client: StreamChat.of(context).client,
|
||||||
|
filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]),
|
||||||
|
limit: 5,
|
||||||
|
searchQuery: '',
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'created_at',
|
||||||
|
direction: SortOption.ASC,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
String _channelQuery = '';
|
TextEditingController? _controller;
|
||||||
|
|
||||||
bool _isSearchActive = false;
|
bool _isSearchActive = false;
|
||||||
|
|
||||||
@@ -32,10 +44,11 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
||||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
_messageSearchListController.searchQuery = _controller!.text;
|
||||||
setState(() {
|
setState(() {
|
||||||
_channelQuery = _controller!.text;
|
_isSearchActive = _controller!.text.isNotEmpty;
|
||||||
_isSearchActive = _channelQuery.isNotEmpty;
|
|
||||||
});
|
});
|
||||||
|
if (_isSearchActive) _messageSearchListController.doInitialLoad();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -61,12 +74,12 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
_controller?.removeListener(_channelQueryListener);
|
_controller?.removeListener(_channelQueryListener);
|
||||||
_controller?.dispose();
|
_controller?.dispose();
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
|
_channelListController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final user = StreamChat.of(context).currentUser;
|
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
if (_isSearchActive) {
|
if (_isSearchActive) {
|
||||||
@@ -98,17 +111,7 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
],
|
],
|
||||||
body: _isSearchActive
|
body: _isSearchActive
|
||||||
? StreamMessageSearchListView(
|
? StreamMessageSearchListView(
|
||||||
showErrorTile: true,
|
controller: _messageSearchListController,
|
||||||
messageQuery: _channelQuery,
|
|
||||||
filters: Filter.in_('members', [user!.id]),
|
|
||||||
sortOptions: [
|
|
||||||
SortOption(
|
|
||||||
'created_at',
|
|
||||||
direction: SortOption.ASC,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
pullToRefresh: false,
|
|
||||||
limit: 30,
|
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, viewportConstraints) {
|
builder: (context, viewportConstraints) {
|
||||||
@@ -139,24 +142,34 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onItemTap: (messageResponse) async {
|
itemBuilder: (
|
||||||
FocusScope.of(context).requestFocus(FocusNode());
|
context,
|
||||||
final client = StreamChat.of(context).client;
|
messageResponses,
|
||||||
final message = messageResponse.message;
|
index,
|
||||||
final channel = client.channel(
|
defaultWidget,
|
||||||
messageResponse.channel!.type,
|
) {
|
||||||
id: messageResponse.channel!.id,
|
return defaultWidget.copyWith(
|
||||||
);
|
onTap: () async {
|
||||||
if (channel.state == null) {
|
final messageResponse = messageResponses[index];
|
||||||
await channel.watch();
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
}
|
final client = StreamChat.of(context).client;
|
||||||
Navigator.pushNamed(
|
final message = messageResponse.message;
|
||||||
context,
|
final channel = client.channel(
|
||||||
Routes.CHANNEL_PAGE,
|
messageResponse.channel!.type,
|
||||||
arguments: ChannelPageArgs(
|
id: messageResponse.channel!.id,
|
||||||
channel: channel,
|
);
|
||||||
initialMessage: message,
|
if (channel.state == null) {
|
||||||
),
|
await channel.watch();
|
||||||
|
}
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
Routes.CHANNEL_PAGE,
|
||||||
|
arguments: ChannelPageArgs(
|
||||||
|
channel: channel,
|
||||||
|
initialMessage: message,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -166,9 +179,10 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
onRefresh: _channelListController.refresh,
|
onRefresh: _channelListController.refresh,
|
||||||
child: StreamChannelListView(
|
child: StreamChannelListView(
|
||||||
controller: _channelListController,
|
controller: _channelListController,
|
||||||
itemBuilder: (context, channel, tile) {
|
itemBuilder: (context, channels, index, defaultWidget) {
|
||||||
final chatTheme = StreamChatTheme.of(context);
|
final chatTheme = StreamChatTheme.of(context);
|
||||||
final backgroundColor = chatTheme.colorTheme.inputBg;
|
final backgroundColor = chatTheme.colorTheme.inputBg;
|
||||||
|
final channel = channels[index];
|
||||||
final canDeleteChannel = channel.ownCapabilities
|
final canDeleteChannel = channel.ownCapabilities
|
||||||
.contains(PermissionType.deleteChannel);
|
.contains(PermissionType.deleteChannel);
|
||||||
return Slidable(
|
return Slidable(
|
||||||
@@ -249,7 +263,7 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: tile,
|
child: defaultWidget,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onChannelTap: (channel) {
|
onChannelTap: (channel) {
|
||||||
|
|||||||
@@ -704,6 +704,28 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
|
|||||||
|
|
||||||
void _buildAddUserModal(context) {
|
void _buildAddUserModal(context) {
|
||||||
var channel = StreamChannel.of(context).channel;
|
var channel = StreamChannel.of(context).channel;
|
||||||
|
final userListController = StreamUserListController(
|
||||||
|
client: channel.client,
|
||||||
|
limit: 25,
|
||||||
|
filter: Filter.and(
|
||||||
|
[
|
||||||
|
if (_searchController!.text.isNotEmpty)
|
||||||
|
Filter.autoComplete('name', _userNameQuery),
|
||||||
|
Filter.notIn('id', [
|
||||||
|
StreamChat.of(context).currentUser!.id,
|
||||||
|
...channel.state!.members
|
||||||
|
.map<String?>(((e) => e.userId))
|
||||||
|
.whereType<String>(),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
@@ -721,85 +743,63 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
|
|||||||
),
|
),
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: UsersBloc(
|
body: Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.all(16),
|
||||||
padding: const EdgeInsets.all(16),
|
child: _buildTextInputSection(modalSetState),
|
||||||
child: _buildTextInputSection(modalSetState),
|
),
|
||||||
),
|
Expanded(
|
||||||
Expanded(
|
child: StreamUserListView(
|
||||||
child: StreamUserListView(
|
controller: userListController,
|
||||||
selectedUsers: {},
|
onUserTap: (user) async {
|
||||||
onUserTap: (user, _) async {
|
_searchController!.clear();
|
||||||
_searchController!.clear();
|
|
||||||
|
|
||||||
await channel.addMembers([user.id]);
|
await channel.addMembers([user.id]);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
crossAxisCount: 4,
|
emptyBuilder: (_) {
|
||||||
limit: 25,
|
return LayoutBuilder(
|
||||||
filter: Filter.and(
|
builder: (context, viewportConstraints) {
|
||||||
[
|
return SingleChildScrollView(
|
||||||
if (_searchController!.text.isNotEmpty)
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
Filter.autoComplete('name', _userNameQuery),
|
child: ConstrainedBox(
|
||||||
Filter.notIn('id', [
|
constraints: BoxConstraints(
|
||||||
StreamChat.of(context).currentUser!.id,
|
minHeight: viewportConstraints.maxHeight,
|
||||||
...channel.state!.members
|
),
|
||||||
.map<String?>(((e) => e.userId))
|
child: Center(
|
||||||
.whereType<String>(),
|
child: Column(
|
||||||
]),
|
children: [
|
||||||
],
|
Padding(
|
||||||
),
|
padding: const EdgeInsets.all(24),
|
||||||
sort: [
|
child: StreamSvgIcon.search(
|
||||||
SortOption(
|
size: 96,
|
||||||
'name',
|
color: StreamChatTheme.of(context)
|
||||||
direction: 1,
|
.colorTheme
|
||||||
),
|
.textLowEmphasis,
|
||||||
],
|
|
||||||
emptyBuilder: (_) {
|
|
||||||
return LayoutBuilder(
|
|
||||||
builder: (context, viewportConstraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: viewportConstraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
child: StreamSvgIcon.search(
|
|
||||||
size: 96,
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.colorTheme
|
|
||||||
.textLowEmphasis,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Text(AppLocalizations.of(context)
|
),
|
||||||
.noUserMatchesTheseKeywords),
|
Text(AppLocalizations.of(context)
|
||||||
],
|
.noUserMatchesTheseKeywords),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
).then((_) => userListController.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTextInputSection(modalSetState) {
|
Widget _buildTextInputSection(modalSetState) {
|
||||||
|
|||||||
@@ -19,6 +19,20 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
|
|
||||||
late TextEditingController _controller;
|
late TextEditingController _controller;
|
||||||
|
|
||||||
|
late final userListController = StreamUserListController(
|
||||||
|
client: StreamChat.of(context).client,
|
||||||
|
limit: 25,
|
||||||
|
filter: Filter.and([
|
||||||
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
|
]),
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
ChipInputTextFieldState? get _chipInputTextFieldState =>
|
ChipInputTextFieldState? get _chipInputTextFieldState =>
|
||||||
_chipInputTextFieldStateKey.currentState;
|
_chipInputTextFieldStateKey.currentState;
|
||||||
|
|
||||||
@@ -45,6 +59,12 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
_userNameQuery = _controller.text;
|
_userNameQuery = _controller.text;
|
||||||
_isSearchActive = _userNameQuery.isNotEmpty;
|
_isSearchActive = _userNameQuery.isNotEmpty;
|
||||||
});
|
});
|
||||||
|
userListController.filter = Filter.and([
|
||||||
|
if (_userNameQuery.isNotEmpty)
|
||||||
|
Filter.autoComplete('name', _userNameQuery),
|
||||||
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
|
]);
|
||||||
|
userListController.doInitialLoad();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +132,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
_controller.clear();
|
_controller.clear();
|
||||||
_controller.removeListener(_userNameListener);
|
_controller.removeListener(_userNameListener);
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
userListController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,10 +310,10 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||||
child: UsersBloc(
|
child: UsersBloc(
|
||||||
child: StreamUserListView(
|
child: StreamUserListView(
|
||||||
selectedUsers: _selectedUsers,
|
controller: userListController,
|
||||||
groupAlphabetically:
|
// groupAlphabetically:
|
||||||
_isSearchActive ? false : true,
|
// _isSearchActive ? false : true,
|
||||||
onUserTap: (user, _) {
|
onUserTap: (user) {
|
||||||
_controller.clear();
|
_controller.clear();
|
||||||
if (!_selectedUsers.contains(user)) {
|
if (!_selectedUsers.contains(user)) {
|
||||||
_chipInputTextFieldState
|
_chipInputTextFieldState
|
||||||
@@ -302,19 +323,17 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
_chipInputTextFieldState!.removeItem(user);
|
_chipInputTextFieldState!.removeItem(user);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
limit: 25,
|
itemBuilder: (
|
||||||
filter: Filter.and([
|
context,
|
||||||
if (_userNameQuery.isNotEmpty)
|
users,
|
||||||
Filter.autoComplete('name', _userNameQuery),
|
index,
|
||||||
Filter.notEqual('id',
|
defaultWidget,
|
||||||
StreamChat.of(context).currentUser!.id),
|
) {
|
||||||
]),
|
return defaultWidget.copyWith(
|
||||||
sort: [
|
selected:
|
||||||
SortOption(
|
_selectedUsers.contains(users[index]),
|
||||||
'name',
|
);
|
||||||
direction: 1,
|
},
|
||||||
),
|
|
||||||
],
|
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, viewportConstraints) {
|
builder: (context, viewportConstraints) {
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
|
|
||||||
Timer? _debounce;
|
Timer? _debounce;
|
||||||
|
|
||||||
|
late final userListController = StreamUserListController(
|
||||||
|
client: StreamChat.of(context).client,
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
limit: 25,
|
||||||
|
filter: Filter.and([
|
||||||
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
void _userNameListener() {
|
void _userNameListener() {
|
||||||
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
||||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||||
@@ -31,6 +45,12 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
_userNameQuery = _controller!.text;
|
_userNameQuery = _controller!.text;
|
||||||
_isSearchActive = _userNameQuery.isNotEmpty;
|
_isSearchActive = _userNameQuery.isNotEmpty;
|
||||||
});
|
});
|
||||||
|
userListController.filter = Filter.and([
|
||||||
|
if (_userNameQuery.isNotEmpty)
|
||||||
|
Filter.autoComplete('name', _userNameQuery),
|
||||||
|
Filter.notEqual('id', StreamChat.of(context).currentUser!.id),
|
||||||
|
]);
|
||||||
|
userListController.doInitialLoad();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -46,6 +66,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
_controller?.clear();
|
_controller?.clear();
|
||||||
_controller?.removeListener(_userNameListener);
|
_controller?.removeListener(_userNameListener);
|
||||||
_controller?.dispose();
|
_controller?.dispose();
|
||||||
|
userListController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,77 +249,66 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||||
child: UsersBloc(
|
child: StreamUserListView(
|
||||||
child: StreamUserListView(
|
controller: userListController,
|
||||||
selectedUsers: _selectedUsers,
|
// groupAlphabetically: _isSearchActive ? false : true,
|
||||||
pullToRefresh: false,
|
itemBuilder: (context, items, index, defaultWidget) {
|
||||||
groupAlphabetically: _isSearchActive ? false : true,
|
return defaultWidget.copyWith(
|
||||||
onUserTap: (user, _) {
|
selected: _selectedUsers.contains(items[index]),
|
||||||
if (!_selectedUsers.contains(user)) {
|
);
|
||||||
setState(() {
|
},
|
||||||
_selectedUsers.add(user);
|
onUserTap: (user) {
|
||||||
});
|
if (!_selectedUsers.contains(user)) {
|
||||||
} else {
|
setState(() {
|
||||||
setState(() {
|
_selectedUsers.add(user);
|
||||||
_selectedUsers.remove(user);
|
});
|
||||||
});
|
} else {
|
||||||
}
|
setState(() {
|
||||||
},
|
_selectedUsers.remove(user);
|
||||||
limit: 25,
|
});
|
||||||
filter: Filter.and([
|
}
|
||||||
if (_userNameQuery.isNotEmpty)
|
},
|
||||||
Filter.autoComplete('name', _userNameQuery),
|
emptyBuilder: (_) {
|
||||||
Filter.notEqual(
|
return LayoutBuilder(
|
||||||
'id', StreamChat.of(context).currentUser!.id),
|
builder: (context, viewportConstraints) {
|
||||||
]),
|
return SingleChildScrollView(
|
||||||
sort: [
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
SortOption(
|
child: ConstrainedBox(
|
||||||
'name',
|
constraints: BoxConstraints(
|
||||||
direction: 1,
|
minHeight: viewportConstraints.maxHeight,
|
||||||
),
|
),
|
||||||
],
|
child: Center(
|
||||||
emptyBuilder: (_) {
|
child: Column(
|
||||||
return LayoutBuilder(
|
children: [
|
||||||
builder: (context, viewportConstraints) {
|
Padding(
|
||||||
return SingleChildScrollView(
|
padding: const EdgeInsets.all(24),
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
child: StreamSvgIcon.search(
|
||||||
child: ConstrainedBox(
|
size: 96,
|
||||||
constraints: BoxConstraints(
|
color: StreamChatTheme.of(context)
|
||||||
minHeight: viewportConstraints.maxHeight,
|
.colorTheme
|
||||||
),
|
.textLowEmphasis,
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
child: StreamSvgIcon.search(
|
|
||||||
size: 96,
|
|
||||||
color: StreamChatTheme.of(context)
|
|
||||||
.colorTheme
|
|
||||||
.textLowEmphasis,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
AppLocalizations.of(context)
|
Text(
|
||||||
.noUserMatchesTheseKeywords,
|
AppLocalizations.of(context)
|
||||||
style: StreamChatTheme.of(context)
|
.noUserMatchesTheseKeywords,
|
||||||
.textTheme
|
style: StreamChatTheme.of(context)
|
||||||
.footnote
|
.textTheme
|
||||||
.copyWith(
|
.footnote
|
||||||
color: StreamChatTheme.of(context)
|
.copyWith(
|
||||||
.colorTheme
|
color: StreamChatTheme.of(context)
|
||||||
.textLowEmphasis,
|
.colorTheme
|
||||||
),
|
.textLowEmphasis,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,85 +5,94 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
|
|
||||||
import 'channel_page.dart';
|
import 'channel_page.dart';
|
||||||
|
|
||||||
class UserMentionsPage extends StatelessWidget {
|
class UserMentionsPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<UserMentionsPage> createState() => _UserMentionsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserMentionsPageState extends State<UserMentionsPage> {
|
||||||
|
late final controller = StreamMessageSearchListController(
|
||||||
|
client: StreamChat.of(context).client,
|
||||||
|
filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]),
|
||||||
|
messageFilter: Filter.custom(
|
||||||
|
operator: r'$contains',
|
||||||
|
key: 'mentioned_users.id',
|
||||||
|
value: StreamChat.of(context).currentUser!.id,
|
||||||
|
),
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'created_at',
|
||||||
|
direction: SortOption.ASC,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
limit: 20,
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final user = StreamChat.of(context).currentUser!;
|
return StreamMessageSearchListView(
|
||||||
return MessageSearchBloc(
|
controller: controller,
|
||||||
child: StreamMessageSearchListView(
|
emptyBuilder: (_) {
|
||||||
filters: Filter.in_('members', [user.id]),
|
return LayoutBuilder(
|
||||||
messageFilters: Filter.custom(
|
builder: (context, viewportConstraints) {
|
||||||
operator: r'$contains',
|
return SingleChildScrollView(
|
||||||
key: 'mentioned_users.id',
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
value: user.id,
|
child: ConstrainedBox(
|
||||||
),
|
constraints: BoxConstraints(
|
||||||
sortOptions: [
|
minHeight: viewportConstraints.maxHeight,
|
||||||
SortOption(
|
),
|
||||||
'created_at',
|
child: Center(
|
||||||
direction: SortOption.ASC,
|
child: Column(
|
||||||
),
|
children: [
|
||||||
],
|
Padding(
|
||||||
limit: 20,
|
padding: const EdgeInsets.all(24),
|
||||||
showResultCount: false,
|
child: StreamSvgIcon.mentions(
|
||||||
emptyBuilder: (_) {
|
size: 96,
|
||||||
return LayoutBuilder(
|
color:
|
||||||
builder: (context, viewportConstraints) {
|
StreamChatTheme.of(context).colorTheme.disabled,
|
||||||
return SingleChildScrollView(
|
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: viewportConstraints.maxHeight,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
child: StreamSvgIcon.mentions(
|
|
||||||
size: 96,
|
|
||||||
color:
|
|
||||||
StreamChatTheme.of(context).colorTheme.disabled,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
AppLocalizations.of(context).noMentionsExistYet,
|
Text(
|
||||||
style: StreamChatTheme.of(context)
|
AppLocalizations.of(context).noMentionsExistYet,
|
||||||
.textTheme
|
style:
|
||||||
.body
|
StreamChatTheme.of(context).textTheme.body.copyWith(
|
||||||
.copyWith(
|
color: StreamChatTheme.of(context)
|
||||||
color: StreamChatTheme.of(context)
|
.colorTheme
|
||||||
.colorTheme
|
.textLowEmphasis,
|
||||||
.textLowEmphasis,
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
onItemTap: (messageResponse) async {
|
},
|
||||||
final client = StreamChat.of(context).client;
|
onMessageTap: (messageResponse) async {
|
||||||
final message = messageResponse.message;
|
final client = StreamChat.of(context).client;
|
||||||
final channel = client.channel(
|
final message = messageResponse.message;
|
||||||
messageResponse.channel!.type,
|
final channel = client.channel(
|
||||||
id: messageResponse.channel!.id,
|
messageResponse.channel!.type,
|
||||||
);
|
id: messageResponse.channel!.id,
|
||||||
if (channel.state == null) {
|
);
|
||||||
await channel.watch();
|
if (channel.state == null) {
|
||||||
}
|
await channel.watch();
|
||||||
Navigator.pushNamed(
|
}
|
||||||
context,
|
Navigator.pushNamed(
|
||||||
Routes.CHANNEL_PAGE,
|
context,
|
||||||
arguments: ChannelPageArgs(
|
Routes.CHANNEL_PAGE,
|
||||||
channel: channel,
|
arguments: ChannelPageArgs(
|
||||||
initialMessage: message,
|
channel: channel,
|
||||||
),
|
initialMessage: message,
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user