Skip to content

Conversation

@rajveermalviya
Copy link
Member

@rajveermalviya rajveermalviya commented Oct 22, 2025

@rajveermalviya rajveermalviya added the maintainer review PR ready for review by Zulip maintainers label Oct 22, 2025
@alya
Copy link
Collaborator

alya commented Oct 23, 2025

Hm, looking at this now, I don't like the "Organizations" button there. It's not immediately apparent what organizations it's referring to/why.

Where does it go? The account switcher?

@rajveermalviya
Copy link
Member Author

Where does it go? The account switcher?

Correct in the current revision it goes to the account switcher button, also the Figma design doesn't have a separate "Switch account" button in the main menu.

@alya
Copy link
Collaborator

alya commented Oct 23, 2025

Can you just click on the org name itself to switch accounts?

@alya
Copy link
Collaborator

alya commented Oct 23, 2025

(If we're moving the account switching action to this new top line, we'll want to remove the "switch account" option in the same PR.)

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! Comments below, and see also Alya's feedback (mentioning it so it doesn't get lost in the thread).

Comment on lines 426 to 434
String? get realmName => account.realmName;

Uri? get realmIcon => account.realmIcon;
// The `account` is populated with the `realmName` before
// PerAccountStore is created, so this should never be null.
// See `UpdateMachine.load`.
String get realmName => account.realmName!;

// The `account` is populated with the `realmIcon` before
// PerAccountStore is created, so this should never be null.
// See `UpdateMachine.load`.
Uri get realmIcon => account.realmIcon!;
Copy link
Collaborator

Choose a reason for hiding this comment

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

store: Make realmName and realmIcon getters non-null

Commit-message nit: "non-nullable", right? Also the commit message repeats reasoning that's already clear from added code comments, so we can remove it from the commit message.

Comment on lines 323 to 331
testWidgets('_AboutZulipButton', (tester) async {
tester.view.physicalSize = Size(1080, 1920);
prepareBoringImageHttpClient();
await prepare(tester);
await tapOpenMenuAndAwait(tester);
await tapButtonAndAwaitTransition(tester, find.byIcon(ZulipIcons.info));
check(find.byType(AboutZulipPage)).findsOne();
debugNetworkImageHttpClientProvider = null;
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rather than thinking through what's accomplished with the numbers 1080 and 1920 and whether they're correct, I'd rather just scroll until the button is in view:

    testWidgets('_AboutZulipButton', (tester) async {
      prepareBoringImageHttpClient();
      await prepare(tester);
      await tapOpenMenuAndAwait(tester);
      await tester.ensureVisible(find.byIcon(ZulipIcons.info));
      await tapButtonAndAwaitTransition(tester, find.byIcon(ZulipIcons.info));
      check(find.byType(AboutZulipPage)).findsOne();
      debugNetworkImageHttpClientProvider = null;
    });

That's simpler and more transparent, and also adds some coverage of the scrolling logic; it seems like a win-win :)

final designVariables = DesignVariables.of(context);
final store = PerAccountStoreWidget.of(context);

final realmIconUrl = store.tryResolveUrl(store.realmIcon.toString());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Most of this line seems like code we'd rather not need to recite whenever we need the realm icon—should be possible to encapsulate it in PerAccountStore (maybe even Account?) where we have access to the realm URL.

padding: const EdgeInsets.only(top: 6),
child: Row(children: [
Expanded(child: Padding(
padding: const EdgeInsets.fromLTRB(12, 6, 4, 6),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use EdgeInsetsDirectional.fromSTEB here, for RTL support.

MaterialWidgetRoute(page: const ChooseAccountPage()));
},
style: TextButton.styleFrom(
padding: const EdgeInsets.fromLTRB(8, 7, 14, 7),
Copy link
Collaborator

Choose a reason for hiding this comment

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

(Same comment about EdgeInsetsDirectional.fromSTEB.)

Comment on lines 375 to 376
? RealmContentNetworkImage(realmIconUrl)
: const SizedBox.shrink()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

When the icon URL doesn't parse for whatever reason, and also when it does but the network request fails, how about we show an empty rounded square colored by DesignVariables.avatarPlaceholderBg? Maybe we could have a reusable RealmIconImage widget that takes care of that, much like AvatarImage takes care of choosing a placeholder (which it'll do in more cases with #1558).

/// The main-menu sheet.
///
/// Figma link:
/// https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=11367-20647&t=lSnHudU6l7NWx0Fa-0
Copy link
Collaborator

Choose a reason for hiding this comment

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

This URL is taking me to the "Read receipts" sheet; do you reproduce? (Could be a Figma issue)

backgroundColor: Colors.transparent,
overlayColor: Colors.transparent,
splashFactory: NoSplash.splashFactory,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

This border radius shouldn't make a difference, with a transparent background/overlay/etc., right? I see it in the Figma, but it looks accidental there, too; I think we can leave it out without comment.

@rajveermalviya
Copy link
Member Author

Thanks for the reviews @chrisbobbe, @alya.
Pushed an update, and also updated the screenshots in the description, PTAL.

This helper will be used soon to display organization logo
in various places.
@alya
Copy link
Collaborator

alya commented Oct 28, 2025

Seems reasonable to me, thanks! Open to feedback from @terpimost if he has another suggestion.

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! Comments below.

///
/// This returns null if [reference] fails to parse as a URL.
Uri? tryResolveUrl(String reference) => _tryResolveUrl(realmUrl, reference);
Uri? tryResolveUrl(String reference) => _tryResolveUrlStr(realmUrl, reference);
Copy link
Collaborator

Choose a reason for hiding this comment

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

store [nfc]: Rename _tryResolveUrl to _tryResolveUrlStr

flutter analyze is complaining to me at this commit:

Analyzing zulip-flutter...                                              

   info • Unnecessary 'this.' qualifier • lib/model/emoji.dart:229:25 • unnecessary_this
   info • Unnecessary 'this.' qualifier • lib/model/emoji.dart:234:26 • unnecessary_this

2 issues found. (ran in 3.5s)

Comment on lines 470 to +471
/// Like [Uri.resolve], but on failure return null instead of throwing.
Uri? tryResolveUrl(Uri baseUrl, String reference) {
Uri? tryResolveUrlStr(Uri baseUrl, String reference) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we move this helper to a different file, like maybe lib/basic.dart? It's a convenience function encapsulating some control flow (a try/catch) and doesn't depend on details of a store.

Ditto the new, parallel helper that you're adding, which takes a Uri instead of String for reference.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Or, alternatively, I think we could just make both of these helpers private.

Comment on lines 403 to +404
check(() => Uri.parse(expectedImages.single.srcUrl)).throws<void>();
check(tryResolveUrl(eg.realmUrl, expectedImages.single.srcUrl)).isNull();
check(tryResolveUrlStr(eg.realmUrl, expectedImages.single.srcUrl)).isNull();
Copy link
Collaborator

Choose a reason for hiding this comment

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

The rename brings attention to this existing check 🙂 which looks redundant with the one above it (.throws<void>()). I think we're free to remove it.


return Padding(
padding: const EdgeInsets.only(top: 6),
child: AnimatedScaleOnTap(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this would look better without the AnimatedScaleOnTap effect. It looks like two things that are moving, rather than one thing that's resizing.

Nov-03-2025 16-51-44

I think we should reserve this effect for buttons that are a rounded-rectangle surface:

Nov-03-2025 16-54-11

Thoughts @alya?

Copy link
Collaborator

Choose a reason for hiding this comment

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

For touch feedback here, how about opacity? Per Vlad's suggestion at #mobile-design > all channels view design @ 💬:

we could use opacity by default to indicate touch if its not provided

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed that the effect in that screen capture isn't working. Trying Vlad's suggestion sounds good to me.

Comment on lines +410 to +412
child: Icon(ZulipIcons.arrow_left_right,
size: 19,
color: designVariables.icon)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if this would be a good place to use ZulipIconButton.

).merge(weightVariableTextStyle(context, wght: 600)))),
]))),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(8, 7, 14, 7),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if the end padding should be 12px, to match the padding before the org icon?

This 14px value comes from the Figma, but the Figma uses end-aligned text, and I think the 14px value might be tailored to that case. Also maybe the 7px vertical padding? Seems like it would be simpler, and logical, if we just wrapped the whole row with 12px horizontal padding and 6px vertical padding, and said spacing: 12 (or some other appropriate value) on the Row.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer review PR ready for review by Zulip maintainers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show current organization's name and logo atop main menu

3 participants