ios: fix keyboard behavior

This commit is contained in:
2026-05-03 21:52:49 -07:00
parent d1140d21d4
commit 4bc0773d35
3 changed files with 45 additions and 10 deletions

View File

@@ -8,8 +8,19 @@ Instructions for work under `/Users/buzzert/src/sybil-2/ios`.
- `just build` will:
1. generate `Sybil.xcodeproj` with `xcodegen` if missing,
2. build scheme `Sybil` for `iPhone 16e` simulator.
- Preferred test command: `just test`
- `just test` runs the Swift package tests through `xcodebuild test` on the `iPhone 16e` iOS simulator from `ios/Packages/Sybil`.
- `just test` disables Xcode parallel testing because the current async view-model tests use timing-sensitive selection tasks.
- Do not use plain `swift test` for this package; it runs as host macOS and hits a deployment mismatch with `MarkdownUI`.
- If `xcbeautify` is installed it is used automatically; otherwise raw `xcodebuild` output is used.
## Simulator Workflow
- Run the app in the simulator with `just run` from `/Users/buzzert/src/sybil-2/ios`.
- `just run` boots the `iPhone 16e` simulator if needed, builds with a stable derived data path, installs `Sybil.app`, and launches bundle id `net.buzzert.sybil2`.
- Capture a simulator screenshot with `just screenshot` from `/Users/buzzert/src/sybil-2/ios`; it writes `build/sybil-screenshot.png` by default.
- To choose a screenshot path, run `just screenshot path=build/name.png`.
- The underlying screenshot command is `xcrun simctl io booted screenshot <path>` and requires a booted simulator.
## App Structure
- App target entry: `/Users/buzzert/src/sybil-2/ios/Apps/Sybil/Sources/SybilApp.swift`
- Shared iOS app code lives in Swift package:

View File

@@ -62,6 +62,14 @@ struct SybilWorkspaceView: View {
return "chat:none"
}
private var shouldAutoFocusComposer: Bool {
viewModel.displayedMessages.isEmpty
}
private var composerFocusPolicyID: String {
"\(transcriptScrollContextID):\(composerFocusRequest):\(shouldAutoFocusComposer)"
}
private var canSwipeToCreateChat: Bool {
guard onRequestNewChat != nil else {
return false
@@ -124,8 +132,8 @@ struct SybilWorkspaceView: View {
}
resetNewChatSwipe(animated: false)
}
.task(id: composerFocusRequest) {
await focusComposerIfRequested()
.task(id: composerFocusPolicyID) {
await applyComposerFocusPolicy()
}
}
@@ -346,15 +354,13 @@ struct SybilWorkspaceView: View {
}
@MainActor
private func focusComposerIfRequested() async {
guard composerFocusRequest > 0 else {
private func applyComposerFocusPolicy() async {
guard shouldAutoFocusComposer else {
composerFocused = false
return
}
await Task.yield()
try? await Task.sleep(for: .milliseconds(80))
guard viewModel.showsComposer, !viewModel.isSearchMode else {
guard shouldAutoFocusComposer, viewModel.showsComposer else {
return
}
composerFocused = true

View File

@@ -1,10 +1,28 @@
simulator := "platform=iOS Simulator,name=iPhone 16e,OS=latest"
simulator_name := "iPhone 16e"
derived_data := "build/DerivedData"
default:
@just build
build:
if [ ! -d "Sybil.xcodeproj" ]; then xcodegen --spec project.yml; fi
if command -v xcbeautify >/dev/null 2>&1; then \
xcodebuild -scheme Sybil -destination 'platform=iOS Simulator,name=iPhone 16e,OS=latest' | xcbeautify; \
xcodebuild -scheme Sybil -destination '{{simulator}}' | xcbeautify; \
else \
xcodebuild -scheme Sybil -destination 'platform=iOS Simulator,name=iPhone 16e,OS=latest'; \
xcodebuild -scheme Sybil -destination '{{simulator}}'; \
fi
test:
cd Packages/Sybil && xcodebuild test -scheme Sybil -destination '{{simulator}}' -parallel-testing-enabled NO
run:
if [ ! -d "Sybil.xcodeproj" ]; then xcodegen --spec project.yml; fi
xcrun simctl boot '{{simulator_name}}' 2>/dev/null || true
xcodebuild -scheme Sybil -destination '{{simulator}}' -derivedDataPath '{{derived_data}}'
xcrun simctl install booted '{{derived_data}}/Build/Products/Debug-iphonesimulator/Sybil.app'
xcrun simctl launch booted net.buzzert.sybil2
screenshot path="build/sybil-screenshot.png":
mkdir -p "$(dirname '{{path}}')"
xcrun simctl io booted screenshot '{{path}}'