From c6cb44db61b7919f0b1db53339830f99e6149d4c Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:20:48 +0200 Subject: [PATCH] fix: apply the text filters once typing pauses instead of querying per keystroke --- src/screens/EmailListScreen.tsx | 48 +++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/screens/EmailListScreen.tsx b/src/screens/EmailListScreen.tsx index a69215f1..1058903e 100644 --- a/src/screens/EmailListScreen.tsx +++ b/src/screens/EmailListScreen.tsx @@ -316,6 +316,38 @@ const EmailListItem = React.memo(function EmailListItem({ ); }); +/** + * A text filter that applies once typing pauses (or on Return), like the main + * search: applying every keystroke ran a server query per character. + */ +function DebouncedFilterInput({ + value, + onCommit, + ...props +}: Omit, 'value' | 'onChangeText'> & { + value: string; + onCommit: (value: string) => void; +}) { + const [text, setText] = React.useState(value); + React.useEffect(() => { setText(value); }, [value]); + const commitRef = React.useRef(onCommit); + commitRef.current = onCommit; + React.useEffect(() => { + if (text === value) return undefined; + const id = setTimeout(() => commitRef.current(text), 600); + return () => clearTimeout(id); + }, [text, value]); + return ( + { if (text !== value) onCommit(text); }} + /> + ); +} + function EmailRowSeparator() { const c = useColors(); const styles = React.useMemo(() => makeStyles(c), [c]); @@ -1575,9 +1607,9 @@ export default function EmailListScreen({ {t('advanced_search.from', 'From')} - setFilterField('from', v)} + onCommit={(v) => setFilterField('from', v)} placeholder={t('advanced_search.from_placeholder', 'Sender email or name')} placeholderTextColor={c.textMuted} autoCapitalize="none" @@ -1587,9 +1619,9 @@ export default function EmailListScreen({ {t('advanced_search.to', 'To')} - setFilterField('to', v)} + onCommit={(v) => setFilterField('to', v)} placeholder={t('advanced_search.to_placeholder', 'Recipient email or name')} placeholderTextColor={c.textMuted} autoCapitalize="none" @@ -1601,9 +1633,9 @@ export default function EmailListScreen({ {t('advanced_search.subject', 'Subject')} - setFilterField('subject', v)} + onCommit={(v) => setFilterField('subject', v)} placeholder={t('advanced_search.subject_placeholder', 'Subject contains...')} placeholderTextColor={c.textMuted} style={styles.filterFieldInput} @@ -1612,9 +1644,9 @@ export default function EmailListScreen({ {t('advanced_search.body', 'Body')} - setFilterField('body', v)} + onCommit={(v) => setFilterField('body', v)} placeholder={t('advanced_search.body_placeholder', 'Body contains...')} placeholderTextColor={c.textMuted} style={styles.filterFieldInput}