Skip to content

Conversation

@rajveermalviya
Copy link
Member

@rajveermalviya rajveermalviya commented Sep 30, 2025

Stacked on top of ea5cd48 and b8e0143 from #1937.


Separated from #1816 to preserve some drafts commits there from @chrisbobbe.

Screenshots coming..

Tests are TODO and will happen as part of #1787 in a follow-up PR.

Figma: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=12853-76543&p=f&t=oBRXWxFjbkz1yeI7-0
Fixes: #1779

@rajveermalviya
Copy link
Member Author

rajveermalviya commented Oct 3, 2025

Screenshots:

Channels DMs Choose account
image image image
image image image

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.

SubscriptionListPageBody(
showTopicListButtonInActionSheet: false,
hideChannelsIfUserCantSendMessage: true,
allowGoToAllChannels: false,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This removal looks unintentional.

Comment on lines 190 to 192
// We should already have the `store.realmIcon` after the
// PerAccountStore has completed loading, hence the `!` here.
final realmIconUrl = store.realmUrl.resolveUri(store.realmIcon!);
Copy link
Collaborator

Choose a reason for hiding this comment

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

If a PerAccountStore is guaranteed to have non-null .realmIcon, then why is it typed as optional? If we can make it required, we should do so, right? (Ditto .realmName.) Then if there's some subtlety in explaining that, we can do it just once where the field is declared, instead of all the places that try to consume it.

Comment on lines 212 to 216
SizedBox.square(
dimension: 42,
child: Padding(
padding: const EdgeInsets.all(7),
child: RealmContentNetworkImage(realmIconUrl))),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Following the link to the "company-logo" component in Figma—

https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=421-14693&m=dev

—it looks like this is supposed to have a 4px border radius:

image

Would the AvatarShape widget be appropriate here? Its dartdoc says "A rounded square shape, to wrap an [AvatarImage] or similar.".

Copy link
Collaborator

Choose a reason for hiding this comment

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

I also see an additional 4px horizontal padding in the Figma that's not implemented in this revision:

https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=12853-76635&m=dev

image

labelStyle: labelStyle,
labelColor: designVariables.iconSelected,
unselectedLabelColor: designVariables.icon,
indicatorWeight: 0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, two things stand out to me in the dartdoc of indicatorWeight:

  • /// The value of this parameter must be greater than zero.
  • /// If [indicator] is specified […] this property is ignored.

What happens if we don't pass indicatorWeight?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a bit of context in a comment on why the indicatorWeight: 0 is needed here.

final labelStyle = TextStyle(
fontSize: 18,
height: 24 / 18,
letterSpacing: 0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't letterSpacing: 0 the default, from zulipTypography?

Comment on lines 234 to 235
child: RealmContentNetworkImage(realmIconUrl))),
),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
child: RealmContentNetworkImage(realmIconUrl))),
),
child: RealmContentNetworkImage(realmIconUrl)))),

Comment on lines 103 to 107
ShareDialog.show(
pageContext: context,
initialAccountId: accountId,
sharedFiles: sharedFiles,
sharedText: intentSendEvent.extraText);
Copy link
Collaborator

Choose a reason for hiding this comment

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

share: Re-design from page to a dialog

This commit breaks the "New DM" button in the "Direct messages" tab, because a PageRoot ancestor is no longer found when the button is tapped:

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
No PageRoot ancestor
'package:zulip/widgets/page.dart':
Failed assertion: line 26 pos 12: 'element != null'

When the exception was thrown, this was the stack: 
#2      PageRoot.contextOf (package:zulip/widgets/page.dart:26:12)
#3      showNewDmSheet (package:zulip/widgets/new_dm_sheet.dart:17:32)
#4      _NewDmButtonState.build.<anonymous closure> (package:zulip/widgets/recent_dm_conversations.dart:270:20)

[etc.]

Comment on lines 344 to 380
unawaited(() async {
final GetServerSettingsResult serverSettings;
final connection = globalStore.apiConnection(
realmUrl: account.realmUrl,
zulipFeatureLevel: null);
try {
serverSettings = await getServerSettings(connection);
} catch (_) {
return;
} finally {
connection.close();
}

if (globalStore.getAccount(accountId) != null) {
await globalStore.updateRealmData(
accountId,
realmName: serverSettings.realmName,
realmIcon: serverSettings.realmIcon);
}
}());
Copy link
Collaborator

Choose a reason for hiding this comment

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

The goal is to make sure the realm name and icon are present and up-to-date, right?

I think my ideal way to do this would be more centralized and a bit more rigorous:

  • The choose-account page/dialog doesn't yet show the name and icon, but it will, and it'll be equally useful there to refresh them as here.
  • We've written careful "refuse-to-connect-to-ancient-servers" logic that should eliminate ancient-server behavior as a possible source of bugs, which should help simplify debugging. This revision puts a small hole in that logic, which we could fix by checking ZulipVersionData.isUnsupported before interpreting realmName and realmIcon. Like we do around the other getServerSettings call.
    • I don't think any ancient servers format realmName and realmIcon in weird, interfering ways…but the point is being confident that it wouldn't matter even if they did.
  • The realm name and icon are also provided via the event system, and we should defer to that: if a PerAccountStore finishes loading before we've received and recorded the data from get-server-settings, we should abort instead of clobbering the store with this data that arrived out-of-band.

Copy link
Collaborator

Choose a reason for hiding this comment

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

more centralized

I'm not sure yet where's the most helpful place to put this. Maybe in a stateful widget that gets passed to PerAccountStoreWidget.placeholder? I'd be happy to think about that when I revisit my draft commits in #1816, and in the meantime perhaps you can just address my second and third bullet points above, which are correctness issues.

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 a good home for this would be as a method on GlobalStore, perhaps named like ensureFreshAccountData. (Or ensureFreshRealmMetadata? The point is it's the data (a) that we store in the Account record but (b) about the realm as a whole.)

Then that method will have access to _perAccountStoresLoading as well as _perAccountStores. It can look at those in order to ensure that it doesn't do anything if there's already a PerAccountStore or one being loaded.

return const SizedBox.shrink();
}

return ListTile(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps add a TODO(#1038) for aligning this dialog with other choose-account dialogs (link: #1038)

Comment on lines 221 to 228
onTap: hasMultipleAccounts
? () {
ChooseAccountForShareDialog.show(
pageContext: context,
selectedAccountId: store.accountId,
sharedFiles: sharedFiles,
sharedText: sharedText);
}
Copy link
Collaborator

@chrisbobbe chrisbobbe Oct 8, 2025

Choose a reason for hiding this comment

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

I wonder if there's some way we can make it clearer that the org icon can be tapped to switch accounts. Like the chevron-down icon on the emoji selector on the set-status page:

image

Copy link
Collaborator

Choose a reason for hiding this comment

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

I dunno, at least as an Android user, I feel like one is pretty well trained that clicking on your avatar opens the account switcher.

@chrisbobbe
Copy link
Collaborator

@alya curious for your thoughts on #1883 (comment) too.

@chrisbobbe
Copy link
Collaborator

@rajveermalviya gentle bump on this; there's material from my draft commits in #1816 that I'd like to refresh and send as a PR after this PR settles.

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch from 01bc09d to db3de4b Compare December 10, 2025 18:28
@chrisbobbe
Copy link
Collaborator

I see you've pushed changes but I'm not sure if you're intending them to be ready for review 🙂 please let me know when ready.

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch 2 times, most recently from f02fe4a to c02e265 Compare December 11, 2025 16:36
@rajveermalviya
Copy link
Member Author

Thanks for the review @chrisbobbe! Sorry for the delay. I've pushed a new revision, PTAL.

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch 2 times, most recently from 79ceed6 to 955d505 Compare December 12, 2025 06:49
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.

/// to update the realm metadata (name and icon).
///
/// The updation for some accounts may be skipped if:
/// - The per account store for the account is already loaded or is loading.
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Helpful to use the identifier [PerAccountStore] here

/// - The version of corresponding realm server is unsupported.
///
/// Returns immediately; the fetches and updates are done asynchronously.
void ensureFreshRealmMetadata() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This name makes me think that…well, that it'll ensure the realm metadata is fresh 🙂, and that it'll accomplish that before it returns. (I guess I'm thinking of calls like TestZulipBinding.ensureInitialized();.)

Really, it just kicks off an attempt at refreshing the metadata, under certain conditions (like that the server isn't ancient); an attempt which may or may not succeed, sometime after the function returns.

How about tryRefreshRealmMetadata, or just refreshRealmMetadata? I think the latter is fine (it's shorter); I think the important improvement is just to remove the really strong "ensure" wording.

Comment on lines 150 to 157
child: PageRoot(
child: ShareSheet(
sharedFiles: sharedFiles,
sharedText: sharedText),
));
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: parens at end

text,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: extra space

splashColor: Colors.transparent,
leading: AspectRatio(
aspectRatio: 1,
child: account.realmIcon == null
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't the account.realmIcon == null case impossible here, because of the account.realmIcon! above?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh, the account.realmIcon! above should have a conditional, because account.{realmIcon,realmName} == null is possible for accounts that never had the realm metadata stored. i.e PerAccountStore wasn't loaded recently (specifically after a8b236d) or GlobalStore.refreshRealmMetadata hasn't updated the data yet.

sharedText: widget.sharedText);
},
splashColor: Colors.transparent,
leading: AspectRatio(
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about using AvatarShape for the realm icon, as elsewhere

headers: userAgentHeader(),
filterQuality: FilterQuality.medium,
fit: BoxFit.cover)),
title: Text(account.realmName ?? account.realmUrl.toString()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can account.realmName ever be null here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, see: #1883 (comment)

Comment on lines 402 to 404
header: Padding(
padding: const EdgeInsets.only(top: 8),
child: BottomSheetHeader(title: zulipLocalizations.shareChooseAccountLabel)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of the Padding widget, pass outerVerticalPadding: true to BottomSheetHeader. (I think this was an API change in BottomSheetHeader that landed after your first revision of this.)

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch 3 times, most recently from 3c9cc57 to 5d559ae Compare December 16, 2025 13:39
@rajveermalviya
Copy link
Member Author

Thanks for the review @chrisbobbe! Pushed an update, PTAL.

@chrisbobbe
Copy link
Collaborator

Thanks! Marking for Greg's review.

Thanks for the reminder at #1883 (comment) — AIUI that the realm icon/name will be present on a PerAccountStore, but might be missing on an Account, which is what we'll be looking at for the account-switcher UI. My one suggestion is that it might be helpful to write some tests in which a realm icon or name is missing when we try to show that UI.

@chrisbobbe chrisbobbe requested a review from gnprice December 23, 2025 22:23
@chrisbobbe chrisbobbe assigned gnprice and unassigned chrisbobbe Dec 23, 2025
@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 Dec 23, 2025
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 @rajveermalviya, and thanks @chrisbobbe for the previous reviews!

Generally this looks good; comments below.

I haven't yet looked at the screenshots or tried experimenting with the UI.

/// Fetches server settings for each account and then calls [updateRealmData]
/// to update the realm metadata (name and icon).
///
/// The updation for some accounts may be skipped if:
Copy link
Member

Choose a reason for hiding this comment

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

nit: "updation" isn't a word 🙂; could say "the update"

///
/// The updation for some accounts may be skipped if:
/// - The [PerAccountStore] for the account is already loaded or is loading.
/// - The version of corresponding realm server is unsupported.
Copy link
Member

Choose a reason for hiding this comment

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

I can't quite parse this last line. Does this cover what you mean?

Suggested change
/// - The version of corresponding realm server is unsupported.
/// - The Zulip Server version of the realm's server is unsupported.

Comment on lines 360 to 390
// Avoid updating realm metadata if per account store has already
// loaded or is being loaded. It should be updated with data from
// the initial snapshot or realm update events.
if (_perAccountStoresLoading.containsKey(accountId)) continue;
if (_perAccountStores.containsKey(accountId)) continue;
Copy link
Member

Choose a reason for hiding this comment

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

Here "should" sounds to me like it's saying there's some obligation which has yet to be discharged. I think what this is intended to say is a reassurance: the update will get taken care of, by other code.

Suggested change
// Avoid updating realm metadata if per account store has already
// loaded or is being loaded. It should be updated with data from
// the initial snapshot or realm update events.
if (_perAccountStoresLoading.containsKey(accountId)) continue;
if (_perAccountStores.containsKey(accountId)) continue;
// Avoid updating realm metadata if per account store has already
// loaded or is being loaded. It will be updated with data from
// the initial snapshot or realm update events.
if (_perAccountStoresLoading.containsKey(accountId)) continue;
if (_perAccountStores.containsKey(accountId)) continue;

Comment on lines 366 to 367
final account = getAccount(accountId);
if (account == null) continue;
Copy link
Member

Choose a reason for hiding this comment

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

What's the situation where this condition can arise?

… I think it can't — this is a lookup in the same map that we're iterating through the keys of. So let's write the logic in a way that makes explicit that this case is impossible.

An immediate version of that would be to say ! here — that makes clear we believe it's impossible. Better yet: iterate through accountEntries rather than accountIds, so that this case is structurally impossible by the way the logic is arranged.

Copy link
Member

Choose a reason for hiding this comment

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

Or for that matter iterate through accounts, and use account.id to get the account ID.

Comment on lines 372 to 389
final GetServerSettingsResult serverSettings;
final connection = apiConnection(
realmUrl: account.realmUrl,
zulipFeatureLevel: null);
try {
serverSettings = await getServerSettings(connection);
final zulipVersionData = ZulipVersionData.fromServerSettings(serverSettings);
if (zulipVersionData.isUnsupported) {
throw ServerVersionUnsupportedException(zulipVersionData);
}
} on MalformedServerResponseException catch (e) {
final zulipVersionData = ZulipVersionData.fromMalformedServerResponseException(e);
if (zulipVersionData != null && zulipVersionData.isUnsupported) {
throw ServerVersionUnsupportedException(zulipVersionData);
}
rethrow;
} finally {
connection.close();
}
Copy link
Member

Choose a reason for hiding this comment

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

This logic is rather subtle, and it's duplicated with the other place we call getServerSettings, in the login flow. Can we deduplicate? Something like this:

Suggested change
final GetServerSettingsResult serverSettings;
final connection = apiConnection(
realmUrl: account.realmUrl,
zulipFeatureLevel: null);
try {
serverSettings = await getServerSettings(connection);
final zulipVersionData = ZulipVersionData.fromServerSettings(serverSettings);
if (zulipVersionData.isUnsupported) {
throw ServerVersionUnsupportedException(zulipVersionData);
}
} on MalformedServerResponseException catch (e) {
final zulipVersionData = ZulipVersionData.fromMalformedServerResponseException(e);
if (zulipVersionData != null && zulipVersionData.isUnsupported) {
throw ServerVersionUnsupportedException(zulipVersionData);
}
rethrow;
} finally {
connection.close();
}
final serverSettings = await fetchServerSettings(account.realmUrl);

We'd arrange that as an NFC commit factoring out GlobalStore.fetchServerSettings (and using it in the existing place), then the commit adding this refreshRealmMetadata method using it.

if (account == null) continue;

// Fetch the server settings and update the realm data without awaiting.
// This allows fetching server settings of all the accounts parallelly.
Copy link
Member

Choose a reason for hiding this comment

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

nit: "parallelly" isn't a word

Suggested change
// This allows fetching server settings of all the accounts parallelly.
// This allows fetching server settings of all the accounts in parallel.

Comment on lines 378 to 380
final zulipVersionData = ZulipVersionData.fromServerSettings(serverSettings);
if (zulipVersionData.isUnsupported) {
throw ServerVersionUnsupportedException(zulipVersionData);
}
Copy link
Member

Choose a reason for hiding this comment

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

This part seems unnecessary. If we can successfully parse the name and icon, why not use them?

Happily I think this also belongs outside the scope of a "fetch server settings" helper method. The other call site of that method can do this part itself after calling the method.

Comment on lines 253 to 255
Expanded(child: TabBar(
padding: 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.

Suggested change
Expanded(child: TabBar(
padding: EdgeInsets.zero,
Expanded(child: TabBar(

This is equivalent, right?

final globalStore = GlobalStoreWidget.of(context);
final zulipLocalizations = ZulipLocalizations.of(context);

final accountIds = List<int>.unmodifiable(globalStore.accountIds);
Copy link
Member

Choose a reason for hiding this comment

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

nit: this may as well get the list of actual account objects:

Suggested change
final accountIds = List<int>.unmodifiable(globalStore.accountIds);
final accounts = List<int>.unmodifiable(globalStore.accounts);

That simplifies the code below a bit, by eliminating any wonder about if the accounts can go missing.

This version will update itself the same way, in the end, that the current revision does: this widget is already registering a dependency on GlobalStoreWidget, so it will get rebuilt when the GlobalStore notifies its listeners, which happens whenever the list of accounts (or any individual account within it) changes.

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch from 5d559ae to 6fd5a6b Compare December 30, 2025 17:46
@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch from 6fd5a6b to 876dcdc Compare January 5, 2026 16:07
@rajveermalviya
Copy link
Member Author

Thanks for the review @gnprice! Pushed an update, PTAL.

@rajveermalviya rajveermalviya requested a review from gnprice January 5, 2026 16:14
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! Generally this all looks good, and I've also now gone through the screenshots and tried out the UI. Small comments below.

Comment on lines 359 to 360
final serverSettings = await getServerSettings(connection);
return serverSettings;
Copy link
Member

Choose a reason for hiding this comment

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

nit: simplify


return ListTile(
onTap: () {
if (globalStore.getAccount(accountId) == null) return;
Copy link
Member

Choose a reason for hiding this comment

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

What's the situation where this could occur?

I think it can't, for the reasons at #1883 (comment) .

}
}

class ChooseAccountForShareDialog extends StatefulWidget {
Copy link
Member

Choose a reason for hiding this comment

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

This isn't a dialog — it's a bottom sheet. I think s/Dialog/BottomSheet/ would do.

Copy link
Member

Choose a reason for hiding this comment

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

Or s/Dialog/Modal/. That's a more general category that includes dialogs and modal bottom sheets, and maybe it's the more apt level of abstraction to think about the role of this piece of UI. (It also has a shorter name.)

Comment on lines +314 to +318
static void show({
required BuildContext pageContext,
required int selectedAccountId,
required Iterable<FileToUpload>? sharedFiles,
required String? sharedText,
}) async {
unawaited(showModalBottomSheet<void>(
Copy link
Member

Choose a reason for hiding this comment

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

I like this organization where the "show" function is a static method on the widget class. That helps keep the widget code organized into widget classes, like it is for most everything other than dialogs and bottom sheets.

}

class ChooseAccountForShareDialog extends StatefulWidget {
const ChooseAccountForShareDialog({
Copy link
Member

Choose a reason for hiding this comment

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

The one downside of this way of organizing it (with "show" as a static method on the widget class) is that it makes the widget class public, when it's really an implementation detail of the "show" function.

I think that can be addressed nicely, though, by making the constructor here private. That clarifies that the widget is only meant to be used via the "show" method. (And it's hardly a surprise that there will be some sort of widget corresponding to the modal; so with the constructor private, the class itself being public is harmless.)

"description": "Title for the page about sharing content received from other apps."
"shareChooseAccountLabel": "Choose an account",
"@shareChooseAccountLabel": {
"description": "Label for the page about selecting an account to share content received from other apps."
Copy link
Member

Choose a reason for hiding this comment

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

The thing this is used for isn't a page; it's a modal bottom sheet.


return DraggableScrollableModalBottomSheet(
header: BottomSheetHeader(
title: zulipLocalizations.shareChooseAccountLabel,
Copy link
Member

Choose a reason for hiding this comment

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

nit: Seems like "title" would be a more apt term than "label" in the name of this string.

@rajveermalviya rajveermalviya force-pushed the pr-switch-account-share branch 3 times, most recently from 28f32dc to b9c02f1 Compare January 6, 2026 14:08
@rajveermalviya
Copy link
Member Author

Thanks for the review @gnprice! Pushed an update, PTAL.

@rajveermalviya rajveermalviya requested a review from gnprice January 6, 2026 14:16
rajveermalviya and others added 4 commits January 6, 2026 13:09
Extract some of the complexity around `getServerSettings` in the
login flow, into a helper method in `GlobalStore`.
A helper that attempts to update the realm metadata (name and icon)
for each account.
@gnprice
Copy link
Member

gnprice commented Jan 6, 2026

Thanks! All looks good; merging.

@gnprice gnprice force-pushed the pr-switch-account-share branch from b9c02f1 to f813bc8 Compare January 6, 2026 21:17
@gnprice gnprice merged commit f813bc8 into zulip:main Jan 6, 2026
1 check passed
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.

[Android] Allow selecting an account when sharing to Zulip from other apps

4 participants