add to top bar connect

This commit is contained in:
cheykrym 2025-10-21 03:12:35 +03:00
parent 4a2636879d
commit 7c1d46ab77
4 changed files with 72 additions and 1 deletions

View File

@ -27,6 +27,10 @@ struct TopBarView: View {
return title == "Profile" return title == "Profile"
} }
private var shouldShowConnectionStatus: Bool {
viewModel.socketState != .connected
}
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
HStack { HStack {
@ -43,7 +47,10 @@ struct TopBarView: View {
// Spacer() // Spacer()
if isHomeTab{ if shouldShowConnectionStatus {
connectionStatusView
Spacer()
} else if isHomeTab{
Text("Yobble") Text("Yobble")
.font(.largeTitle) .font(.largeTitle)
.fontWeight(.bold) .fontWeight(.bold)
@ -129,6 +136,16 @@ struct TopBarView: View {
} }
private extension TopBarView { private extension TopBarView {
var connectionStatusView: some View {
HStack(spacing: 8) {
ProgressView()
.progressViewStyle(.circular)
Text(NSLocalizedString("Подключение", comment: ""))
.font(.headline)
.foregroundColor(.primary)
}
}
private var normalizedRevealProgress: CGFloat { private var normalizedRevealProgress: CGFloat {
guard isChatsTab else { return 0 } guard isChatsTab else { return 0 }
return max(0, min(chatSearchRevealProgress, 1)) return max(0, min(chatSearchRevealProgress, 1))

View File

@ -1473,6 +1473,9 @@
} }
} }
} }
},
"Подключение" : {
}, },
"Подтверждение пароля" : { "Подтверждение пароля" : {
"comment" : "Подтверждение пароля", "comment" : "Подтверждение пароля",

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import Combine
#if canImport(SocketIO) #if canImport(SocketIO)
import SocketIO import SocketIO
#endif #endif
@ -6,10 +7,28 @@ import SocketIO
final class SocketService { final class SocketService {
static let shared = SocketService() static let shared = SocketService()
enum ConnectionState: Equatable {
case disconnected
case connecting
case connected
}
private let syncQueue = DispatchQueue(label: "org.yobble.socket.service") private let syncQueue = DispatchQueue(label: "org.yobble.socket.service")
private var currentToken: String? private var currentToken: String?
private var currentAuthPayload: [String: Any] = [:] private var currentAuthPayload: [String: Any] = [:]
private let connectionStateSubject = CurrentValueSubject<ConnectionState, Never>(.disconnected)
var connectionStatePublisher: AnyPublisher<ConnectionState, Never> {
connectionStateSubject
.removeDuplicates()
.eraseToAnyPublisher()
}
var currentConnectionState: ConnectionState {
connectionStateSubject.value
}
#if canImport(SocketIO) #if canImport(SocketIO)
private var manager: SocketManager? private var manager: SocketManager?
private var socket: SocketIOClient? private var socket: SocketIOClient?
@ -17,6 +36,19 @@ final class SocketService {
private init() {} private init() {}
private func updateConnectionState(_ state: ConnectionState) {
let sendState: () -> Void = { [weak self] in
guard let self, self.connectionStateSubject.value != state else { return }
self.connectionStateSubject.send(state)
}
if Thread.isMainThread {
sendState()
} else {
DispatchQueue.main.async(execute: sendState)
}
}
func connectForCurrentUser() { func connectForCurrentUser() {
syncQueue.async { [weak self] in syncQueue.async { [weak self] in
guard let self else { return } guard let self else { return }
@ -68,8 +100,10 @@ final class SocketService {
currentToken = token currentToken = token
currentAuthPayload = ["token": token] currentAuthPayload = ["token": token]
setupSocket(with: token) setupSocket(with: token)
updateConnectionState(.connecting)
socket?.connect(withPayload: currentAuthPayload) socket?.connect(withPayload: currentAuthPayload)
#else #else
updateConnectionState(.disconnected)
if AppConfig.DEBUG { if AppConfig.DEBUG {
print("[SocketService] SocketIO framework not available; skipping connection") print("[SocketService] SocketIO framework not available; skipping connection")
} }
@ -112,14 +146,17 @@ final class SocketService {
socket.on(clientEvent: .connect) { _, _ in socket.on(clientEvent: .connect) { _, _ in
if AppConfig.DEBUG { print("[SocketService] Connected") } if AppConfig.DEBUG { print("[SocketService] Connected") }
self.updateConnectionState(.connected)
} }
socket.on(clientEvent: .disconnect) { data, _ in socket.on(clientEvent: .disconnect) { data, _ in
if AppConfig.DEBUG { print("[SocketService] Disconnected: \(data)") } if AppConfig.DEBUG { print("[SocketService] Disconnected: \(data)") }
self.updateConnectionState(.disconnected)
} }
socket.on(clientEvent: .error) { data, _ in socket.on(clientEvent: .error) { data, _ in
if AppConfig.DEBUG { print("[SocketService] Error: \(data)") } if AppConfig.DEBUG { print("[SocketService] Error: \(data)") }
self.updateConnectionState(.disconnected)
} }
self.manager = manager self.manager = manager
@ -131,6 +168,7 @@ final class SocketService {
manager?.disconnect() manager?.disconnect()
socket = nil socket = nil
manager = nil manager = nil
updateConnectionState(.disconnected)
} }
#else #else
private func disconnectInternal() { } private func disconnectInternal() { }

View File

@ -16,9 +16,11 @@ class LoginViewModel: ObservableObject {
@Published var showError: Bool = false @Published var showError: Bool = false
@Published var errorMessage: String = "" @Published var errorMessage: String = ""
@Published var isLoggedIn: Bool = false @Published var isLoggedIn: Bool = false
@Published var socketState: SocketService.ConnectionState
private let authService = AuthService() private let authService = AuthService()
private let socketService = SocketService.shared private let socketService = SocketService.shared
private var cancellables = Set<AnyCancellable>()
private enum DefaultsKeys { private enum DefaultsKeys {
static let currentUser = "currentUser" static let currentUser = "currentUser"
@ -26,12 +28,23 @@ class LoginViewModel: ObservableObject {
} }
init() { init() {
socketState = socketService.currentConnectionState
observeSocketState()
// loadStoredUser() // loadStoredUser()
// Запускаем автологин // Запускаем автологин
autoLogin() autoLogin()
} }
private func observeSocketState() {
socketService.connectionStatePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] state in
self?.socketState = state
}
.store(in: &cancellables)
}
func autoLogin() { func autoLogin() {
authService.autoLogin { [weak self] success, error in authService.autoLogin { [weak self] success, error in
DispatchQueue.main.async { DispatchQueue.main.async {