mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 16:05:39 +00:00
fix: start another folder, tag or search at the top of its list (bulwarkmail/webmail#1138)
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { listViewKey } from '../list-view-key';
|
||||
|
||||
// The list kept its scroll offset when the folder, tag or search changed, so
|
||||
// the new list opened somewhere in the middle (webmail #1138).
|
||||
|
||||
describe('list scroll position on a view switch (bulwarkmail/webmail#1138)', () => {
|
||||
it('changes with the folder, the search and the tag, and only with them', () => {
|
||||
const base = listViewKey('inbox', '', {});
|
||||
expect(listViewKey('inbox', '', {})).toBe(base);
|
||||
expect(listViewKey('inbox', ' ', {})).toBe(base);
|
||||
expect(listViewKey('archive', '', {})).not.toBe(base);
|
||||
expect(listViewKey('inbox', 'invoice', {})).not.toBe(base);
|
||||
expect(listViewKey('inbox', '', { keyword: '$label:red' })).not.toBe(base);
|
||||
});
|
||||
|
||||
it('scrolls the list to the top when it changes', () => {
|
||||
const list = fs.readFileSync(path.resolve(__dirname, '../../screens/EmailListScreen.tsx'), 'utf8');
|
||||
expect(list).toMatch(/ref=\{listRef\}/);
|
||||
expect(list).toMatch(/listRef\.current\?\.scrollToOffset\(\{ offset: 0, animated: false \}\);\s*\}, \[viewKey\]\);/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* What the message list shows, as one string: the folder, the search and the
|
||||
* filters (a tag view is a keyword filter). The list scrolls back to the top
|
||||
* when it changes, so another folder, tag or search doesn't open at the
|
||||
* offset the last one was left at (webmail #1138).
|
||||
*/
|
||||
export function listViewKey(
|
||||
currentMailboxId: string | null,
|
||||
searchQuery: string,
|
||||
filters: object,
|
||||
): string {
|
||||
return JSON.stringify([currentMailboxId, searchQuery.trim(), filters]);
|
||||
}
|
||||
@@ -63,6 +63,7 @@ import {
|
||||
import { isPermanentDelete, confirmPermanentDelete } from '../lib/delete-confirm';
|
||||
import { confirmMailRemoval } from '../lib/mail-removal-confirm';
|
||||
import { moveSheetCurrentId } from '../lib/move-targets';
|
||||
import { listViewKey } from '../lib/list-view-key';
|
||||
import { draftContextFromEmail, isDraftEmail } from '../lib/draft-context';
|
||||
import { getFullEmail, emptyMailbox as apiEmptyMailbox } from '../api/email';
|
||||
import type { RootStackParamList } from '../navigation/types';
|
||||
@@ -458,6 +459,13 @@ export default function EmailListScreen({
|
||||
const currentMailboxId = useEmailStore((s) => s.currentMailboxId);
|
||||
const storeSearchQuery = useEmailStore((s) => s.searchQuery);
|
||||
const filters = useEmailStore((s) => s.filters);
|
||||
// Another folder, tag or search starts at the top of its list, not at the
|
||||
// offset the last one was scrolled to (webmail #1138).
|
||||
const listRef = React.useRef<FlatList<Email>>(null);
|
||||
const viewKey = listViewKey(currentMailboxId, storeSearchQuery, filters);
|
||||
React.useEffect(() => {
|
||||
listRef.current?.scrollToOffset({ offset: 0, animated: false });
|
||||
}, [viewKey]);
|
||||
const accountErrors = useEmailStore((s) => s.accountErrors);
|
||||
const fetchMailboxes = useEmailStore((s) => s.fetchMailboxes);
|
||||
const ensureMailboxes = useEmailStore((s) => s.ensureMailboxes);
|
||||
@@ -1688,6 +1696,7 @@ export default function EmailListScreen({
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
ref={listRef}
|
||||
data={visibleEmails}
|
||||
keyExtractor={emailKeyExtractor}
|
||||
renderItem={renderEmailRow}
|
||||
|
||||
Reference in New Issue
Block a user