topic_list: Enable topic filtering - #2326
Conversation
rajveermalviya
left a comment
There was a problem hiding this comment.
Thanks @sm-sayedi! Comments below, including one about the query implementation, haven't looked at the tests yet.
There was a problem hiding this comment.
nit: commit message
icons: Edit `search` icon to remove the additional space around it
The icon was edited in Inkspace and cleaned up using the following guide:
https://zulip.readthedocs.io/en/latest/subsystems/icons.html#preparing-icons-for-use-with-zulip
s/Inkspace/Inkscape
| @@ -161,6 +167,9 @@ class _TopicListState extends State<_TopicList> with PerAccountStoreAwareStateMi | |||
|
|
|||
| @override | |||
| Widget build(BuildContext context) { | |||
| final store = PerAccountStoreWidget.of(context); | |||
| final zulipLocalization = ZulipLocalizations.of(context); | |||
There was a problem hiding this comment.
nit: zulipLocalizations (not zulipLocalization).
Also remove another instance of final zulipLocalizations = ZulipLocalizations.of(context); below.
| @override | ||
| Widget build(BuildContext context) { | ||
| final designVariables = DesignVariables.of(context); | ||
| final zulipLocalization = ZulipLocalizations.of(context); |
There was a problem hiding this comment.
nit: zulipLocalizations (not zulipLocalization).
| final filteredTopics = _filterQuery == null | ||
| ? channelTopics | ||
| : channelTopics.where((e) => | ||
| (e.name.displayName ?? store.realmEmptyTopicDisplayName).toLowerCase() | ||
| .contains(_filterQuery!.toLowerCase())); |
There was a problem hiding this comment.
I think we want this search to behave in the same way the current topic autocomplete behaves. See #1384 (comment).
So we should probably use relevant bits from lib/model/autocomplete.dart for topic autocomplete, just like emoji picker search.
c385b09 to
3ce261b
Compare
|
Thanks @rajveermalviya for the review. Changes pushed, PTAL. |
rajveermalviya
left a comment
There was a problem hiding this comment.
Thanks for the revision @sm-sayedi! All LGTM, some small comments below.
After addressing them please mark it for the integration review.
| void _handleViewModelUpdate() { | ||
| setState(() { | ||
| _resultsToDisplay = List.unmodifiable(_viewModel!.results); | ||
| _resultsToDisplay = List.unmodifiable(_viewModel?.results ?? []); |
There was a problem hiding this comment.
nit: _handleViewModelUpdate will always have non-null _viewModel, right?
| _resultsToDisplay = List.unmodifiable(_viewModel?.results ?? []); | |
| _resultsToDisplay = List.unmodifiable(_viewModel!.results ?? []); |
|
|
||
| class _TopicListState extends State<_TopicList> with PerAccountStoreAwareStateMixin { | ||
| Topics? topicsModel; | ||
| final TextEditingController _controller = TextEditingController(); |
There was a problem hiding this comment.
nit: let's move this instantiation inside initState, and make this a late declaration.
| final TextEditingController _controller = TextEditingController(); | |
| late TextEditingController _controller; |
| _controller.dispose(); | ||
| _topicAutocompleteModel?.dispose(); | ||
| unreadsModel?.removeListener(_unreadsModelChanged); |
There was a problem hiding this comment.
The order of these should be reverse of their initialization.
3ce261b to
85d085a
Compare
|
Thanks Rajesh for the review. Changes pushed, marking for Chris's review. |
85d085a to
b85fd69
Compare
|
Looks like this has gathered some conflicts; would you rebase please? I hope to get to this soon. |
b85fd69 to
82e2889
Compare
|
(Conflicts resolved.) |
82e2889 to
3ebabb0
Compare
chrisbobbe
left a comment
There was a problem hiding this comment.
Thanks! Comments below.
| child: Icon(size: 24, ZulipIcons.search)), | ||
| child: SizedBox.square(dimension: 24, | ||
| child: Icon(size: 20, ZulipIcons.search))), |
There was a problem hiding this comment.
icons: Edit `search` icon to remove the additional space around it
This change looks like it adds, or restores, some amount of additional space around the icon? What's the actual intent of this commit? If this change is part of that intent, why isn't the ZulipIcons.search in lib/widgets/home.dart also touched?
There was a problem hiding this comment.
Thanks for the catch. The search icon in other places should've been changed too; done in the new revision. The only exception is the search icon in the main-menu sheet. The Figma design seems to be inconsistent with the icon sizes of the menu buttons, ranging from 20px to 24px. We use 24px for all of them.
The actual intent of the commit is to have the search icon without any surrounding space, so we can exactly match the Figma design where the icon is used. Discovered the need for this while implementing the search field in the topic list page.
There was a problem hiding this comment.
The Figma design seems to be inconsistent with the icon sizes of the menu buttons, ranging from 20px to 24px.
Worth being precise about this, I think: I don't actually see an inconsistency here. I'm seeing consistent 24px squares for all the menu buttons, at the icons/24/foo level:
There's a nested node on all of them that's less than 24px, e.g. 22px with the "clock" icon:
where the square box wraps the icon's glyph tightly, leaving no surrounding whitespace. But the icon asset we actually export from the Figma—linked by the "go to main component" button—is the 24px version with the surrounding whitespace:
That looks to be the case with the "search" icon too:
There was a problem hiding this comment.
So I don't think there's a change to be made here, and we should just keep the asset unchanged, without adding padding in the widget tree to compensate anywhere. Am I missing something, though?
There was a problem hiding this comment.
The inconsistency that I was referring to was about the nested node inside the 24px square box. But now that you mentioned that we export the main icon component that has internal padding, we can drop the commit.
| } | ||
| return topic.displayName != raw | ||
| && AutocompleteQuery.lowercaseAndStripDiacritics(topic.displayName!).contains(_normalized); | ||
| return AutocompleteQuery.lowercaseAndStripDiacritics( |
There was a problem hiding this comment.
autocomplete: Include the result when the query matches the topic
Commit-message nit: let's mention "topic autocomplete" in the summary line. Maybe:
autocomplete: In topic autocomplete, include exact matches
| final int channelId; | ||
|
|
||
| Iterable<TopicName> _topics = []; | ||
| Iterable<GetChannelTopicsEntry> _topics = []; |
There was a problem hiding this comment.
autocomplete: Change TopicAutocompleteResult.topic type
Can this be marked NFC, or is there some behavior change I'm missing?
There was a problem hiding this comment.
Yep, that's NFC. Thanks for bringing it up.
| required this.channelId, | ||
| }); | ||
| }) { | ||
| store.topics.addListener(_fetch); |
There was a problem hiding this comment.
autocomplete: Search again when there is a change in topics
This code is more indirect than it needs to be: a topics change triggers _fetch, which doesn't actually fetch anything (the data is already present, right), and then that calls _startSearch. This would read more transparently if it were store.topics.addListener(_startSearch).
How about:
- In a prep commit, remove the mutable
_topicsfield and the.._fetch()inTopicAutocompleteView.init. Instead, putfinal topics = await store.topics.getChannelTopics(channelId)at the top ofcomputeResults. - Then this line in this commit can change to
store.topics.addListener(_startSearch).
?
There was a problem hiding this comment.
That's a nice improvement, thanks.
| ], | ||
| ), | ||
| ); |
There was a problem hiding this comment.
nit: coalesce closing parens
7602c9e to
f467175
Compare
|
Thanks for the review, Chris. Revision pushed. Also, dropped the commit |
chrisbobbe
left a comment
There was a problem hiding this comment.
Thanks! Small comment below with a finding from reading Git history, and see my reply above: #2326 (comment)
| return AutocompleteQuery.lowercaseAndStripDiacritics(store.realmEmptyTopicDisplayName) | ||
| .contains(_normalized); | ||
| } | ||
| return topic.displayName != raw |
There was a problem hiding this comment.
autocomplete: In topic autocomplete, include exact matches
Interesting: in code review, it looks like Greg requested the != raw condition be dropped, for the same reason you give—we want to match web—but it seems that request wasn't acted on, and it slipped through and got merged. So you could additionally link to that review in the commit message, to support the change: #627 (comment)
f467175 to
d21a92c
Compare
|
Thanks for the review. Changes pushed with that icon commit dropped! |
d21a92c to
35a5c57
Compare
chrisbobbe
left a comment
There was a problem hiding this comment.
Thanks! Here's a partial review before I have to run to dinner; more later.
I noticed something this time in manual testing: this has a bug like #1175, which I think should be fixed the same way: when you change your query, it should jump back to the top (the "zero" scroll position) so you can see the most relevant results.
| Future<List<TopicAutocompleteResult>?> computeResults() async { | ||
| // TODO: handle fetch failure | ||
| final topics = await store.topics.getChannelTopics(channelId); |
There was a problem hiding this comment.
autocomplete [nfc]: In TopicAutocomplete, fetch topics in computeResults
This isn't NFC, because now we're letting the user re-trigger the fetch by changing the query, if it failed the first time.
0c2ae40 to
400fe2e
Compare
|
Thanks for those points. New changes pushed. Also addressed some feedback from a review Claude did. |
Previously, in topic autocomplete, the query "t" would not include a topic named "t" (an exact match). I think this is not desired and it's not what the web does. This also matches a suggestion Greg made in an earlier review of this part of the code: zulip#627 (comment)
Change it from TopicName to GetChannelTopicsEntry. This allows future commits to access maxId when the TopicAutocomplete machinery is used for topic filtering on the topic-list page.
Move the topic fetch from TopicAutocompleteView.init to computeResults. This simplifies the implementation by awaiting the cached Topics.getChannelTopics call directly, instead of restarting the search after the fetch completes. Another benefit is that user can re-trigger the topic-list fetch by changing the query; if initially failed. The main motivation for this change is that it will enable us to cleanly search again when the topics change.
This enables the UI to reflect changes to the topics. This will be needed in the next commit(s), where we use the TopicAutocomplete machinery for topic filtering on the topic-list page.
400fe2e to
b7c5085
Compare
Fixes #1384.
Figma design: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=6821-37083&t=IUNKC8IkYmIvIb5d-0
Screenshots
Screen recording
Screen.Recording.2026-05-24.at.5.08.12.PM.mov