From b3b02835b6e87ca5594c5c4ef0d75158886cb31a Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Thu, 21 May 2026 00:36:08 +0300 Subject: [PATCH] Expose network state to iOS bridge --- .../Sources/TeleTuiIOSCore/Bridge.swift | 5 +++++ .../TeleTuiIOSCore/UniFfiSessionBridge.swift | 4 ++++ .../Sources/TeleTuiIOSCore/ViewModels.swift | 16 +++++++++++++++- .../Sources/TeleTuiIOSSmokeTests/main.swift | 2 ++ crates/tele-ios-ffi/src/lib.rs | 9 +++++++++ scripts/smoke-ios-ffi-swift.sh | 8 ++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/Bridge.swift b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/Bridge.swift index e01c503..b23d194 100644 --- a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/Bridge.swift +++ b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/Bridge.swift @@ -2,6 +2,7 @@ import Foundation public protocol SessionBridge: Sendable { func authState() async throws -> AuthState + func networkState() async throws -> NetworkState func pollEvents() async throws -> [SessionEvent] func sendPhoneNumber(_ phone: String) async throws func sendCode(_ code: String) async throws @@ -66,6 +67,10 @@ public actor FakeSessionBridge: SessionBridge { auth } + public func networkState() async throws -> NetworkState { + .ready + } + public func pollEvents() async throws -> [SessionEvent] { let drained = events events.removeAll() diff --git a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/UniFfiSessionBridge.swift b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/UniFfiSessionBridge.swift index 7a47406..19cd859 100644 --- a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/UniFfiSessionBridge.swift +++ b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/UniFfiSessionBridge.swift @@ -26,6 +26,10 @@ public actor UniFfiSessionBridge: SessionBridge { Self.mapAuthState(handle.authState()) } + public func networkState() async throws -> NetworkState { + Self.mapNetworkState(handle.networkState()) + } + public func pollEvents() async throws -> [SessionEvent] { handle.pollEvents().map(Self.mapEvent) } diff --git a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/ViewModels.swift b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/ViewModels.swift index 262915f..13aae01 100644 --- a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/ViewModels.swift +++ b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/ViewModels.swift @@ -24,10 +24,24 @@ public final class SessionStore: ObservableObject { } } + public func refreshNetworkState() async { + do { + networkState = try await bridge.networkState() + errorMessage = nil + } catch { + errorMessage = error.localizedDescription + } + } + public func apply(events: [SessionEvent]) { for event in events { - if case let .authChanged(state) = event { + switch event { + case let .authChanged(state): authState = state + case let .networkChanged(state): + networkState = state + default: + break } } } diff --git a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSSmokeTests/main.swift b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSSmokeTests/main.swift index 4fc3ee6..1fc7a33 100644 --- a/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSSmokeTests/main.swift +++ b/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSSmokeTests/main.swift @@ -23,6 +23,8 @@ struct TeleTuiIOSSmokeTests { await store.refreshAuthState() precondition(store.authState == .waitPhoneNumber) + await store.refreshNetworkState() + precondition(store.networkState == .ready) viewModel.phone = "+10000000000" await viewModel.submitCurrentStep() diff --git a/crates/tele-ios-ffi/src/lib.rs b/crates/tele-ios-ffi/src/lib.rs index 7e160fd..35326cd 100644 --- a/crates/tele-ios-ffi/src/lib.rs +++ b/crates/tele-ios-ffi/src/lib.rs @@ -493,6 +493,10 @@ impl SessionHandle { self.with_session(|session| session.auth_state().into()) } + pub fn network_state(&self) -> IosNetworkState { + self.with_session(|session| session.network_state().into()) + } + pub fn poll_events(&self) -> Vec { self.with_session(|session| { session.drain_client_events(); @@ -909,6 +913,10 @@ impl SessionHandle { .clone() } + pub fn network_state(&self) -> IosNetworkState { + IosNetworkState::Ready + } + pub fn poll_events(&self) -> Vec { let mut state = self.state.lock().expect("session mutex poisoned"); std::mem::take(&mut state.events) @@ -1296,6 +1304,7 @@ mod tests { let chats = session.load_chats(20).unwrap(); assert_eq!(chats.len(), 1); + assert_eq!(session.network_state(), IosNetworkState::Ready); let history = session.load_history(chats[0].id, 20).unwrap(); assert_eq!(history[0].text, "Hello from fake TDLib"); diff --git a/scripts/smoke-ios-ffi-swift.sh b/scripts/smoke-ios-ffi-swift.sh index 61d6234..52d3413 100755 --- a/scripts/smoke-ios-ffi-swift.sh +++ b/scripts/smoke-ios-ffi-swift.sh @@ -57,6 +57,14 @@ struct Smoke { require(chats.count == 1, "expected one fake chat") let chat = chats[0] + let network = session.networkState() + require({ + if case .ready = network { + return true + } + return false + }(), "expected ready network state") + let history = try session.loadHistory(chatId: chat.id, limit: 20) require(history.first?.text == "Hello from fake TDLib", "expected seeded history")