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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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

@saphidsaphid 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

coderabbitaiBot 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-actionsgithub-actionsBot 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

macroscopeappBot 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from 1e3b9bb to a8b87f3CompareAugust 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
saphidforce-pushed the agent/issue125-swiftui-keyboard-dismiss branch from a8b87f3 to 4b90652CompareAugust 28, 2026 12:50
@github-actionsgithub-actionsBot 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@saphid