fix: eliminate full-screen flash when switching accounts
This commit is contained in:
+37
-16
@@ -451,8 +451,11 @@ export async function connectedAccountCandidates(client: JMAPClient, serverUrl:
|
|||||||
} catch { /* session unavailable */ }
|
} catch { /* session unavailable */ }
|
||||||
let primaryEmail: string | undefined;
|
let primaryEmail: string | undefined;
|
||||||
try {
|
try {
|
||||||
const { primaryIdentity } = loadIdentities(await client.getIdentities(), client.getUsername());
|
// Pure resolution (no setIdentities side effect): this guard runs while the
|
||||||
primaryEmail = primaryIdentity?.email;
|
// previous account may still be on screen during a seamless switch, so it
|
||||||
|
// must not mutate the live identity store.
|
||||||
|
const sorted = sortIdentities(await client.getIdentities(), client.getUsername());
|
||||||
|
primaryEmail = sorted[0]?.email;
|
||||||
} catch { /* identities unavailable */ }
|
} catch { /* identities unavailable */ }
|
||||||
return buildServerIdentifiers(sessionUser, primaryEmail, serverUrl);
|
return buildServerIdentifiers(sessionUser, primaryEmail, serverUrl);
|
||||||
}
|
}
|
||||||
@@ -1350,24 +1353,30 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
const targetAccount = accountStore.getAccountById(accountId);
|
const targetAccount = accountStore.getAccountById(accountId);
|
||||||
if (!targetAccount) return;
|
if (!targetAccount) return;
|
||||||
|
|
||||||
// Null out the client immediately so the page doesn't fire data-loading
|
// A switch between two already-connected accounts is done seamlessly:
|
||||||
// effects with the old client while stores are being cleared.
|
// the current account's client and mail stay on screen while we verify
|
||||||
set({ isLoading: true, client: null, isRateLimited: false, rateLimitUntil: null });
|
// the target session, then the store state is swapped in one synchronous
|
||||||
|
// batch (further below). Nulling the client / raising isLoading here
|
||||||
// Snapshot current account
|
// would trip the page's full-screen loading gate and blank the whole app
|
||||||
if (state.activeAccountId) {
|
// mid-switch, so we only do that when the target must be re-connected
|
||||||
snapshotAccount(state.activeAccountId);
|
// over the network (nothing worth keeping on screen while we wait).
|
||||||
}
|
|
||||||
|
|
||||||
// Clear current stores
|
|
||||||
clearAllStores();
|
|
||||||
useSettingsStore.getState().disableSync();
|
|
||||||
|
|
||||||
// Get or create client for target account
|
|
||||||
let targetClient = clients.get(accountId);
|
let targetClient = clients.get(accountId);
|
||||||
|
const wasConnected = !!targetClient;
|
||||||
let targetRestoreRateLimited = false;
|
let targetRestoreRateLimited = false;
|
||||||
|
|
||||||
if (!targetClient) {
|
if (!targetClient) {
|
||||||
|
// Null out the client immediately so the page doesn't fire data-loading
|
||||||
|
// effects with the old client while stores are being cleared.
|
||||||
|
set({ isLoading: true, client: null, isRateLimited: false, rateLimitUntil: null });
|
||||||
|
|
||||||
|
// Snapshot current account, then clear - there's nothing to keep on
|
||||||
|
// screen during the network round-trip.
|
||||||
|
if (state.activeAccountId) {
|
||||||
|
snapshotAccount(state.activeAccountId);
|
||||||
|
}
|
||||||
|
clearAllStores();
|
||||||
|
useSettingsStore.getState().disableSync();
|
||||||
|
|
||||||
// Client not connected - try to restore
|
// Client not connected - try to restore
|
||||||
try {
|
try {
|
||||||
if (targetAccount.authMode === 'oauth') {
|
if (targetAccount.authMode === 'oauth') {
|
||||||
@@ -1497,6 +1506,18 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
accountStore.updateAccount(accountId, { serverIdentifiers: connectedCandidates });
|
accountStore.updateAccount(accountId, { serverIdentifiers: connectedCandidates });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seamless path: the outgoing account is still on screen (we deferred
|
||||||
|
// clearing it), so snapshot + clear it now - synchronously, right before
|
||||||
|
// the restore and client swap below - so the UI never blanks between the
|
||||||
|
// two accounts. The network path already snapshotted and cleared above.
|
||||||
|
if (wasConnected) {
|
||||||
|
if (state.activeAccountId) {
|
||||||
|
snapshotAccount(state.activeAccountId);
|
||||||
|
}
|
||||||
|
clearAllStores();
|
||||||
|
useSettingsStore.getState().disableSync();
|
||||||
|
}
|
||||||
|
|
||||||
// Restore cached state or fetch fresh
|
// Restore cached state or fetch fresh
|
||||||
const restored = restoreAccount(accountId);
|
const restored = restoreAccount(accountId);
|
||||||
accountStore.setActiveAccount(accountId);
|
accountStore.setActiveAccount(accountId);
|
||||||
|
|||||||
Reference in New Issue
Block a user