Skip to content

Delay picker and select opens until the keyboard dismisses#143

Merged
Gamius00 merged 1 commit into
mainfrom
codex/triage-issue-128
Jun 26, 2026
Merged

Delay picker and select opens until the keyboard dismisses#143
Gamius00 merged 1 commit into
mainfrom
codex/triage-issue-128

Conversation

@FleetAdmiralJakob

@FleetAdmiralJakob FleetAdmiralJakob commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes Overflowing Bottomsheet and Keyboard on create Homework Page #128 by delaying create-entry picker and select-sheet presentation until the active software keyboard has been dismissed.
  • Routes the create-entry subject, exam-type, date, and time triggers through guarded open helpers so modal picker surfaces do not compete with focused text inputs.
  • Cleans up pending keyboard listeners, fallback timers, and animation frames when picker surfaces close or the screen unmounts.

Issue

Fixes #128

Testing

  • pnpm typecheck
  • pnpm lint
  • git diff --check
  • CodeRabbit CLI in WSL: coderabbit review --agent -t uncommitted -c AGENTS.md raised 0 issues

Manual Verification

  • Not run here: physical Android device/emulator verification for the exact Notizen -> Schulfach keyboard overlap flow.

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced date/time picker and selection modal interactions with keyboard visibility to ensure smoother modal opening after keyboard dismissal.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds keyboard-dismiss coordination to the new entry form in src/app/entry/new.tsx. A fallback timeout constant and three refs track a keyboard-hide subscription, a timeout, and an animation-frame handle. A new openAfterKeyboardDismiss function dismisses the keyboard, waits for the hide event or fallback, then opens the modal. All picker and select UI triggers are updated to call openPicker/openSelect instead of setting state directly.

Changes

Keyboard-Aware Modal Opening in Entry Form

Layer / File(s) Summary
Fallback constant and coordination refs
src/app/entry/new.tsx
Adds KEYBOARD_DISMISS_FALLBACK_MS constant and three new refs (keyboard-hide subscription, fallback timeout, animation-frame handle) that the coordination logic depends on.
Keyboard-aware open/close lifecycle
src/app/entry/new.tsx
Implements clearPendingModalOpen, openAfterKeyboardDismiss (dismisses keyboard, waits for hide event or fallback, then opens modal via requestAnimationFrame), openPicker/openSelect wrappers, and updated close handlers that clear pending resources.
UI trigger call-site updates
src/app/entry/new.tsx
Replaces direct setPickerTarget/setSelectTarget calls with openPicker/openSelect in all homework and exam pill/trigger handlers (due-date, planned-date, planned-time, planned-end-time, subject, exam type).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 The keyboard would pop up and block every sheet,
So I added a fallback with timing so neat.
A ref for the timeout, a frame for the wait,
Now modals open smoothly — never too late!
Hop, hop, dismiss first, then animate free~ 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the main change: delaying picker and select modal opens until keyboard dismissal, which is the core objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/triage-issue-128

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/entry/new.tsx`:
- Around line 300-333: The openAfterKeyboardDismiss function queues modal opens
that may execute after the user navigates to a different step, causing stale
callbacks to modify the wrong step's state. You need to call
clearPendingModalOpen() before all step-changing operations (anywhere setStep is
called in this component) to ensure pending modal opens are cancelled when the
user navigates away. This prevents the queued open callback from executing after
the step context has changed and setting pickerTarget or selectTarget in the
wrong step.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f4a1009-e2fd-46cc-bc5b-5e144e2432cb

📥 Commits

Reviewing files that changed from the base of the PR and between 9531c85 and 2426cb9.

📒 Files selected for processing (1)
  • src/app/entry/new.tsx

Comment thread src/app/entry/new.tsx
Comment on lines +300 to +333
useEffect(() => clearPendingModalOpen, [clearPendingModalOpen]);

const openAfterKeyboardDismiss = useCallback(
(open: () => void) => {
clearPendingModalOpen();
const isKeyboardVisible = Keyboard.isVisible();

if (!isKeyboardVisible) {
Keyboard.dismiss();
open();
return;
}

let didOpen = false;
const finishOpen = () => {
if (didOpen) return;
didOpen = true;
clearPendingModalOpen();
keyboardDismissFrameRef.current = requestAnimationFrame(() => {
keyboardDismissFrameRef.current = null;
open();
});
};

keyboardHideSubscriptionRef.current = Keyboard.addListener(
"keyboardDidHide",
finishOpen,
);
keyboardDismissFallbackRef.current = setTimeout(
finishOpen,
KEYBOARD_DISMISS_FALLBACK_MS,
);
Keyboard.dismiss();
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Cancel queued opens before changing steps.

Line 302 queues the modal open outside React state, but step transitions still call setStep(...) without clearing that queue. If the keyboard is hiding and the user taps Back/Weiter before keyboardDidHide or the fallback fires, the stale open() can set pickerTarget/selectTarget after the UI has moved to another step.

🐛 Proposed fix
 const handleBack = useCallback(() => {
+	clearPendingModalOpen();
+
 	if (selectTarget) {
 		setSelectTarget(null);
 		return true;
 	}
@@
 	goBackOrReplace(router, "/home");
 	return true;
-}, [pickerTarget, router, selectTarget, step]);
+}, [clearPendingModalOpen, pickerTarget, router, selectTarget, step]);

Also clear before other step-changing paths:

 if (isHomework) {
+	clearPendingModalOpen();
 	setStep("success");
 	return;
 }
@@
 if (step === "basics") {
+	clearPendingModalOpen();
 	setStep("planning");
 	return;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/entry/new.tsx` around lines 300 - 333, The openAfterKeyboardDismiss
function queues modal opens that may execute after the user navigates to a
different step, causing stale callbacks to modify the wrong step's state. You
need to call clearPendingModalOpen() before all step-changing operations
(anywhere setStep is called in this component) to ensure pending modal opens are
cancelled when the user navigates away. This prevents the queued open callback
from executing after the step context has changed and setting pickerTarget or
selectTarget in the wrong step.

@Gamius00
Gamius00 merged commit 7926665 into main Jun 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Overflowing Bottomsheet and Keyboard on create Homework Page

2 participants