Skip to content

narrow: Add starred messages narrow #870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 21, 2024
Merged

narrow: Add starred messages narrow #870

merged 5 commits into from
Aug 21, 2024

Conversation

PIG208
Copy link
Member

@PIG208 PIG208 commented Aug 7, 2024

Unreads can probably be handled in a separate PR, because it will probably grow in complexity.

This is stacked on top of #869

@PIG208 PIG208 changed the title WIP narrow: Add starred messages narrow narrow: Add starred messages narrow Aug 8, 2024
@PIG208 PIG208 marked this pull request as ready for review August 8, 2024 00:36
@PIG208
Copy link
Member Author

PIG208 commented Aug 8, 2024

This does not implement live updates for newly starred/unstarred messages. We should able to handle #818 together with this as a post-launch follow-up.

Copy link
Member Author

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will leave unreads for starred messages for now, as it is pretty uncommon to have unreads for them.

@PIG208 PIG208 added the maintainer review PR ready for review by Zulip maintainers label Aug 8, 2024
@PIG208
Copy link
Member Author

PIG208 commented Aug 8, 2024

Skipping the first 3 commits, this should be reviewable independently from #869.

@PIG208 PIG208 requested a review from chrisbobbe August 8, 2024 17:49
@PIG208 PIG208 force-pushed the starred branch 2 times, most recently from 6604aff to 6784d55 Compare August 12, 2024 19:03
@chrisbobbe
Copy link
Collaborator

Looks like CI is failing.

@PIG208
Copy link
Member Author

PIG208 commented Aug 12, 2024

Should be fixed now. It was an error emerged from moved messages support across narrows.

@chrisbobbe
Copy link
Collaborator

Thanks! Ah, but it looks like some conflicts appeared after you pushed that revision; could you resolve those please? :)

@PIG208
Copy link
Member Author

PIG208 commented Aug 13, 2024

Thanks! Just rebased it.

@PIG208
Copy link
Member Author

PIG208 commented Aug 15, 2024

(Pushed again to fix another merge conflict.)

Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Small comments below, including one about a bug I noticed.

In manual testing, I noticed that when I'm viewing the starred-messages narrow, when I unstar a message, it remains in the list. At first I thought this was a bug, but Greg pointed out that it's actually a product decision; it lets you easily undo the unstar action if you want. So that seems fine.

—But let's put a comment in the code, clarifying that it's intentional (to offer undo), so readers don't have to wonder. This point already applies for messages with @-mentions in the mentions narrow, I think, so it would be good to mention that narrow too, in a separate, earlier commit. I think the right place to comment on these things would be in MessageStoreImpl.handleUpdateMessageFlagsEvent, near where it operates on the message-list views (by having them notify listeners but not remove messages).

…Hmm. Thinking more, actually…The current behavior for remove-star events does seem helpful, but wouldn't it also be helpful if MessageStoreImpl.handleUpdateMessageFlagsEvent acted on add-star events by making the message appear in the starred-narrow message list? Similarly for mentioned messages in the mentions narrow.

final message = eg.streamMessage();
await setupToMessageActionSheet(tester, message: message, narrow: const MentionsNarrow());
check(findQuoteAndReplyButton(tester)).isNull();
group('composing to reply is not yet supported', () {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test [nfc]: Parameterize some narrow-related tests.

I would leave off the [nfc]. It's true that application code doesn't change, but with the test prefix, I would reserve [nfc] for commits that don't change observable behavior when we run the tests. This does change behavior, by nesting some tests in a new group.


for (final (narrowName, narrow, message) in testCases) {
assert(narrow.containsMessage(message));
testWidgets('not offered in $narrowName (composing to reply is not yet supported)', (tester) async {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the "(composing to reply is not yet supported)" necessary? It repeats what's in the group description.

Comment on lines 127 to 128
("Combined feed", const CombinedFeedNarrow(), <MessageFlag>[]),
("MentionsNarrow", const MentionsNarrow(), [MessageFlag.mentioned]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the narrowName, let's be consistent about using the identifier ("CombinedFeedNarrow", "MentionsNarrow") or not ("Combined feed", "Mentions narrow").

@@ -203,6 +203,7 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
case IsOperand.private:
case IsOperand.alerted:
case IsOperand.starred:
return const StarredMessagesNarrow();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal_link: Parse "/is/starred" internal links.

This is a bug. :) Since cases before IsOperand.starred are empty, they'll also give const StarredMessagesNarrow(), just like the IsOperand.starred case.

https://dart.dev/language/branches#switch-statements

Non-empty case clauses jump to the end of the switch after completion. They do not require a break statement.

It's a common pattern to want multiple cases to give the same thing, and to express that with empty case clauses, as here.

To fix (here and in the test, which has the same bug), I would just reorder:

    switch (isElementOperands.single) {
      case IsOperand.mentioned:
        return const MentionsNarrow();
      case IsOperand.starred:
        return const StarredMessagesNarrow();
      case IsOperand.dm:
      case IsOperand.private:
      case IsOperand.alerted:
      case IsOperand.followed:
      case IsOperand.resolved:
      case IsOperand.unread:
      case IsOperand.unknown:
        return null;
    }

@PIG208
Copy link
Member Author

PIG208 commented Aug 15, 2024

Regarding

…Hmm. Thinking more, actually…The current behavior for remove-star events does seem helpful, but wouldn't it also be helpful if MessageStoreImpl.handleUpdateMessageFlagsEvent acted on add-star events by making the message appear in the starred-narrow message list? Similarly for mentioned messages in the mentions narrow.

Live-updates for starred messages and @-mentions are post-launch features, so we leave them out for now:

This does not implement live updates for newly starred/unstarred messages. We should able to handle #818 together with this as a post-launch follow-up.

@PIG208
Copy link
Member Author

PIG208 commented Aug 15, 2024

Having comments for now should be suitable.

@PIG208 PIG208 force-pushed the starred branch 2 times, most recently from 689e153 to bf0759d Compare August 15, 2024 23:55
@PIG208
Copy link
Member Author

PIG208 commented Aug 15, 2024

Updated the PR. Thanks for the review!

@chrisbobbe
Copy link
Collaborator

Thanks, LGTM! Over to Greg, then.

@chrisbobbe chrisbobbe added integration review Added by maintainers when PR may be ready for integration and removed maintainer review PR ready for review by Zulip maintainers labels Aug 17, 2024
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @PIG208, and thanks @chrisbobbe for the previous review!

Generally this looks great. Comments below on the tests, mostly just on their structure.

Separately, I think the last three commits make most sense squashed together:
8d8841e narrow: Add starred messages narrow.
3b3b4c3 internal_link: Parse "/is/starred" internal links.
bf0759d nav: Add a button for starred messages page.

The latter two are small changes adding pieces that really should be there in order to say we support the starred-messages narrow. It seems like the main difference between those and most of the changes in the main commit is just that the main commit has the changes that are prompted by exhaustive-switch checking once the StarredMessagesNarrow type is added. That's a very useful tool but doesn't need to decide our commit structure.

(Even in the other direction: if the changes required to satisfy exhaustive switches added up to a big change that we didn't want to put in a single commit, we could split it up by making some of the new cases just throw UnimplementedError() or the like, with TODO comments pointing to the relevant issue.)

Comment on lines 720 to 727
testWidgets('show stream name in CombinedFeedNarrow', (tester) async {
await setupMessageListPage(tester,
narrow: const CombinedFeedNarrow(),
messages: [message], subscriptions: [eg.subscription(stream)]);
await tester.pump();
check(findInMessageList('stream name')).length.equals(1);
check(findInMessageList('topic name')).length.equals(1);
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these tests (and the other two sets of tests that get parametrized in the second commit) are actually better off in the form they were in, where each one has its own separate testWidgets call in the source code.

One reason is that that helps make each test case straightforward to read, by having fewer layers of indirection and conditionals to go through.

It also makes the set of test cases visible to the IDE (which does only some kind of very simple analysis looking for test and testWidgets calls), which is handy for running and debugging tests from there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, the preferable way to tighten up a set of related test cases is to factor out helper methods from their body, so that they can each call those helpers.

That solves the visibility-to-the-IDE problem. And though it does mean another layer of indirection, it's typically a simpler indirection — it doesn't have to cover computing a name for the test, and conditionals like the one below:

            if (showChannelName) {
              check(findInMessageList('stream name')).single;
            } else {
              check(findInMessageList('stream name')).isEmpty();
            }

get expressed by different test cases just doing one thing or the other.

Here, a small helper for the setupMessageListPage and tester.pump calls would work fine, though I think the existing tests are also fine without it.


The main situations where we put the test or testWidgets calls themselves inside a loop are:

  • when there's a bunch of variables we want to systematically cover all combinations of, as in test/widgets/sticky_header_test.dart
  • when there's a very large number of cases we want to test, as in test/model/internal_link_test.dart

The same downsides still apply, but those are where the payoff of that approach is large enough to make it worth it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. sticky_header_test.dart is an interesting example. Dropped the parameterization commit.

Comment on lines 124 to 136
group('presents message content appropriately', () {
// regression test for https://github.com/zulip/zulip-flutter/issues/736
testWidgets('content in "Combined feed" not asked to consume insets (including bottom)', (tester) async {
const fakePadding = FakeViewPadding(left: 10, top: 10, right: 10, bottom: 10);
tester.view.viewInsets = fakePadding;
tester.view.padding = fakePadding;

await setupMessageListPage(tester, narrow: const CombinedFeedNarrow(),
messages: [eg.streamMessage(content: ContentExample.codeBlockPlain.html)]);

final element = tester.element(find.byType(CodeBlock));
final padding = MediaQuery.of(element).padding;
check(padding).equals(EdgeInsets.zero);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setup and checking gets lengthy enough that I agree it's a bit annoying to repeat it three times. That could be solved with a helper that the test cases call (as in my preceding comment)… or, looking closer at what these particular tests are about, it could really just be a single test case using any one of these narrows (probably CombinedFeedNarrow). It's a regression test for #736, and to do that job it really just needs some message list that doesn't have a compose box.

For good measure the test could check there is no compose box — that'd make it robust to a hypothetical future where one particular narrow grows a compose box, by ensuring that in that case we'd update the test so it continues to be effective for any other narrows that lack a compose box.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this interpretation makes sense me. I decided to remove the MentionsNarrow test, because I think they will be largely verifying the same code path. It is reasonable to check for the absence of compose box in different narrows, but we are more interested in testing the inset fix here.

@PIG208 PIG208 force-pushed the starred branch 3 times, most recently from 36272bf to 6c79685 Compare August 21, 2024 04:20
@PIG208
Copy link
Member Author

PIG208 commented Aug 21, 2024

Updated the PR. Thanks for the review!

Made separate functions for one test each in action_sheet_test.dart and message_list_test.dart, and removed the extra regression test. I also squashed the later commits together as suggested.

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the revision!

A few new nits below — otherwise all looks good. I'll fix those up and merge.

Comment on lines -391 to 392
final message = eg.streamMessage();
final message = eg.streamMessage(flags: [MessageFlag.mentioned]);
await setupToMessageActionSheet(tester, message: message, narrow: const MentionsNarrow());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

action_sheet test: Create message with the appropriate flag.

The message wouldn't otherwise appear in MentionsNarrow.

Hmm indeed. But I'm a bit puzzled then: why wasn't this test already failing?

Ah it's because the code actually will show the message. So this is just a realism fix, making the simulated server response something a non-buggy server might give on this request.

Comment on lines 273 to 274
// TODO(#818): Support MentionsNarrow live-updates when handling
// @-mentioned flags.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indent any continuation lines on a TODO comment:

Suggested change
// TODO(#818): Support MentionsNarrow live-updates when handling
// @-mentioned flags.
// TODO(#818): Support MentionsNarrow live-updates when handling
// @-mentioned flags.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also "@-mentioned flags" reads to me as about flags that were @-mentioned; could say "mention flags" or "@-mention flags")

PIG208 added 3 commits August 21, 2024 14:49
Otherwise this message wouldn't be expected to appear in the
messages fetched for MentionsNarrow.

Signed-off-by: Zixuan James Li <[email protected]>
A test on CombinedFeedNarrow is sufficient for preventing this
particular regression. We could go further and test this on other
narrows, but there's little to gain because the bug related to the
absence of a compose box, not any other detail of the narrow.

Signed-off-by: Zixuan James Li <[email protected]>
@@ -135,19 +135,6 @@ void main() {
final padding = MediaQuery.of(element).padding;
check(padding).equals(EdgeInsets.zero);
});

testWidgets('content in MentionsNarrow not asked to consume insets (including bottom)', (tester) async {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh one other commit-message comment:

A test on CombinedFeedNarrow is sufficient for preventing this particular
regression. We could go further and test this on other narrows, but
there is little to gain other than verifying that those other narrows do
not have a compose box, which is covered statically with the exhaustive
check from hasComposeBox.

The last sentence here doesn't sound right, as this test didn't check that the narrow doesn't have a compose box. Rather, if the narrow had a compose box, the test would pass even if the bug were to return on other narrows that don't have the compose box. The original bug reproduced only on CombinedFeedNarrow (the only narrow lacking a compose box at the time), which is why the repro test used that narrow.

…ion test

This way if some future change causes CombinedFeedNarrow to have a
compose box, we'll be prompted to update this test, so that it still
checks for this bug if there are any other narrows that still lack
a compose box.
"Starred messages narrow" is the user facing name of the narrow, thus we
name the Narrow class after it. This narrow is pretty similar to
MentionsNarrow.

Signed-off-by: Zixuan James Li <[email protected]>
@gnprice
Copy link
Member

gnprice commented Aug 21, 2024

I'll fix those up and merge.

Done. I also added a commit to better pin down that existing regression test's assumptions:
5bcb5d4 msglist test [nfc]: Pin down lack of compose box in no-insets regression test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants