🐛 Fixed stupid app state updated twice
This commit is contained in:
@@ -455,18 +455,20 @@ class NetworkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func connectWebSocket(token: String, serverUrl: String) {
|
func connectWebSocket(token: String, serverUrl: String) {
|
||||||
connectLock.lock()
|
|
||||||
defer { connectLock.unlock() }
|
|
||||||
|
|
||||||
webSocketQueue.async { [weak self] in
|
webSocketQueue.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.connectLock.lock()
|
||||||
|
defer { self.connectLock.unlock() }
|
||||||
|
|
||||||
// Prevent redundant connection attempts
|
// Prevent redundant connection attempts
|
||||||
if self.currentConnectionState == .connecting || self.currentConnectionState == .connected {
|
if self.currentConnectionState == .connecting || self.currentConnectionState == .connected {
|
||||||
print("[WebSocket] Already connecting or connected, ignoring new connect request.")
|
print("[WebSocket] Already connecting or connected, ignoring new connect request.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.currentConnectionState = .connecting
|
||||||
|
|
||||||
// Ensure any existing task is cancelled before starting a new one
|
// Ensure any existing task is cancelled before starting a new one
|
||||||
self.webSocketTask?.cancel(with: .goingAway, reason: nil)
|
self.webSocketTask?.cancel(with: .goingAway, reason: nil)
|
||||||
self.webSocketTask = nil
|
self.webSocketTask = nil
|
||||||
@@ -490,13 +492,12 @@ class NetworkService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
print("[WebSocket] Trying connecting to \(url)")
|
|
||||||
self.currentConnectionState = .connecting
|
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
|
print("[WebSocket] Trying connecting to \(url)")
|
||||||
|
|
||||||
self.webSocketTask = self.session.webSocketTask(with: request)
|
self.webSocketTask = self.session.webSocketTask(with: request)
|
||||||
self.webSocketTask?.resume()
|
self.webSocketTask?.resume()
|
||||||
|
|
||||||
|
|||||||
@@ -19,22 +19,34 @@ class AppState: ObservableObject {
|
|||||||
let networkService = NetworkService()
|
let networkService = NetworkService()
|
||||||
private var wcService = WatchConnectivityService()
|
private var wcService = WatchConnectivityService()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
private var hasAttemptedConnection = false
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
wcService.$token.combineLatest(wcService.$serverUrl)
|
wcService.$token.combineLatest(wcService.$serverUrl, wcService.$isFetched)
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] token, serverUrl in
|
.sink { [weak self] (token: String?, serverUrl: String?, isFetched: Bool?) in
|
||||||
self?.token = token
|
guard let self = self else { return }
|
||||||
self?.serverUrl = serverUrl
|
|
||||||
if let token = token, let serverUrl = serverUrl {
|
self.token = token
|
||||||
self?.isReady = true
|
self.serverUrl = serverUrl
|
||||||
// Auto-connect WebSocket here
|
|
||||||
self?.networkService.connectWebSocket(token: token, serverUrl: serverUrl)
|
if let token = token, let serverUrl = serverUrl, !token.isEmpty, !serverUrl.isEmpty {
|
||||||
} else {
|
self.isReady = true
|
||||||
self?.isReady = false
|
// Only connect once when we have valid credentials and tried fetch from phone
|
||||||
// Disconnect WebSocket if token or serverUrl become nil
|
if !self.hasAttemptedConnection && isFetched == true {
|
||||||
self?.networkService.disconnectWebSocket()
|
self.hasAttemptedConnection = true
|
||||||
} }
|
print("[AppState] Connecting WebSocket to server: \(serverUrl)")
|
||||||
|
self.networkService.connectWebSocket(token: token, serverUrl: serverUrl)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.isReady = false
|
||||||
|
if self.hasAttemptedConnection {
|
||||||
|
self.hasAttemptedConnection = false
|
||||||
|
// Disconnect WebSocket if token or serverUrl become invalid
|
||||||
|
self.networkService.disconnectWebSocket()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import Combine
|
|||||||
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
||||||
@Published var token: String?
|
@Published var token: String?
|
||||||
@Published var serverUrl: String?
|
@Published var serverUrl: String?
|
||||||
|
@Published var isFetched: Bool?
|
||||||
|
|
||||||
private let session: WCSession
|
private let session: WCSession
|
||||||
private let userDefaults = UserDefaults.standard
|
private let userDefaults = UserDefaults.standard
|
||||||
@@ -30,6 +31,7 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
|||||||
// Load cached data
|
// Load cached data
|
||||||
self.token = userDefaults.string(forKey: tokenKey)
|
self.token = userDefaults.string(forKey: tokenKey)
|
||||||
self.serverUrl = userDefaults.string(forKey: serverUrlKey)
|
self.serverUrl = userDefaults.string(forKey: serverUrlKey)
|
||||||
|
self.isFetched = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
@@ -58,7 +60,13 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func requestDataFromPhone() {
|
func requestDataFromPhone() {
|
||||||
|
if self.isFetched == true {
|
||||||
|
print("[watchOS] Skipped fetch from phone due to tried.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
guard session.isReachable else {
|
guard session.isReachable else {
|
||||||
|
self.isFetched = true
|
||||||
print("[watchOS] Phone is not reachable")
|
print("[watchOS] Phone is not reachable")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -68,6 +76,7 @@ class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
print("[watchOS] Received reply: \(response)")
|
print("[watchOS] Received reply: \(response)")
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
self.isFetched = true
|
||||||
if let token = response["token"] as? String {
|
if let token = response["token"] as? String {
|
||||||
self.token = token
|
self.token = token
|
||||||
self.userDefaults.set(token, forKey: self.tokenKey)
|
self.userDefaults.set(token, forKey: self.tokenKey)
|
||||||
|
|||||||
@@ -49,9 +49,6 @@ struct ExploreView: View {
|
|||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
} else {
|
} else {
|
||||||
ProgressView { Text("Connecting to phone...") }
|
ProgressView { Text("Connecting to phone...") }
|
||||||
.onAppear {
|
|
||||||
appState.requestData()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $isComposing) {
|
.sheet(isPresented: $isComposing) {
|
||||||
|
|||||||
Reference in New Issue
Block a user