feat(ios): polish onboarding and native sign-in flow (#15217)

## Summary
- Reworks the iOS onboarding, native sign-in, and paywall flow so
first-install and cold-start entry stay native, adaptive, and aligned
with the current login/subscription gates.
- Removes onboarding swipe paging, refines onboarding/paywall layout
behavior, and keeps AI/paywall entry behavior consistent for logged-in
and subscribed users.
- Adds the new mobile all-docs empty states with localized copy and
dialog entry points, and closes the remaining review follow-ups by
removing the onboarding plan artifact and dropping the iOS AI
subscription bypass.

## Test plan
- Built the iOS app for simulator with `xcodebuild -workspace
App.xcworkspace -scheme App -configuration Debug -sdk iphonesimulator
-destination 'generic/platform=iOS Simulator' ARCHS=arm64
ONLY_ACTIVE_ARCH=YES CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
build` during the native onboarding/sign-in flow work.
- Let the repo pre-commit hooks run on the latest follow-up commit
(`prettier` + `eslint --fix`).
- Checked diagnostics for the edited TS/TSX files after the review
follow-up changes.
- Manually iterated on onboarding/native sign-in/paywall UI states in
simulator during implementation.

---------

Co-authored-by: DarkSky <darksky2048@gmail.com>
This commit is contained in:
keepClamDown
2026-08-21 08:12:27 +08:00
committed by GitHub
parent c57004ea2c
commit 73e2d10973
130 changed files with 6478 additions and 2268 deletions

View File

@@ -177,6 +177,7 @@ private extension ChatManager {
timeoutInterval: 10
)
request.setValue("close", forHTTPHeaderField: "Connection")
request = QLService.shared.authorized(request)
let closable = ClosableTask(detachedTask: .detached(operation: {
let eventSource = EventSource()

View File

@@ -70,7 +70,10 @@ public class IntelligentContext {
private init() {}
public func preparePresent(_ completion: @escaping (Result<Void, Error>) -> Void) {
public func preparePresent(
createSession shouldCreateSession: Bool = true,
_ completion: @escaping (Result<Void, Error>) -> Void
) {
assert(webView != nil)
DispatchQueue.global(qos: .userInitiated).async { [self] in
prepareTemporaryDirectory()
@@ -130,6 +133,10 @@ public class IntelligentContext {
let currentDocumentId: String? = webViewMetadata[.currentDocId] as? String
dumpMetadataContents()
guard shouldCreateSession else {
completion(.success(()))
return
}
createSession(
workspaceId: workspaceId,

View File

@@ -6,6 +6,7 @@
//
import Apollo
import AffineGraphQL
import Foundation
extension QLService {
@@ -17,5 +18,36 @@ extension QLService {
self.session.configuration.httpCookieStorage?.setCookie(cookie)
}
}
@discardableResult
override func sendRequest(
_ request: URLRequest,
taskDescription: String?,
rawTaskCompletionHandler: RawCompletion?,
completion: @escaping Completion
) -> URLSessionTask {
super.sendRequest(
QLService.shared.authorized(request),
taskDescription: taskDescription,
rawTaskCompletionHandler: rawTaskCompletionHandler,
completion: completion
)
}
}
}
extension QLService {
func authorized(_ request: URLRequest) -> URLRequest {
guard request.value(forHTTPHeaderField: "Authorization") == nil,
let requestURL = request.url,
let token = AuthAccessTokenCache.shared.token(
for: requestURL, matching: serverBaseURL)
else {
return request
}
var authorized = request
authorized.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
return authorized
}
}