ios: fix keyboard behavior
This commit is contained in:
@@ -8,8 +8,19 @@ Instructions for work under `/Users/buzzert/src/sybil-2/ios`.
|
|||||||
- `just build` will:
|
- `just build` will:
|
||||||
1. generate `Sybil.xcodeproj` with `xcodegen` if missing,
|
1. generate `Sybil.xcodeproj` with `xcodegen` if missing,
|
||||||
2. build scheme `Sybil` for `iPhone 16e` simulator.
|
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.
|
- 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 Structure
|
||||||
- App target entry: `/Users/buzzert/src/sybil-2/ios/Apps/Sybil/Sources/SybilApp.swift`
|
- App target entry: `/Users/buzzert/src/sybil-2/ios/Apps/Sybil/Sources/SybilApp.swift`
|
||||||
- Shared iOS app code lives in Swift package:
|
- Shared iOS app code lives in Swift package:
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ struct SybilWorkspaceView: View {
|
|||||||
return "chat:none"
|
return "chat:none"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var shouldAutoFocusComposer: Bool {
|
||||||
|
viewModel.displayedMessages.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
private var composerFocusPolicyID: String {
|
||||||
|
"\(transcriptScrollContextID):\(composerFocusRequest):\(shouldAutoFocusComposer)"
|
||||||
|
}
|
||||||
|
|
||||||
private var canSwipeToCreateChat: Bool {
|
private var canSwipeToCreateChat: Bool {
|
||||||
guard onRequestNewChat != nil else {
|
guard onRequestNewChat != nil else {
|
||||||
return false
|
return false
|
||||||
@@ -124,8 +132,8 @@ struct SybilWorkspaceView: View {
|
|||||||
}
|
}
|
||||||
resetNewChatSwipe(animated: false)
|
resetNewChatSwipe(animated: false)
|
||||||
}
|
}
|
||||||
.task(id: composerFocusRequest) {
|
.task(id: composerFocusPolicyID) {
|
||||||
await focusComposerIfRequested()
|
await applyComposerFocusPolicy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,15 +354,13 @@ struct SybilWorkspaceView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func focusComposerIfRequested() async {
|
private func applyComposerFocusPolicy() async {
|
||||||
guard composerFocusRequest > 0 else {
|
guard shouldAutoFocusComposer else {
|
||||||
|
composerFocused = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.yield()
|
guard shouldAutoFocusComposer, viewModel.showsComposer else {
|
||||||
try? await Task.sleep(for: .milliseconds(80))
|
|
||||||
|
|
||||||
guard viewModel.showsComposer, !viewModel.isSearchMode else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
composerFocused = true
|
composerFocused = true
|
||||||
|
|||||||
22
ios/justfile
22
ios/justfile
@@ -1,10 +1,28 @@
|
|||||||
|
simulator := "platform=iOS Simulator,name=iPhone 16e,OS=latest"
|
||||||
|
simulator_name := "iPhone 16e"
|
||||||
|
derived_data := "build/DerivedData"
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@just build
|
@just build
|
||||||
|
|
||||||
build:
|
build:
|
||||||
if [ ! -d "Sybil.xcodeproj" ]; then xcodegen --spec project.yml; fi
|
if [ ! -d "Sybil.xcodeproj" ]; then xcodegen --spec project.yml; fi
|
||||||
if command -v xcbeautify >/dev/null 2>&1; then \
|
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 \
|
else \
|
||||||
xcodebuild -scheme Sybil -destination 'platform=iOS Simulator,name=iPhone 16e,OS=latest'; \
|
xcodebuild -scheme Sybil -destination '{{simulator}}'; \
|
||||||
fi
|
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}}'
|
||||||
|
|||||||
Reference in New Issue
Block a user