From c8be383c05fbd5163f2757b3f7eedaec8f385828 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 29 Aug 2026 18:01:53 +0200 Subject: [PATCH] fix: page the viewer over the list a unified-inbox message was opened from --- src/screens/EmailThreadScreen.tsx | 17 ++++++++++++++++- src/screens/UnifiedInboxScreen.tsx | 8 +++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/screens/EmailThreadScreen.tsx b/src/screens/EmailThreadScreen.tsx index c28d5397..faf66af4 100644 --- a/src/screens/EmailThreadScreen.tsx +++ b/src/screens/EmailThreadScreen.tsx @@ -82,7 +82,22 @@ export default function EmailThreadScreen({ route, navigation }: Props) { const archiveEmailAction = useEmailStore((s) => s.archiveEmail); const mailboxes = useEmailStore((s) => s.mailboxes); const currentMailboxId = useEmailStore((s) => s.currentMailboxId); - const emails = useEmailStore((s) => s.emails); + const storeEmails = useEmailStore((s) => s.emails); + // The list the pager pages over. A message opened from the active folder + // pages over that folder; one opened from another list (unified inbox, + // contact activity) pages over the ids that list handed us, and a message + // that is in neither (e.g. a group-inbox message not in the folder page) + // gets a one-element list — otherwise the pager would render `emails[0]` + // while the toolbar acted on the tapped message. + const emails = React.useMemo(() => { + const { emailIds, emailId, threadId } = route.params; + if (emailIds && emailIds.length > 0) { + const byId = jmapAccountId ? null : new Map(storeEmails.map((e) => [e.id, e])); + return emailIds.map((id) => byId?.get(id) ?? ({ id, threadId } as Email)); + } + if (!jmapAccountId && storeEmails.some((e) => e.id === emailId)) return storeEmails; + return [{ id: emailId, threadId } as Email]; + }, [storeEmails, route.params, jmapAccountId]); // The JMAP account the open message belongs to: the route param when the // unified inbox opened a group message, otherwise the account behind the diff --git a/src/screens/UnifiedInboxScreen.tsx b/src/screens/UnifiedInboxScreen.tsx index a6081c37..96b7b1a5 100644 --- a/src/screens/UnifiedInboxScreen.tsx +++ b/src/screens/UnifiedInboxScreen.tsx @@ -69,6 +69,11 @@ export default function UnifiedInboxScreen({ navigation }: Props) { await switchAccount(email.sourceAccountId); if (useAuthStore.getState().activeAccountId !== email.sourceAccountId) return; } + // Page over the rows of the same account the user is looking at + // (ids are only unique per JMAP account, so never mix accounts). + const emailIds = emails + .filter((e) => e.sourceAccountId === email.sourceAccountId && e.jmapAccountId === email.jmapAccountId) + .map((e) => e.id); navigation.navigate('EmailThread', { emailId: email.id, threadId: email.threadId, @@ -76,13 +81,14 @@ export default function UnifiedInboxScreen({ navigation }: Props) { // Group/shared messages live under another JMAP account in the // same session; pass it so the thread opens against the right one. jmapAccountId: email.isShared ? email.jmapAccountId : undefined, + emailIds, }); } finally { setOpening(false); } })(); }, - [opening, switchAccount, navigation], + [opening, switchAccount, navigation, emails], ); const errorCount = Object.keys(errors).length;