Skip to content

feat(swift-ios): let readers dismiss the keyboard over a long draft - #7501

Open
saphid wants to merge 2 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/issue125-swiftui-keyboard-dismiss
Open

feat(swift-ios): let readers dismiss the keyboard over a long draft#7501
saphid wants to merge 2 commits into
pingdotgg:t3code/rebuild-mobile-app-swiftfrom
saphid:agent/issue125-swiftui-keyboard-dismiss

Conversation

@saphid

@saphid saphid commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Observed problem and reproduction

Open a SwiftUI thread, type a draft long enough to reach the composer's line cap, and raise the keyboard. The composer and keyboard can cover most of the transcript. The reader needs an obvious way to put the keyboard away without losing or collapsing the draft.

Cause

Thread detail had keyboard-dismiss gestures but no visible, deterministic control in the composer footer. The target branch now supplies the gesture behavior itself: transcript dragging keeps its upstream .onDrag behavior, and the UIKit-backed composer handles a downward drag without giving up normal long-draft scrolling.

Change and boundary

This PR now adds only a 44-point Hide keyboard footer button to the thread-detail composer. The control appears while that composer is focused, calls the target branch's existing dismiss handler, and leaves the draft unchanged and expanded.

The branch was rebased onto b67837984e5650888b1eed0e1cd7fff83625f696. During conflict resolution, the target's ThreadDetailView was accepted unchanged and the remaining button was re-expressed as an explicit opt-in. The target's transcript scrolling, composer drag recognizer, long-draft sizing, and New Thread integration are preserved.

Non-goals

This PR no longer changes transcript drag direction or thresholds; the target branch superseded that part of the original patch. New-thread and workspace composers do not gain the footer button. There are no draft-persistence, server, provider, contract, or connection changes, and the composer line cap is unchanged.

Affected areas

Affected client: SwiftUI mobile thread detail only.

Platforms: iOS.

Providers, contracts, and connection modes: unchanged.

States: focused and unfocused thread composer, keyboard visible and hidden, and non-empty draft preservation.

Validation

Current local head: 4b90652c1fa3c686c20c82221928e04b3ce92df2.

git diff --check upstream/t3code/rebuild-mobile-app-swift...HEAD passed. The target-relative diff is limited to the opt-in footer control, its thread-detail call site, and focused policy tests.

The intended focused run is:

~/.agents/skills/ios-build-hygiene/scripts/run-xcodebuild-clean.sh -- \
  -project apps/swift-ios/T3Code.xcodeproj \
  -scheme T3Code \
  -destination 'platform=iOS Simulator,id=6224940C-3FA9-4DB0-8FD4-33EABD9A1A65' \
  test \
  -only-testing:T3CodeTests/ThreadKeyboardDismissTests \
  -only-testing:T3CodeTests/FeatureComposerPowerTests

Both bounded attempts were safely deferred with exit 75 before Xcode started because another XcodeBuildMCP session owns the native hygiene lane. CI shown before the force-push belongs to the superseded head and is not claimed for this commit.

Risks, untested paths, and known gaps

  • The control intentionally consumes one footer slot only while the thread composer is focused.
  • Cross-provider review was not launched because the user explicitly prohibited Claude; no independent review receipt is claimed.
  • Known gaps: current-head light and dark screenshots plus the long-draft interaction video are pending. The proof lock was free, but the active native hygiene owner prevented building, installing, and hash-binding this exact head on the canonical simulator. Existing media was captured from a8b87f3e9026b26ad4617019b2a1782feebd330d and is historical only.

Evidence

Historical evidence from the pre-rebase head (not valid as exact-head proof):

Owning issue and stack

Owning issue: saphid/t3code-personal#125. This PR targets t3code/rebuild-mobile-app-swift. Maintainer edits are enabled.


Note

Low Risk
Localized SwiftUI UI in thread detail with opt-in defaults; no auth, data, or server changes.

Overview
Adds an opt-in Hide keyboard icon button to the expanded composer footer so thread readers can dismiss the keyboard without losing a long draft.

The control is gated by showsKeyboardDismissControl (defaults to false) and FeatureComposerKeyboardDismissPolicy, which requires focus, the flag, and an onDismissKeyboard handler. Thread detail enables it and routes taps to the existing dismissKeyboard path (clears composer focus and resigns first responder). Other composer call sites stay unchanged.

Tests cover when the button should appear and that FeatureComposerCollapsePolicy keeps a non-empty draft expanded after focus is lost.

Reviewed by Cursor Bugbot for commit 7fa7bd1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add keyboard dismiss button to FeatureComposerView

  • Adds a showsKeyboardDismissControl parameter to FeatureComposerView.init that renders a dismissKeyboardButton in the composer footer when the composer is focused, the feature is enabled, and an onDismissKeyboard handler is provided.
  • Gates visibility through the new FeatureComposerKeyboardDismissPolicy.showsDismissControl(isFocused:isEnabled:canDismiss:) helper.
  • Enables the control on ThreadDetailView and adds unit tests covering show/hide conditions and draft-collapse policy.
  • Behavioral Change: ThreadDetailView now shows a "Hide keyboard" control in the composer footer; no change for other call sites that do not pass showsKeyboardDismissControl.

Macroscope summarized 7fa7bd1.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4791b1b8-53ec-4829-9b03-28c2fba4221d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a localized Hide keyboard control to the production thread-detail composer and enables it by default for that flow. Although the implementation is small and preserves existing drafts and other composer call sites, it changes the product’s default user experience.

You can add or adjust custom eligibility rules. Learn more.

@saphid
saphid force-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3 Compare August 19, 2026 21:16
A grown composer plus the keyboard covered the whole transcript with no
way back to reading it. Two iOS-conventional exits, both draft-preserving:

- The transcript now uses `keyboardDismissMode = .interactive` and tracks
  the drag itself. The transcript is laid out above the keyboard, so
  `.interactive` alone never engages; a downward drag past 16pt — reaching
  back through a bottom-anchored thread — dismisses immediately wherever it
  starts. Upward nudges toward the latest turn keep the draft editable,
  replacing the previous dismiss-on-any-drag behaviour.
- The composer footer gains a `keyboard.chevron.compact.down` control while
  focused. It only drops focus, so the draft and its caret survive, and it
  is opt-in per call site — the thread page passes a handler, other
  composers do not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@saphid
saphid force-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652 Compare August 28, 2026 12:50
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant