mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-22 04:21:40 +08:00
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:
+69
@@ -0,0 +1,69 @@
|
||||
import Foundation
|
||||
|
||||
public final class AuthAccessTokenCache: @unchecked Sendable {
|
||||
public static let shared = AuthAccessTokenCache()
|
||||
|
||||
private struct Entry {
|
||||
let token: String
|
||||
let expiresAt: Date
|
||||
}
|
||||
|
||||
private let lock = NSLock()
|
||||
private var entries: [String: Entry] = [:]
|
||||
|
||||
private init() {}
|
||||
|
||||
public func set(_ token: String, expiresAt: Date, for endpoint: String) {
|
||||
guard let key = Self.canonicalOrigin(endpoint) else { return }
|
||||
lock.lock()
|
||||
entries[key] = Entry(token: token, expiresAt: expiresAt)
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
public func token(for endpoint: URL, minimumValidity: TimeInterval = 0) -> String? {
|
||||
token(for: endpoint, matching: nil, minimumValidity: minimumValidity)
|
||||
}
|
||||
|
||||
public func token(
|
||||
for endpoint: URL,
|
||||
matching origin: URL?,
|
||||
minimumValidity: TimeInterval = 0
|
||||
) -> String? {
|
||||
guard let key = Self.canonicalOrigin(endpoint) else { return nil }
|
||||
if let origin, Self.canonicalOrigin(origin) != key { return nil }
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
|
||||
guard let entry = entries[key], entry.expiresAt.timeIntervalSinceNow > minimumValidity else {
|
||||
return nil
|
||||
}
|
||||
return entry.token
|
||||
}
|
||||
|
||||
public func remove(for endpoint: String) {
|
||||
guard let key = Self.canonicalOrigin(endpoint) else { return }
|
||||
lock.lock()
|
||||
entries[key] = nil
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
private static func canonicalOrigin(_ endpoint: String) -> String? {
|
||||
guard let url = URL(string: endpoint) else { return nil }
|
||||
return canonicalOrigin(url)
|
||||
}
|
||||
|
||||
private static func canonicalOrigin(_ url: URL) -> String? {
|
||||
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
||||
let scheme = components.scheme?.lowercased(),
|
||||
let host = components.host?.lowercased()
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let defaultPort = scheme == "https" ? 443 : (scheme == "http" ? 80 : nil)
|
||||
if let port = components.port, port != defaultPort {
|
||||
return "\(scheme)://\(host):\(port)"
|
||||
}
|
||||
return "\(scheme)://\(host)"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user