Merge pull request #197 from GetStream/feat/mention-screen
Add mention screen
This commit is contained in:
+101
-2
@@ -286,8 +286,75 @@ class _HomePageState extends State<HomePage> {
|
||||
class UserMentionPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Text('On Pause Right Now!'),
|
||||
final user = StreamChat.of(context).user;
|
||||
return MessageSearchBloc(
|
||||
child: MessageSearchListView(
|
||||
filters: {
|
||||
'members': {
|
||||
r'$in': [user.id],
|
||||
},
|
||||
},
|
||||
messageFilters: {
|
||||
'mentioned_users.id': {
|
||||
r'$contains': user.id,
|
||||
},
|
||||
},
|
||||
sortOptions: [
|
||||
SortOption(
|
||||
'created_at',
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
showResultCount: false,
|
||||
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.mentions(
|
||||
size: 96,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text('No mentions exist yet...'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onItemTap: (messageResponse) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = messageResponse.message;
|
||||
final channel = client.channel(
|
||||
messageResponse.channel.type,
|
||||
id: messageResponse.channel.id,
|
||||
);
|
||||
if (channel.state == null) {
|
||||
await channel.watch();
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.CHANNEL_PAGE,
|
||||
arguments: ChannelPageArgs(
|
||||
channel: channel,
|
||||
initialMessage: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -371,7 +438,39 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
||||
direction: SortOption.ASC,
|
||||
),
|
||||
],
|
||||
pullToRefresh: false,
|
||||
paginationParams: PaginationParams(limit: 20),
|
||||
emptyBuilder: (_, query) {
|
||||
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: Colors.grey,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'No results for \"$query\"...',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onItemTap: (messageResponse) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
final message = messageResponse.message;
|
||||
|
||||
@@ -52,7 +52,7 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
||||
Stream<bool> get queryMessagesLoading =>
|
||||
_queryMessagesLoadingController.stream;
|
||||
|
||||
/// Calls [Client.search] updating [queryMessagesLoading] stream
|
||||
/// Calls [Client.search] updating [messageResponses] stream
|
||||
Future<void> search({
|
||||
Map<String, dynamic> filter,
|
||||
Map<String, dynamic> messageFilter,
|
||||
@@ -60,10 +60,30 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
||||
String query,
|
||||
PaginationParams pagination,
|
||||
}) async {
|
||||
final client = StreamChat.of(context).client;
|
||||
_messageResponses.add(null);
|
||||
try {
|
||||
final messages = await _search(
|
||||
filter: filter,
|
||||
messageFilter: messageFilter,
|
||||
sort: sort,
|
||||
query: query,
|
||||
pagination: pagination,
|
||||
);
|
||||
_messageResponses.add(messages.results);
|
||||
} catch (err, stk) {
|
||||
_messageResponses.addError(err, stk);
|
||||
}
|
||||
}
|
||||
|
||||
if (client.state?.user == null ||
|
||||
_queryMessagesLoadingController.value == true) {
|
||||
/// Calls [Client.search] updating [queryMessagesLoading] stream
|
||||
Future<void> loadMore({
|
||||
Map<String, dynamic> filter,
|
||||
Map<String, dynamic> messageFilter,
|
||||
List<SortOption> sort,
|
||||
String query,
|
||||
PaginationParams pagination,
|
||||
}) async {
|
||||
if (_queryMessagesLoadingController.value == true) {
|
||||
return;
|
||||
}
|
||||
_queryMessagesLoadingController.add(true);
|
||||
@@ -74,18 +94,18 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
||||
|
||||
final oldMessages = List<GetMessageResponse>.from(messageResponses ?? []);
|
||||
|
||||
final messageResponse = await client.search(
|
||||
filter,
|
||||
sort,
|
||||
query,
|
||||
pagination,
|
||||
messageFilters: messageFilter,
|
||||
final messages = await _search(
|
||||
filter: filter,
|
||||
messageFilter: messageFilter,
|
||||
sort: sort,
|
||||
query: query,
|
||||
pagination: pagination,
|
||||
);
|
||||
|
||||
if (clear) {
|
||||
_messageResponses.add(messageResponse.results);
|
||||
_messageResponses.add(messages.results);
|
||||
} else {
|
||||
final temp = oldMessages + messageResponse.results;
|
||||
final temp = oldMessages + messages.results;
|
||||
_messageResponses.add(temp);
|
||||
}
|
||||
|
||||
@@ -95,6 +115,23 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
||||
}
|
||||
}
|
||||
|
||||
Future<SearchMessagesResponse> _search({
|
||||
Map<String, dynamic> filter,
|
||||
Map<String, dynamic> messageFilter,
|
||||
List<SortOption> sort,
|
||||
String query,
|
||||
PaginationParams pagination,
|
||||
}) {
|
||||
final client = StreamChat.of(context).client;
|
||||
return client.search(
|
||||
filter,
|
||||
sort,
|
||||
query,
|
||||
pagination,
|
||||
messageFilters: messageFilter,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
|
||||
@@ -51,16 +51,18 @@ class MessageSearchListView extends StatefulWidget {
|
||||
/// Instantiate a new MessageSearchListView
|
||||
const MessageSearchListView({
|
||||
Key key,
|
||||
@required this.messageQuery,
|
||||
@required this.filters,
|
||||
this.messageQuery,
|
||||
this.filters,
|
||||
this.sortOptions,
|
||||
this.paginationParams,
|
||||
this.messageFilters,
|
||||
this.emptyBuilder,
|
||||
this.errorBuilder,
|
||||
this.separatorBuilder,
|
||||
this.itemBuilder,
|
||||
this.onItemTap,
|
||||
this.showResultCount = true,
|
||||
this.pullToRefresh = true,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Message String to search on
|
||||
@@ -83,6 +85,11 @@ class MessageSearchListView extends StatefulWidget {
|
||||
/// message_limit: how many messages should be included to each channel
|
||||
final PaginationParams paginationParams;
|
||||
|
||||
/// The message query filters to use.
|
||||
/// You can query on any of the custom fields you've defined on the [Channel].
|
||||
/// You can also filter other built-in channel fields.
|
||||
final Map<String, dynamic> messageFilters;
|
||||
|
||||
/// Builder used to create a custom item preview
|
||||
final MessageSearchItemBuilder itemBuilder;
|
||||
|
||||
@@ -101,6 +108,9 @@ class MessageSearchListView extends StatefulWidget {
|
||||
/// Set it to false to hide total results text
|
||||
final bool showResultCount;
|
||||
|
||||
/// Set it to false to disable the pull-to-refresh widget
|
||||
final bool pullToRefresh;
|
||||
|
||||
@override
|
||||
_MessageSearchListViewState createState() => _MessageSearchListViewState();
|
||||
}
|
||||
@@ -115,6 +125,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
sort: widget.sortOptions,
|
||||
query: widget.messageQuery,
|
||||
pagination: widget.paginationParams,
|
||||
messageFilter: widget.messageFilters,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,9 +138,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
Widget _separatorBuilder(BuildContext context, int index) {
|
||||
return Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1)
|
||||
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1),
|
||||
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -205,9 +214,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
),
|
||||
padding: const EdgeInsets.only(right: 2.0),
|
||||
child: Icon(Icons.error_outline),
|
||||
),
|
||||
),
|
||||
@@ -217,18 +224,17 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16.0,
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: Text(message),
|
||||
),
|
||||
FlatButton(
|
||||
RaisedButton(
|
||||
onPressed: () {
|
||||
messageSearchBloc.search(
|
||||
filter: widget.filters,
|
||||
sort: widget.sortOptions,
|
||||
query: widget.messageQuery,
|
||||
pagination: widget.paginationParams,
|
||||
messageFilter: widget.messageFilters,
|
||||
);
|
||||
},
|
||||
child: Text('Retry'),
|
||||
@@ -279,32 +285,46 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget child;
|
||||
Widget child = ListView.separated(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
||||
separatorBuilder: (_, index) {
|
||||
if (widget.separatorBuilder != null) {
|
||||
return widget.separatorBuilder(context, index);
|
||||
}
|
||||
return _separatorBuilder(context, index);
|
||||
},
|
||||
itemBuilder: (context, index) {
|
||||
if (index < items.length) {
|
||||
return _listItemBuilder(context, items[index]);
|
||||
}
|
||||
return _buildQueryProgressIndicator(context, messageSearchBloc);
|
||||
},
|
||||
);
|
||||
if (widget.pullToRefresh) {
|
||||
child = RefreshIndicator(
|
||||
onRefresh: () async => messageSearchBloc.search(
|
||||
filter: widget.filters,
|
||||
sort: widget.sortOptions,
|
||||
query: widget.messageQuery,
|
||||
pagination: widget.paginationParams,
|
||||
messageFilter: widget.messageFilters,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
child = LazyLoadScrollView(
|
||||
onEndOfPage: () => messageSearchBloc.search(
|
||||
onEndOfPage: () => messageSearchBloc.loadMore(
|
||||
filter: widget.filters,
|
||||
sort: widget.sortOptions,
|
||||
pagination: widget.paginationParams.copyWith(
|
||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
||||
),
|
||||
query: widget.messageQuery,
|
||||
messageFilter: widget.messageFilters,
|
||||
),
|
||||
child: ListView.separated(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
itemCount: items.isNotEmpty ? items.length + 1 : items.length,
|
||||
separatorBuilder: (_, index) {
|
||||
if (widget.separatorBuilder != null) {
|
||||
return widget.separatorBuilder(context, index);
|
||||
}
|
||||
return _separatorBuilder(context, index);
|
||||
},
|
||||
itemBuilder: (context, index) {
|
||||
if (index < items.length) {
|
||||
return _listItemBuilder(context, items[index]);
|
||||
}
|
||||
return _buildQueryProgressIndicator(context, messageSearchBloc);
|
||||
},
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
|
||||
if (widget.showResultCount) {
|
||||
@@ -344,13 +364,16 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
jsonEncode(widget.sortOptions) != jsonEncode(oldWidget.sortOptions) ||
|
||||
widget.paginationParams?.toJson()?.toString() !=
|
||||
oldWidget.paginationParams?.toJson()?.toString() ||
|
||||
widget.messageQuery?.toString() != oldWidget.messageQuery?.toString()) {
|
||||
widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() ||
|
||||
widget.messageFilters?.toString() !=
|
||||
oldWidget.messageFilters?.toString()) {
|
||||
final messageSearchBloc = MessageSearchBloc.of(context);
|
||||
messageSearchBloc.search(
|
||||
filter: widget.filters,
|
||||
sort: widget.sortOptions,
|
||||
query: widget.messageQuery,
|
||||
pagination: widget.paginationParams,
|
||||
messageFilter: widget.messageFilters,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user