🐛 Fixed stupid app state updated twice

This commit is contained in:
2025-10-30 23:58:05 +08:00
parent 402bb3fe04
commit 3edcdd72af
4 changed files with 42 additions and 23 deletions

View File

@@ -455,18 +455,20 @@ class NetworkService {
}
func connectWebSocket(token: String, serverUrl: String) {
connectLock.lock()
defer { connectLock.unlock() }
webSocketQueue.async { [weak self] in
guard let self = self else { return }
self.connectLock.lock()
defer { self.connectLock.unlock() }
// Prevent redundant connection attempts
if self.currentConnectionState == .connecting || self.currentConnectionState == .connected {
print("[WebSocket] Already connecting or connected, ignoring new connect request.")
return
}
self.currentConnectionState = .connecting
// Ensure any existing task is cancelled before starting a new one
self.webSocketTask?.cancel(with: .goingAway, reason: nil)
self.webSocketTask = nil
@@ -490,13 +492,12 @@ class NetworkService {
return
}
print("[WebSocket] Trying connecting to \(url)")
self.currentConnectionState = .connecting
var request = URLRequest(url: url)
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
print("[WebSocket] Trying connecting to \(url)")
self.webSocketTask = self.session.webSocketTask(with: request)
self.webSocketTask?.resume()

View File

@@ -19,22 +19,34 @@ class AppState: ObservableObject {
let networkService = NetworkService()
private var wcService = WatchConnectivityService()
private var cancellables = Set<AnyCancellable>()
private var hasAttemptedConnection = false
init() {
wcService.$token.combineLatest(wcService.$serverUrl)
wcService.$token.combineLatest(wcService.$serverUrl, wcService.$isFetched)
.receive(on: DispatchQueue.main)
.sink { [weak self] token, serverUrl in
self?.token = token
self?.serverUrl = serverUrl
if let token = token, let serverUrl = serverUrl {
self?.isReady = true
// Auto-connect WebSocket here
self?.networkService.connectWebSocket(token: token, serverUrl: serverUrl)
.sink { [weak self] (token: String?, serverUrl: String?, isFetched: Bool?) in
guard let self = self else { return }
self.token = token
self.serverUrl = serverUrl
if let token = token, let serverUrl = serverUrl, !token.isEmpty, !serverUrl.isEmpty {
self.isReady = true
// Only connect once when we have valid credentials and tried fetch from phone
if !self.hasAttemptedConnection && isFetched == true {
self.hasAttemptedConnection = true
print("[AppState] Connecting WebSocket to server: \(serverUrl)")
self.networkService.connectWebSocket(token: token, serverUrl: serverUrl)
}
} else {
self?.isReady = false
// Disconnect WebSocket if token or serverUrl become nil
self?.networkService.disconnectWebSocket()
} }
self.isReady = false
if self.hasAttemptedConnection {
self.hasAttemptedConnection = false
// Disconnect WebSocket if token or serverUrl become invalid
self.networkService.disconnectWebSocket()
}
}
}
.store(in: &cancellables)
}

View File

@@ -14,6 +14,7 @@ import Combine
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
@Published var token: String?
@Published var serverUrl: String?
@Published var isFetched: Bool?
private let session: WCSession
private let userDefaults = UserDefaults.standard
@@ -30,6 +31,7 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
// Load cached data
self.token = userDefaults.string(forKey: tokenKey)
self.serverUrl = userDefaults.string(forKey: serverUrlKey)
self.isFetched = false
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
@@ -58,7 +60,13 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
}
func requestDataFromPhone() {
if self.isFetched == true {
print("[watchOS] Skipped fetch from phone due to tried.")
return
}
guard session.isReachable else {
self.isFetched = true
print("[watchOS] Phone is not reachable")
return
}
@@ -68,6 +76,7 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
guard let self = self else { return }
print("[watchOS] Received reply: \(response)")
DispatchQueue.main.async {
self.isFetched = true
if let token = response["token"] as? String {
self.token = token
self.userDefaults.set(token, forKey: self.tokenKey)

View File

@@ -49,9 +49,6 @@ struct ExploreView: View {
.environmentObject(appState)
} else {
ProgressView { Text("Connecting to phone...") }
.onAppear {
appState.requestData()
}
}
}
.sheet(isPresented: $isComposing) {