diff --git a/src/screens/EmailThreadScreen.tsx b/src/screens/EmailThreadScreen.tsx index cb1ed143..dbeec789 100644 --- a/src/screens/EmailThreadScreen.tsx +++ b/src/screens/EmailThreadScreen.tsx @@ -1022,6 +1022,19 @@ function EmailPane({ React.useEffect(() => () => { readTimers.forEach((cancel) => cancel()); readTimers.clear(); }, [readTimers]); + // Keeps the quick reply in view while the keyboard opens. Above the + // skeleton's early return: a page opened by id alone (a notification) + // renders the skeleton first, and a hook after it crashed the app. + const scrollRef = React.useRef(null); + const isInputFocused = React.useRef(false); + React.useEffect(() => { + if (kbObstruction > 0 && isInputFocused.current) { + setTimeout(() => { + scrollRef.current?.scrollToEnd({ animated: true }); + }, 50); + } + }, [kbObstruction]); + const toggleCard = (mid: string) => { setExpanded((prev) => { const next = new Set(prev ?? []); @@ -1069,9 +1082,6 @@ function EmailPane({ onZoomChange(z); }; - const scrollRef = React.useRef(null); - const isInputFocused = React.useRef(false); - const bottomPadding = kbObstruction > 0 ? kbObstruction + spacing.md : bottomBarHeight + spacing.lg; @@ -1087,14 +1097,6 @@ function EmailPane({ isInputFocused.current = false; }; - React.useEffect(() => { - if (kbObstruction > 0 && isInputFocused.current) { - setTimeout(() => { - scrollRef.current?.scrollToEnd({ animated: true }); - }, 50); - } - }, [kbObstruction]); - return (